LCOV - code coverage report
Current view: top level - media/mtransport/third_party/nICEr/src/ice - ice_component.c (source / functions) Hit Total Coverage
Test: output.info Lines: 0 861 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 43 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             : Copyright (c) 2007, Adobe Systems, Incorporated
       3             : All rights reserved.
       4             : 
       5             : Redistribution and use in source and binary forms, with or without
       6             : modification, are permitted provided that the following conditions are
       7             : met:
       8             : 
       9             : * Redistributions of source code must retain the above copyright
      10             :   notice, this list of conditions and the following disclaimer.
      11             : 
      12             : * Redistributions in binary form must reproduce the above copyright
      13             :   notice, this list of conditions and the following disclaimer in the
      14             :   documentation and/or other materials provided with the distribution.
      15             : 
      16             : * Neither the name of Adobe Systems, Network Resonance nor the names of its
      17             :   contributors may be used to endorse or promote products derived from
      18             :   this software without specific prior written permission.
      19             : 
      20             : THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
      21             : "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
      22             : LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
      23             : A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
      24             : OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
      25             : SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
      26             : LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      27             : DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      28             : THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      29             : (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
      30             : OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      31             : */
      32             : 
      33             : 
      34             : 
      35             : static char *RCSSTRING __UNUSED__="$Id: ice_component.c,v 1.2 2008/04/28 17:59:01 ekr Exp $";
      36             : 
      37             : #include <string.h>
      38             : #include <assert.h>
      39             : #include <nr_api.h>
      40             : #include <registry.h>
      41             : #include <async_timer.h>
      42             : #include "ice_ctx.h"
      43             : #include "ice_codeword.h"
      44             : #include "stun.h"
      45             : #include "nr_socket_local.h"
      46             : #include "nr_socket_turn.h"
      47             : #include "nr_socket_wrapper.h"
      48             : #include "nr_socket_buffered_stun.h"
      49             : #include "nr_socket_multi_tcp.h"
      50             : #include "ice_reg.h"
      51             : #include "nr_crypto.h"
      52             : #include "r_time.h"
      53             : 
      54             : 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);
      55             : static int nr_ice_pre_answer_request_destroy(nr_ice_pre_answer_request **parp);
      56             : void nr_ice_component_consent_schedule_consent_timer(nr_ice_component *comp);
      57             : void nr_ice_component_consent_destroy(nr_ice_component *comp);
      58             : 
      59             : /* This function takes ownership of the contents of req (but not req itself) */
      60           0 : static int nr_ice_pre_answer_request_create(nr_transport_addr *dst, nr_stun_server_request *req, nr_ice_pre_answer_request **parp)
      61             :   {
      62             :     int r, _status;
      63           0 :     nr_ice_pre_answer_request *par = 0;
      64             :     nr_stun_message_attribute *attr;
      65             : 
      66           0 :     if (!(par = RCALLOC(sizeof(nr_ice_pre_answer_request))))
      67           0 :       ABORT(R_NO_MEMORY);
      68             : 
      69           0 :     par->req = *req; /* Struct assignment */
      70           0 :     memset(req, 0, sizeof(*req)); /* Zero contents to avoid confusion */
      71             : 
      72           0 :     if (r=nr_transport_addr_copy(&par->local_addr, dst))
      73           0 :       ABORT(r);
      74           0 :     if (!nr_stun_message_has_attribute(par->req.request, NR_STUN_ATTR_USERNAME, &attr))
      75           0 :       ABORT(R_INTERNAL);
      76           0 :     if (!(par->username = r_strdup(attr->u.username)))
      77           0 :       ABORT(R_NO_MEMORY);
      78             : 
      79           0 :     *parp=par;
      80           0 :     _status=0;
      81             :  abort:
      82           0 :     if (_status) {
      83             :       /* Erase the request so we don't free it */
      84           0 :       memset(&par->req, 0, sizeof(nr_stun_server_request));
      85           0 :       nr_ice_pre_answer_request_destroy(&par);
      86             :     }
      87             : 
      88           0 :     return(_status);
      89             :   }
      90             : 
      91           0 : static int nr_ice_pre_answer_request_destroy(nr_ice_pre_answer_request **parp)
      92             :   {
      93             :     nr_ice_pre_answer_request *par;
      94             : 
      95           0 :     if (!parp || !*parp)
      96           0 :       return(0);
      97             : 
      98           0 :     par = *parp;
      99           0 :     *parp = 0;
     100             : 
     101           0 :     nr_stun_message_destroy(&par->req.request);
     102           0 :     nr_stun_message_destroy(&par->req.response);
     103             : 
     104           0 :     RFREE(par->username);
     105           0 :     RFREE(par);
     106             : 
     107           0 :     return(0);
     108             :   }
     109             : 
     110           0 : int nr_ice_component_create(nr_ice_media_stream *stream, int component_id, nr_ice_component **componentp)
     111             :   {
     112             :     int _status;
     113           0 :     nr_ice_component *comp=0;
     114             : 
     115           0 :     if(!(comp=RCALLOC(sizeof(nr_ice_component))))
     116           0 :       ABORT(R_NO_MEMORY);
     117             : 
     118           0 :     comp->state=NR_ICE_COMPONENT_UNPAIRED;
     119           0 :     comp->component_id=component_id;
     120           0 :     comp->stream=stream;
     121           0 :     comp->ctx=stream->ctx;
     122             : 
     123           0 :     STAILQ_INIT(&comp->sockets);
     124           0 :     TAILQ_INIT(&comp->candidates);
     125           0 :     STAILQ_INIT(&comp->pre_answer_reqs);
     126             : 
     127           0 :     STAILQ_INSERT_TAIL(&stream->components,comp,entry);
     128             : 
     129           0 :     _status=0;
     130             :   abort:
     131           0 :     return(_status);
     132             :   }
     133             : 
     134           0 : int nr_ice_component_destroy(nr_ice_component **componentp)
     135             :   {
     136             :     nr_ice_component *component;
     137             :     nr_ice_socket *s1,*s2;
     138             :     nr_ice_candidate *c1,*c2;
     139             :     nr_ice_pre_answer_request *r1,*r2;
     140             : 
     141           0 :     if(!componentp || !*componentp)
     142           0 :       return(0);
     143             : 
     144           0 :     component=*componentp;
     145           0 :     *componentp=0;
     146             : 
     147           0 :     nr_ice_component_consent_destroy(component);
     148             : 
     149             :     /* Detach ourselves from the sockets */
     150           0 :     if (component->local_component){
     151           0 :       nr_ice_socket *isock=STAILQ_FIRST(&component->local_component->sockets);
     152           0 :       while(isock){
     153           0 :         nr_stun_server_remove_client(isock->stun_server, component);
     154           0 :         isock=STAILQ_NEXT(isock, entry);
     155             :       }
     156             :     }
     157             : 
     158             :     /* candidates MUST be destroyed before the sockets so that
     159             :        they can deregister */
     160           0 :     TAILQ_FOREACH_SAFE(c1, &component->candidates, entry_comp, c2){
     161           0 :       TAILQ_REMOVE(&component->candidates,c1,entry_comp);
     162           0 :       nr_ice_candidate_destroy(&c1);
     163             :     }
     164             : 
     165           0 :     STAILQ_FOREACH_SAFE(s1, &component->sockets, entry, s2){
     166           0 :       STAILQ_REMOVE(&component->sockets,s1,nr_ice_socket_,entry);
     167           0 :       nr_ice_socket_destroy(&s1);
     168             :     }
     169             : 
     170           0 :     STAILQ_FOREACH_SAFE(r1, &component->pre_answer_reqs, entry, r2){
     171           0 :       STAILQ_REMOVE(&component->pre_answer_reqs,r1,nr_ice_pre_answer_request_, entry);
     172           0 :       nr_ice_pre_answer_request_destroy(&r1);
     173             :     }
     174             : 
     175           0 :     RFREE(component);
     176           0 :     return(0);
     177             :   }
     178             : 
     179           0 : static int nr_ice_component_create_stun_server_ctx(nr_ice_component *component, nr_ice_socket *isock, nr_socket *sock, nr_transport_addr *addr, char *lufrag, Data *pwd)
     180             :   {
     181             :     char label[256];
     182             :     int r,_status;
     183             : 
     184             :     /* Create a STUN server context for this socket */
     185           0 :     snprintf(label, sizeof(label), "server(%s)", addr->as_string);
     186           0 :     if(r=nr_stun_server_ctx_create(label,sock,&isock->stun_server))
     187           0 :       ABORT(r);
     188           0 :     if(r=nr_ice_socket_register_stun_server(isock,isock->stun_server,&isock->stun_server_handle))
     189           0 :       ABORT(r);
     190             : 
     191             :    /* Add the default STUN credentials so that we can respond before
     192             :       we hear about the peer.*/
     193           0 :     if(r=nr_stun_server_add_default_client(isock->stun_server, lufrag, pwd, nr_ice_component_stun_server_default_cb, component))
     194           0 :       ABORT(r);
     195             : 
     196           0 :     _status = 0;
     197             :  abort:
     198           0 :     return(_status);
     199             :   }
     200             : 
     201           0 : 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)
     202             :   {
     203             :     nr_socket *sock;
     204           0 :     nr_ice_socket *isock=0;
     205           0 :     nr_ice_candidate *cand=0;
     206             :     int i;
     207             :     int j;
     208             :     int r,_status;
     209             : 
     210           0 :     if(ctx->flags & NR_ICE_CTX_FLAGS_ONLY_PROXY) {
     211             :       /* No UDP support if we must use a proxy */
     212           0 :       return 0;
     213             :     }
     214             : 
     215             :     /* Now one ice_socket for each address */
     216           0 :     for(i=0;i<addr_ct;i++){
     217             :       char suppress;
     218             : 
     219           0 :       if(r=NR_reg_get2_char(NR_ICE_REG_SUPPRESS_INTERFACE_PRFX,addrs[i].addr.ifname,&suppress)){
     220           0 :         if(r!=R_NOT_FOUND)
     221           0 :           ABORT(r);
     222             :       }
     223             :       else{
     224           0 :         if(suppress)
     225           0 :           continue;
     226             :       }
     227           0 :       r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): host address %s",ctx->label,addrs[i].addr.as_string);
     228           0 :       if((r=nr_socket_factory_create_socket(ctx->socket_factory,&addrs[i].addr,&sock))){
     229           0 :         r_log(LOG_ICE,LOG_WARNING,"ICE(%s): couldn't create socket for address %s",ctx->label,addrs[i].addr.as_string);
     230           0 :         continue;
     231             :       }
     232             : 
     233           0 :       if(r=nr_ice_socket_create(ctx,component,sock,NR_ICE_SOCKET_TYPE_DGRAM,&isock))
     234           0 :         ABORT(r);
     235             : 
     236           0 :       if (!(ctx->flags & NR_ICE_CTX_FLAGS_RELAY_ONLY)) {
     237             :         /* Create one host candidate */
     238           0 :         if(r=nr_ice_candidate_create(ctx,component,isock,sock,HOST,0,0,
     239           0 :           component->component_id,&cand))
     240           0 :           ABORT(r);
     241             : 
     242           0 :         TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
     243           0 :         component->candidate_ct++;
     244           0 :         cand=0;
     245             : 
     246             :         /* And a srvrflx candidate for each STUN server */
     247           0 :         for(j=0;j<ctx->stun_server_ct;j++){
     248             :           /* Skip non-UDP */
     249           0 :           if(ctx->stun_servers[j].transport!=IPPROTO_UDP)
     250           0 :             continue;
     251             : 
     252             :           /* Ensure id is set (nr_ice_ctx_set_stun_servers does not) */
     253           0 :           ctx->stun_servers[j].id = j;
     254           0 :           if(r=nr_ice_candidate_create(ctx,component,
     255             :             isock,sock,SERVER_REFLEXIVE,0,
     256           0 :             &ctx->stun_servers[j],component->component_id,&cand))
     257           0 :             ABORT(r);
     258           0 :           TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
     259           0 :           component->candidate_ct++;
     260           0 :           cand=0;
     261             :         }
     262             :       }
     263             :       else{
     264           0 :         r_log(LOG_ICE,LOG_WARNING,"ICE(%s): relay only option results in no host candidate for %s",ctx->label,addrs[i].addr.as_string);
     265             :       }
     266             : 
     267             : #ifdef USE_TURN
     268           0 :       if ((ctx->flags & NR_ICE_CTX_FLAGS_RELAY_ONLY) &&
     269           0 :           (ctx->turn_server_ct == 0)) {
     270           0 :         r_log(LOG_ICE,LOG_ERR,"ICE(%s): relay only option is set without any TURN server configured",ctx->label);
     271             :       }
     272             :       /* And both a srvrflx and relayed candidate for each TURN server (unless
     273             :          we're in relay-only mode, in which case just the relayed one) */
     274           0 :       for(j=0;j<ctx->turn_server_ct;j++){
     275             :         nr_socket *turn_sock;
     276           0 :         nr_ice_candidate *srvflx_cand=0;
     277             : 
     278             :         /* Skip non-UDP */
     279           0 :         if (ctx->turn_servers[j].turn_server.transport != IPPROTO_UDP)
     280           0 :           continue;
     281             : 
     282           0 :         if (!(ctx->flags & NR_ICE_CTX_FLAGS_RELAY_ONLY)) {
     283             :           /* Ensure id is set with a unique value */
     284           0 :           ctx->turn_servers[j].turn_server.id = j + ctx->stun_server_ct;
     285             :           /* srvrflx */
     286           0 :           if(r=nr_ice_candidate_create(ctx,component,
     287             :             isock,sock,SERVER_REFLEXIVE,0,
     288           0 :             &ctx->turn_servers[j].turn_server,component->component_id,&cand))
     289           0 :             ABORT(r);
     290           0 :           cand->state=NR_ICE_CAND_STATE_INITIALIZING; /* Don't start */
     291           0 :           cand->done_cb=nr_ice_gather_finished_cb;
     292           0 :           cand->cb_arg=cand;
     293             : 
     294           0 :           TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
     295           0 :           component->candidate_ct++;
     296           0 :           srvflx_cand=cand;
     297           0 :           cand=0;
     298             :         }
     299             :         /* relayed*/
     300           0 :         if(r=nr_socket_turn_create(sock, &turn_sock))
     301           0 :           ABORT(r);
     302           0 :         if(r=nr_ice_candidate_create(ctx,component,
     303             :           isock,turn_sock,RELAYED,0,
     304           0 :           &ctx->turn_servers[j].turn_server,component->component_id,&cand))
     305           0 :            ABORT(r);
     306           0 :         if (srvflx_cand) {
     307           0 :           cand->u.relayed.srvflx_candidate=srvflx_cand;
     308           0 :           srvflx_cand->u.srvrflx.relay_candidate=cand;
     309             :         }
     310           0 :         cand->u.relayed.server=&ctx->turn_servers[j];
     311           0 :         TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
     312           0 :         component->candidate_ct++;
     313             : 
     314           0 :         cand=0;
     315             :       }
     316             : #endif /* USE_TURN */
     317             : 
     318             :       /* Create a STUN server context for this socket */
     319           0 :       if ((r=nr_ice_component_create_stun_server_ctx(component,isock,sock,&addrs[i].addr,lufrag,pwd)))
     320           0 :         ABORT(r);
     321             : 
     322           0 :       STAILQ_INSERT_TAIL(&component->sockets,isock,entry);
     323             :     }
     324             : 
     325           0 :     _status = 0;
     326             :  abort:
     327           0 :     return(_status);
     328             :   }
     329             : 
     330           0 : static int nr_ice_component_get_port_from_ephemeral_range(uint16_t *port)
     331             :   {
     332             :     int _status, r;
     333           0 :     void *buf = port;
     334           0 :     if(r=nr_crypto_random_bytes(buf, 2))
     335           0 :       ABORT(r);
     336           0 :     *port|=49152; /* make it fit into IANA ephemeral port range >= 49152 */
     337           0 :     _status=0;
     338             : abort:
     339           0 :     return(_status);
     340             :   }
     341             : 
     342           0 : static int nr_ice_component_create_tcp_host_candidate(struct nr_ice_ctx_ *ctx,
     343             :   nr_ice_component *component, nr_transport_addr *interface_addr, nr_socket_tcp_type tcp_type,
     344             :   int backlog, int so_sock_ct, char *lufrag, Data *pwd, nr_ice_socket **isock)
     345             :   {
     346             :     int r,_status;
     347           0 :     nr_ice_candidate *cand=0;
     348           0 :     int tries=3;
     349           0 :     nr_ice_socket *isock_tmp=0;
     350           0 :     nr_socket *nrsock=0;
     351             :     nr_transport_addr addr;
     352             :     uint16_t local_port;
     353             : 
     354           0 :     if ((r=nr_transport_addr_copy(&addr,interface_addr)))
     355           0 :       ABORT(r);
     356           0 :     addr.protocol=IPPROTO_TCP;
     357             : 
     358             :     do{
     359           0 :       if (!tries--)
     360           0 :         ABORT(r);
     361             : 
     362           0 :       if((r=nr_ice_component_get_port_from_ephemeral_range(&local_port)))
     363           0 :         ABORT(r);
     364             : 
     365           0 :       if ((r=nr_transport_addr_set_port(&addr, local_port)))
     366           0 :         ABORT(r);
     367             : 
     368           0 :       if((r=nr_transport_addr_fmt_addr_string(&addr)))
     369           0 :         ABORT(r);
     370             : 
     371             :       /* It would be better to stop trying if there is error other than
     372             :          port already used, but it'd require significant work to support this. */
     373           0 :       r=nr_socket_multi_tcp_create(ctx,&addr,tcp_type,so_sock_ct,NR_STUN_MAX_MESSAGE_SIZE,&nrsock);
     374             : 
     375           0 :     } while(r);
     376             : 
     377           0 :     if((tcp_type == TCP_TYPE_PASSIVE) && (r=nr_socket_listen(nrsock,backlog)))
     378           0 :       ABORT(r);
     379             : 
     380           0 :     if((r=nr_ice_socket_create(ctx,component,nrsock,NR_ICE_SOCKET_TYPE_STREAM_TCP,&isock_tmp)))
     381           0 :       ABORT(r);
     382             : 
     383             :     /* nr_ice_socket took ownership of nrsock */
     384           0 :     nrsock=NULL;
     385             : 
     386             :     /* Create a STUN server context for this socket */
     387           0 :     if ((r=nr_ice_component_create_stun_server_ctx(component,isock_tmp,isock_tmp->sock,&addr,lufrag,pwd)))
     388           0 :       ABORT(r);
     389             : 
     390           0 :     if((r=nr_ice_candidate_create(ctx,component,isock_tmp,isock_tmp->sock,HOST,tcp_type,0,
     391           0 :       component->component_id,&cand)))
     392           0 :       ABORT(r);
     393             : 
     394           0 :     if (isock)
     395           0 :       *isock=isock_tmp;
     396             : 
     397           0 :     TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
     398           0 :     component->candidate_ct++;
     399             : 
     400           0 :     STAILQ_INSERT_TAIL(&component->sockets,isock_tmp,entry);
     401             : 
     402           0 :     _status=0;
     403             : abort:
     404           0 :     if (_status) {
     405           0 :       nr_ice_socket_destroy(&isock_tmp);
     406           0 :       nr_socket_destroy(&nrsock);
     407             :     }
     408           0 :     return(_status);
     409             :   }
     410             : 
     411           0 : 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)
     412             :   {
     413           0 :     nr_ice_candidate *cand=0;
     414             :     int i;
     415             :     int j;
     416             :     int r,_status;
     417           0 :     int so_sock_ct=0;
     418           0 :     int backlog=10;
     419           0 :     char ice_tcp_disabled=1;
     420             : 
     421           0 :     r_log(LOG_ICE,LOG_DEBUG,"nr_ice_component_initialize_tcp");
     422             : 
     423           0 :     if(r=NR_reg_get_int4(NR_ICE_REG_ICE_TCP_SO_SOCK_COUNT,&so_sock_ct)){
     424           0 :       if(r!=R_NOT_FOUND)
     425           0 :         ABORT(r);
     426             :     }
     427             : 
     428           0 :     if(r=NR_reg_get_int4(NR_ICE_REG_ICE_TCP_LISTEN_BACKLOG,&backlog)){
     429           0 :       if(r!=R_NOT_FOUND)
     430           0 :         ABORT(r);
     431             :     }
     432             : 
     433           0 :     if ((r=NR_reg_get_char(NR_ICE_REG_ICE_TCP_DISABLE, &ice_tcp_disabled))) {
     434           0 :       if (r != R_NOT_FOUND)
     435           0 :         ABORT(r);
     436             :     }
     437           0 :     if ((ctx->flags & NR_ICE_CTX_FLAGS_RELAY_ONLY) ||
     438           0 :         (ctx->flags & NR_ICE_CTX_FLAGS_ONLY_PROXY)) {
     439           0 :       r_log(LOG_ICE,LOG_WARNING,"ICE(%s): relay/proxy only option results in ICE TCP being disabled",ctx->label);
     440           0 :       ice_tcp_disabled = 1;
     441             :     }
     442             : 
     443           0 :     for(i=0;i<addr_ct;i++){
     444             :       char suppress;
     445           0 :       nr_ice_socket *isock_psv=0;
     446           0 :       nr_ice_socket *isock_so=0;
     447             : 
     448           0 :       if(r=NR_reg_get2_char(NR_ICE_REG_SUPPRESS_INTERFACE_PRFX,addrs[i].addr.ifname,&suppress)){
     449           0 :         if(r!=R_NOT_FOUND)
     450           0 :           ABORT(r);
     451             :       }
     452           0 :       else if(suppress) {
     453           0 :           continue;
     454             :       }
     455             : 
     456           0 :       if (!ice_tcp_disabled) {
     457             :         /* passive host candidate */
     458           0 :         if ((r=nr_ice_component_create_tcp_host_candidate(ctx, component, &addrs[i].addr,
     459             :           TCP_TYPE_PASSIVE, backlog, 0, lufrag, pwd, &isock_psv))) {
     460           0 :           r_log(LOG_ICE,LOG_WARNING,"ICE(%s): failed to create passive TCP host candidate: %d",ctx->label,r);
     461             :         }
     462             : 
     463             :         /* active host candidate */
     464           0 :         if ((r=nr_ice_component_create_tcp_host_candidate(ctx, component, &addrs[i].addr,
     465             :           TCP_TYPE_ACTIVE, 0, 0, lufrag, pwd, NULL))) {
     466           0 :           r_log(LOG_ICE,LOG_WARNING,"ICE(%s): failed to create active TCP host candidate: %d",ctx->label,r);
     467             :         }
     468             : 
     469             :         /* simultaneous-open host candidate */
     470           0 :         if (so_sock_ct) {
     471           0 :           if ((r=nr_ice_component_create_tcp_host_candidate(ctx, component, &addrs[i].addr,
     472             :             TCP_TYPE_SO, 0, so_sock_ct, lufrag, pwd, &isock_so))) {
     473           0 :             r_log(LOG_ICE,LOG_WARNING,"ICE(%s): failed to create simultanous open TCP host candidate: %d",ctx->label,r);
     474             :           }
     475             :         }
     476             : 
     477             :         /* And srvrflx candidates for each STUN server */
     478           0 :         for(j=0;j<ctx->stun_server_ct;j++){
     479           0 :           if (ctx->stun_servers[j].transport!=IPPROTO_TCP)
     480           0 :             continue;
     481             : 
     482           0 :           if (isock_psv) {
     483           0 :             if(r=nr_ice_candidate_create(ctx,component,
     484           0 :               isock_psv,isock_psv->sock,SERVER_REFLEXIVE,TCP_TYPE_PASSIVE,
     485           0 :               &ctx->stun_servers[j],component->component_id,&cand))
     486           0 :               ABORT(r);
     487           0 :             TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
     488           0 :             component->candidate_ct++;
     489           0 :             cand=0;
     490             :           }
     491             : 
     492           0 :           if (isock_so) {
     493           0 :             if(r=nr_ice_candidate_create(ctx,component,
     494           0 :               isock_so,isock_so->sock,SERVER_REFLEXIVE,TCP_TYPE_SO,
     495           0 :               &ctx->stun_servers[j],component->component_id,&cand))
     496           0 :               ABORT(r);
     497           0 :             TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
     498           0 :             component->candidate_ct++;
     499           0 :             cand=0;
     500             :           }
     501             :         }
     502             :       }
     503             : 
     504             : #ifdef USE_TURN
     505             :       /* Create a new relayed candidate for each addr/TURN server pair */
     506           0 :       for(j=0;j<ctx->turn_server_ct;j++){
     507             :         nr_transport_addr addr;
     508             :         nr_socket *local_sock;
     509             :         nr_socket *buffered_sock;
     510             :         nr_socket *turn_sock;
     511             :         nr_ice_socket *turn_isock;
     512             : 
     513             :         /* Skip non-TCP */
     514           0 :         if (ctx->turn_servers[j].turn_server.transport != IPPROTO_TCP)
     515           0 :           continue;
     516             : 
     517           0 :         if (ctx->turn_servers[j].turn_server.type == NR_ICE_STUN_SERVER_TYPE_ADDR &&
     518           0 :             nr_transport_addr_cmp(&ctx->turn_servers[j].turn_server.u.addr,
     519           0 :                                   &addrs[i].addr,
     520             :                                   NR_TRANSPORT_ADDR_CMP_MODE_VERSION)) {
     521           0 :           r_log(LOG_ICE,LOG_INFO,"ICE(%s): Skipping TURN server because of IP version mis-match (%u - %u)",ctx->label,addrs[i].addr.ip_version,ctx->turn_servers[j].turn_server.u.addr.ip_version);
     522           0 :           continue;
     523             :         }
     524             : 
     525           0 :         if (!ice_tcp_disabled) {
     526             :           /* Use TURN server to get srflx candidates */
     527           0 :           if (isock_psv) {
     528           0 :             if(r=nr_ice_candidate_create(ctx,component,
     529           0 :               isock_psv,isock_psv->sock,SERVER_REFLEXIVE,TCP_TYPE_PASSIVE,
     530           0 :               &ctx->turn_servers[j].turn_server,component->component_id,&cand))
     531           0 :               ABORT(r);
     532           0 :             TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
     533           0 :             component->candidate_ct++;
     534           0 :             cand=0;
     535             :           }
     536             : 
     537           0 :           if (isock_so) {
     538           0 :             if(r=nr_ice_candidate_create(ctx,component,
     539           0 :               isock_so,isock_so->sock,SERVER_REFLEXIVE,TCP_TYPE_SO,
     540           0 :               &ctx->turn_servers[j].turn_server,component->component_id,&cand))
     541           0 :               ABORT(r);
     542           0 :             TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
     543           0 :             component->candidate_ct++;
     544           0 :             cand=0;
     545             :           }
     546             :         }
     547             : 
     548             :         /* Create relay candidate */
     549           0 :         if ((r=nr_transport_addr_copy(&addr, &addrs[i].addr)))
     550           0 :           ABORT(r);
     551           0 :         addr.protocol = IPPROTO_TCP;
     552             : 
     553             :         /* If we're going to use TLS, make sure that's recorded */
     554           0 :         if (ctx->turn_servers[j].turn_server.tls) {
     555           0 :           strncpy(addr.tls_host,
     556           0 :                   ctx->turn_servers[j].turn_server.u.dnsname.host,
     557             :                   sizeof(addr.tls_host) - 1);
     558             :         }
     559             : 
     560           0 :         if ((r=nr_transport_addr_fmt_addr_string(&addr)))
     561           0 :           ABORT(r);
     562             :         /* Create a local socket */
     563           0 :         if((r=nr_socket_factory_create_socket(ctx->socket_factory,&addr,&local_sock))){
     564           0 :           r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): couldn't create socket for address %s",ctx->label,addr.as_string);
     565           0 :           continue;
     566             :         }
     567             : 
     568           0 :         r_log(LOG_ICE,LOG_DEBUG,"nr_ice_component_initialize_tcp creating TURN TCP wrappers");
     569             : 
     570           0 :         if (ctx->turn_tcp_socket_wrapper) {
     571             :           /* The HTTP proxy socket */
     572           0 :           if((r=nr_socket_wrapper_factory_wrap(ctx->turn_tcp_socket_wrapper, local_sock, &local_sock)))
     573           0 :             ABORT(r);
     574             :         }
     575             : 
     576             :         /* The TCP buffered socket */
     577           0 :         if((r=nr_socket_buffered_stun_create(local_sock, NR_STUN_MAX_MESSAGE_SIZE, TURN_TCP_FRAMING, &buffered_sock)))
     578           0 :           ABORT(r);
     579             : 
     580             :         /* The TURN socket */
     581           0 :         if(r=nr_socket_turn_create(buffered_sock, &turn_sock))
     582           0 :           ABORT(r);
     583             : 
     584             :         /* Create an ICE socket */
     585           0 :         if((r=nr_ice_socket_create(ctx, component, buffered_sock, NR_ICE_SOCKET_TYPE_STREAM_TURN, &turn_isock)))
     586           0 :           ABORT(r);
     587             : 
     588             :         /* Attach ourselves to it */
     589           0 :         if(r=nr_ice_candidate_create(ctx,component,
     590             :           turn_isock,turn_sock,RELAYED,TCP_TYPE_NONE,
     591           0 :           &ctx->turn_servers[j].turn_server,component->component_id,&cand))
     592           0 :           ABORT(r);
     593           0 :         cand->u.relayed.srvflx_candidate=NULL;
     594           0 :         cand->u.relayed.server=&ctx->turn_servers[j];
     595           0 :         TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
     596           0 :         component->candidate_ct++;
     597           0 :         cand=0;
     598             : 
     599             :         /* Create a STUN server context for this socket */
     600           0 :         if ((r=nr_ice_component_create_stun_server_ctx(component,turn_isock,local_sock,&addr,lufrag,pwd)))
     601           0 :           ABORT(r);
     602             : 
     603           0 :         STAILQ_INSERT_TAIL(&component->sockets,turn_isock,entry);
     604             :       }
     605             : #endif /* USE_TURN */
     606             :     }
     607             : 
     608           0 :     _status = 0;
     609             :  abort:
     610           0 :     return(_status);
     611             :   }
     612             : 
     613             : 
     614             : /* Make all the candidates we can make at the beginning */
     615           0 : int nr_ice_component_initialize(struct nr_ice_ctx_ *ctx,nr_ice_component *component)
     616             :   {
     617             :     int r,_status;
     618           0 :     nr_local_addr *addrs=ctx->local_addrs;
     619           0 :     int addr_ct=ctx->local_addr_ct;
     620             :     char *lufrag;
     621             :     char *lpwd;
     622             :     Data pwd;
     623             :     nr_ice_candidate *cand;
     624             : 
     625           0 :     if (component->candidate_ct) {
     626           0 :       r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): component with id %d already has candidates, probably restarting gathering because of a new stream",ctx->label,component->component_id);
     627           0 :       return(0);
     628             :     }
     629             : 
     630           0 :     r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): initializing component with id %d",ctx->label,component->component_id);
     631             : 
     632           0 :     if(addr_ct==0){
     633           0 :       r_log(LOG_ICE,LOG_ERR,"ICE(%s): no local addresses available",ctx->label);
     634           0 :       ABORT(R_NOT_FOUND);
     635             :     }
     636             : 
     637             :     /* Note: we need to recompute these because
     638             :        we have not yet computed the values in the peer media stream.*/
     639           0 :     lufrag=component->stream->ufrag ? component->stream->ufrag : ctx->ufrag;
     640           0 :     assert(lufrag);
     641           0 :     if (!lufrag)
     642           0 :       ABORT(R_INTERNAL);
     643           0 :     lpwd=component->stream->pwd ? component->stream->pwd :ctx->pwd;
     644           0 :     assert(lpwd);
     645           0 :     if (!lpwd)
     646           0 :       ABORT(R_INTERNAL);
     647           0 :     INIT_DATA(pwd, (UCHAR *)lpwd, strlen(lpwd));
     648             : 
     649             :     /* Initialize the UDP candidates */
     650           0 :     if (r=nr_ice_component_initialize_udp(ctx, component, addrs, addr_ct, lufrag, &pwd))
     651           0 :       r_log(LOG_ICE,LOG_INFO,"ICE(%s): failed to create UDP candidates with error %d",ctx->label,r);
     652             :     /* And the TCP candidates */
     653           0 :     if (r=nr_ice_component_initialize_tcp(ctx, component, addrs, addr_ct, lufrag, &pwd))
     654           0 :       r_log(LOG_ICE,LOG_INFO,"ICE(%s): failed to create TCP candidates with error %d",ctx->label,r);
     655             : 
     656             :     /* count the candidates that will be initialized */
     657           0 :     cand=TAILQ_FIRST(&component->candidates);
     658           0 :     if(!cand){
     659           0 :       r_log(LOG_ICE,LOG_ERR,"ICE(%s): couldn't create any valid candidates",ctx->label);
     660           0 :       ABORT(R_NOT_FOUND);
     661             :     }
     662             : 
     663           0 :     while(cand){
     664           0 :       ctx->uninitialized_candidates++;
     665           0 :       cand=TAILQ_NEXT(cand,entry_comp);
     666             :     }
     667             : 
     668             :     /* Now initialize all the candidates */
     669           0 :     cand=TAILQ_FIRST(&component->candidates);
     670           0 :     while(cand){
     671           0 :       if(cand->state!=NR_ICE_CAND_STATE_INITIALIZING){
     672           0 :         nr_ice_candidate_initialize(cand,nr_ice_gather_finished_cb,cand);
     673             :       }
     674           0 :       cand=TAILQ_NEXT(cand,entry_comp);
     675             :     }
     676           0 :     _status=0;
     677             :  abort:
     678           0 :     return(_status);
     679             :   }
     680             : 
     681           0 : static int nr_ice_any_peer_paired(nr_ice_candidate* cand) {
     682           0 :   nr_ice_peer_ctx* pctx=STAILQ_FIRST(&cand->ctx->peers);
     683           0 :   while(pctx && pctx->state == NR_ICE_PEER_STATE_UNPAIRED){
     684             :     /* Is it worth actually looking through the check lists? Probably not. */
     685           0 :     pctx=STAILQ_NEXT(pctx,entry);
     686             :   }
     687           0 :   return pctx != NULL;
     688             : }
     689             : 
     690             : /*
     691             :   Compare this newly initialized candidate against the other initialized
     692             :   candidates and discard the lower-priority one if they are redundant.
     693             : 
     694             :    This algorithm combined with the other algorithms, favors
     695             :    host > srflx > relay
     696             :  */
     697           0 : int nr_ice_component_maybe_prune_candidate(nr_ice_ctx *ctx, nr_ice_component *comp, nr_ice_candidate *c1, int *was_pruned)
     698             :   {
     699           0 :     nr_ice_candidate *c2, *tmp = NULL;
     700             : 
     701           0 :     *was_pruned = 0;
     702           0 :     c2 = TAILQ_FIRST(&comp->candidates);
     703           0 :     while(c2){
     704           0 :       if((c1 != c2) &&
     705           0 :          (c2->state == NR_ICE_CAND_STATE_INITIALIZED) &&
     706           0 :          !nr_transport_addr_cmp(&c1->base,&c2->base,NR_TRANSPORT_ADDR_CMP_MODE_ALL) &&
     707           0 :          !nr_transport_addr_cmp(&c1->addr,&c2->addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL)){
     708             : 
     709           0 :         if((c1->type == c2->type) ||
     710           0 :            (!(ctx->flags & NR_ICE_CTX_FLAGS_HIDE_HOST_CANDIDATES) &&
     711           0 :             ((c1->type==HOST && c2->type == SERVER_REFLEXIVE) ||
     712           0 :              (c2->type==HOST && c1->type == SERVER_REFLEXIVE)))){
     713             : 
     714             :           /*
     715             :              These are redundant. Remove the lower pri one, or if pairing has
     716             :              already occurred, remove the newest one.
     717             : 
     718             :              Since this algorithmis run whenever a new candidate
     719             :              is initialized, there should at most one duplicate.
     720             :            */
     721           0 :           if ((c1->priority <= c2->priority) || nr_ice_any_peer_paired(c2)) {
     722           0 :             tmp = c1;
     723           0 :             *was_pruned = 1;
     724             :           }
     725             :           else {
     726           0 :             tmp = c2;
     727             :           }
     728           0 :           break;
     729             :         }
     730             :       }
     731             : 
     732           0 :       c2=TAILQ_NEXT(c2,entry_comp);
     733             :     }
     734             : 
     735           0 :     if (tmp) {
     736           0 :       r_log(LOG_ICE,LOG_DEBUG,"ICE(%s)/CAND(%s): Removing redundant candidate",
     737           0 :             ctx->label,tmp->label);
     738             : 
     739           0 :       TAILQ_REMOVE(&comp->candidates,tmp,entry_comp);
     740           0 :       comp->candidate_ct--;
     741           0 :       TAILQ_REMOVE(&tmp->isock->candidates,tmp,entry_sock);
     742             : 
     743           0 :       nr_ice_candidate_destroy(&tmp);
     744             :     }
     745             : 
     746           0 :     return 0;
     747             :   }
     748             : 
     749           0 : static int nr_ice_component_pair_matches_check(nr_ice_component *comp, nr_ice_cand_pair *pair, nr_transport_addr *local_addr, nr_stun_server_request *req)
     750             :   {
     751           0 :     if(pair->remote->component->component_id!=comp->component_id)
     752           0 :       return(0);
     753             : 
     754           0 :     if(nr_transport_addr_cmp(&pair->local->base,local_addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL))
     755           0 :       return(0);
     756             : 
     757           0 :     if(nr_transport_addr_cmp(&pair->remote->addr,&req->src_addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL))
     758           0 :       return(0);
     759             : 
     760           0 :     return(1);
     761             :   }
     762             : 
     763           0 : static int nr_ice_component_handle_triggered_check(nr_ice_component *comp, nr_ice_cand_pair *pair, nr_stun_server_request *req, int *error)
     764             :   {
     765           0 :     nr_stun_message *sreq=req->request;
     766           0 :     int r=0,_status;
     767             : 
     768           0 :     if(nr_stun_message_has_attribute(sreq,NR_STUN_ATTR_USE_CANDIDATE,0)){
     769           0 :       if(comp->stream->pctx->controlling){
     770           0 :         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);
     771             :       }
     772             :       else{
     773             :         /* If this is the first time we've noticed this is nominated...*/
     774           0 :         pair->peer_nominated=1;
     775             : 
     776           0 :         if(pair->state==NR_ICE_PAIR_STATE_SUCCEEDED && !pair->nominated){
     777           0 :           pair->nominated=1;
     778             : 
     779           0 :           if(r=nr_ice_component_nominated_pair(pair->remote->component, pair)) {
     780           0 :             *error=(r==R_NO_MEMORY)?500:400;
     781           0 :             ABORT(r);
     782             :           }
     783             :         }
     784             :       }
     785             :     }
     786             : 
     787             :     /* Note: the RFC says to trigger first and then nominate. But in that case
     788             :      * the canceled trigger pair would get nominated and the cloned trigger pair
     789             :      * would not get the nomination status cloned with it.*/
     790           0 :     if(r=nr_ice_candidate_pair_do_triggered_check(comp->stream->pctx,pair)) {
     791           0 :       *error=(r==R_NO_MEMORY)?500:400;
     792           0 :       ABORT(r);
     793             :     }
     794             : 
     795           0 :     _status=0;
     796             :   abort:
     797           0 :     return(r);
     798             :   }
     799             : 
     800             : /* Section 7.2.1 */
     801           0 : static int nr_ice_component_process_incoming_check(nr_ice_component *comp, nr_transport_addr *local_addr, nr_stun_server_request *req, int *error)
     802             :   {
     803             :     nr_ice_cand_pair *pair;
     804           0 :     nr_ice_candidate *pcand=0;
     805           0 :     nr_stun_message *sreq=req->request;
     806             :     nr_stun_message_attribute *attr;
     807           0 :     int r=0,_status;
     808           0 :     int found_valid=0;
     809             : 
     810           0 :     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);
     811             : 
     812           0 :     if (comp->state == NR_ICE_COMPONENT_DISABLED)
     813           0 :       ABORT(R_REJECTED);
     814             : 
     815             :     /* Check for role conficts (7.2.1.1) */
     816           0 :     if(comp->stream->pctx->controlling){
     817           0 :       if(nr_stun_message_has_attribute(sreq,NR_STUN_ATTR_ICE_CONTROLLING,&attr)){
     818             :         /* OK, there is a conflict. Who's right? */
     819           0 :         r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s): role conflict, both controlling",comp->stream->pctx->label);
     820             : 
     821           0 :         if(attr->u.ice_controlling > comp->stream->pctx->tiebreaker){
     822             :           /* Update the peer ctx. This will propagate to all candidate pairs
     823             :              in the context. */
     824           0 :           nr_ice_peer_ctx_switch_controlling_role(comp->stream->pctx);
     825             :         }
     826             :         else {
     827             :           /* We are: throw an error */
     828           0 :           r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s): returning 487 role conflict",comp->stream->pctx->label);
     829             : 
     830           0 :           *error=487;
     831           0 :           ABORT(R_REJECTED);
     832             :         }
     833             :       }
     834             :     }
     835             :     else{
     836           0 :       if(nr_stun_message_has_attribute(sreq,NR_STUN_ATTR_ICE_CONTROLLED,&attr)){
     837             :         /* OK, there is a conflict. Who's right? */
     838           0 :         r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s): role conflict, both controlled",comp->stream->pctx->label);
     839             : 
     840           0 :         if(attr->u.ice_controlled < comp->stream->pctx->tiebreaker){
     841             :           /* Update the peer ctx. This will propagate to all candidate pairs
     842             :              in the context. */
     843           0 :           nr_ice_peer_ctx_switch_controlling_role(comp->stream->pctx);
     844             :         }
     845             :         else {
     846             :           /* We are: throw an error */
     847           0 :           r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s): returning 487 role conflict",comp->stream->pctx->label);
     848             : 
     849           0 :           *error=487;
     850           0 :           ABORT(R_REJECTED);
     851             :         }
     852             :       }
     853             :     }
     854             : 
     855           0 :     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);
     856             : 
     857           0 :     pair=TAILQ_FIRST(&comp->stream->check_list);
     858           0 :     while(pair){
     859             :       /* Since triggered checks create duplicate pairs (in this implementation)
     860             :        * we are willing to handle multiple matches here. */
     861           0 :       if(nr_ice_component_pair_matches_check(comp, pair, local_addr, req)){
     862           0 :         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);
     863           0 :         if(r=nr_ice_component_handle_triggered_check(comp, pair, req, error))
     864           0 :           ABORT(r);
     865           0 :         ++found_valid;
     866             :       }
     867           0 :       pair=TAILQ_NEXT(pair,check_queue_entry);
     868             :     }
     869             : 
     870           0 :     if(!found_valid){
     871             :       /* There were no matching pairs, so we need to create a new peer
     872             :        * reflexive candidate pair. */
     873             : 
     874           0 :       if(!nr_stun_message_has_attribute(sreq,NR_STUN_ATTR_PRIORITY,&attr)){
     875           0 :         r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s): Rejecting stun request without priority",comp->stream->pctx->label);
     876           0 :         *error=400;
     877           0 :         ABORT(R_BAD_DATA);
     878             :       }
     879             : 
     880             :       /* Find our local component candidate */
     881             :       nr_ice_candidate *cand;
     882             : 
     883           0 :       r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s): no matching pair",comp->stream->pctx->label);
     884           0 :       cand=TAILQ_FIRST(&comp->local_component->candidates);
     885           0 :       while(cand){
     886           0 :         if(!nr_transport_addr_cmp(&cand->addr,local_addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL))
     887           0 :           break;
     888             : 
     889           0 :         cand=TAILQ_NEXT(cand,entry_comp);
     890             :       }
     891             : 
     892             :       /* Well, this really shouldn't happen, but it's an error from the
     893             :          other side, so we just throw an error and keep going */
     894           0 :       if(!cand){
     895           0 :         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);
     896             : 
     897           0 :         *error=400;
     898           0 :         ABORT(R_NOT_FOUND);
     899             :       }
     900             : 
     901             :       /* Now make a peer reflexive (remote) candidate */
     902           0 :       if(r=nr_ice_peer_peer_rflx_candidate_create(comp->stream->pctx->ctx,"prflx",comp,&req->src_addr,&pcand)) {
     903           0 :         *error=(r==R_NO_MEMORY)?500:400;
     904           0 :         ABORT(r);
     905             :       }
     906           0 :       pcand->priority=attr->u.priority;
     907           0 :       pcand->state=NR_ICE_CAND_PEER_CANDIDATE_PAIRED;
     908             : 
     909             :       /* Finally, create the candidate pair, insert into the check list, and
     910             :        * apply the incoming check to it. */
     911           0 :       if(r=nr_ice_candidate_pair_create(comp->stream->pctx,cand,pcand,
     912             :            &pair)) {
     913           0 :         *error=(r==R_NO_MEMORY)?500:400;
     914           0 :         ABORT(r);
     915             :       }
     916             : 
     917           0 :       nr_ice_candidate_pair_set_state(pair->pctx,pair,NR_ICE_PAIR_STATE_FROZEN);
     918           0 :       if(r=nr_ice_component_insert_pair(comp,pair)) {
     919           0 :         *error=(r==R_NO_MEMORY)?500:400;
     920           0 :         nr_ice_candidate_pair_destroy(&pair);
     921           0 :         ABORT(r);
     922             :       }
     923             : 
     924             :       /* Do this last, since any call to ABORT will destroy pcand */
     925           0 :       TAILQ_INSERT_TAIL(&comp->candidates,pcand,entry_comp);
     926           0 :       pcand=0;
     927             : 
     928             :       /* Finally start the trigger check if needed */
     929           0 :       if(r=nr_ice_component_handle_triggered_check(comp, pair, req, error))
     930           0 :         ABORT(r);
     931             :     }
     932             : 
     933           0 :     _status=0;
     934             :   abort:
     935           0 :     if(_status){
     936           0 :       nr_ice_candidate_destroy(&pcand);
     937           0 :       assert(*error != 0);
     938           0 :       if(r!=R_NO_MEMORY) assert(*error != 500);
     939             :     }
     940           0 :     return(_status);
     941             :   }
     942             : 
     943           0 : 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)
     944             :   {
     945           0 :     nr_ice_component *comp=cb_arg;
     946             :     nr_transport_addr local_addr;
     947             :     int r,_status;
     948             : 
     949           0 :     if(comp->state==NR_ICE_COMPONENT_FAILED) {
     950           0 :       *error=400;
     951           0 :       ABORT(R_REJECTED);
     952             :     }
     953             : 
     954             :     /* Find the candidate pair that this maps to */
     955           0 :     if(r=nr_socket_getaddr(sock,&local_addr)) {
     956           0 :       *error=500;
     957           0 :       ABORT(r);
     958             :     }
     959             : 
     960           0 :     if (r=nr_ice_component_process_incoming_check(comp, &local_addr, req, error))
     961           0 :       ABORT(r);
     962             : 
     963           0 :     _status=0;
     964             :  abort:
     965           0 :     return(_status);
     966             :   }
     967             : 
     968           0 : int nr_ice_component_service_pre_answer_requests(nr_ice_peer_ctx *pctx, nr_ice_component *pcomp, char *username, int *serviced)
     969             :   {
     970             :     nr_ice_pre_answer_request *r1,*r2;
     971           0 :     nr_ice_component *comp = pcomp->local_component;
     972             :     int r,_status;
     973             : 
     974           0 :     if (serviced)
     975           0 :       *serviced = 0;
     976             : 
     977           0 :     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);
     978             : 
     979           0 :     STAILQ_FOREACH_SAFE(r1, &comp->pre_answer_reqs, entry, r2) {
     980           0 :       if (!strcmp(r1->username, username)) {
     981           0 :         int error = 0;
     982             : 
     983           0 :         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);
     984           0 :         r = nr_ice_component_process_incoming_check(pcomp, &r1->local_addr, &r1->req, &error);
     985           0 :         if (r) {
     986           0 :           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);
     987             :         }
     988           0 :         (*serviced)++;
     989           0 :         STAILQ_REMOVE(&comp->pre_answer_reqs,r1,nr_ice_pre_answer_request_, entry);
     990           0 :         nr_ice_pre_answer_request_destroy(&r1);
     991             :       }
     992             :     }
     993             : 
     994           0 :     _status=0;
     995           0 :      return(_status);
     996             :   }
     997             : 
     998           0 : int nr_ice_component_can_candidate_tcptype_pair(nr_socket_tcp_type left, nr_socket_tcp_type right)
     999             :   {
    1000           0 :     if (left && !right)
    1001           0 :       return(0);
    1002           0 :     if (!left && right)
    1003           0 :       return(0);
    1004           0 :     if (left == TCP_TYPE_ACTIVE && right != TCP_TYPE_PASSIVE)
    1005           0 :       return(0);
    1006           0 :     if (left == TCP_TYPE_SO && right != TCP_TYPE_SO)
    1007           0 :       return(0);
    1008           0 :     if (left == TCP_TYPE_PASSIVE)
    1009           0 :       return(0);
    1010             : 
    1011           0 :     return(1);
    1012             :   }
    1013             : 
    1014             : /* filter out pairings which won't work. */
    1015           0 : int nr_ice_component_can_candidate_addr_pair(nr_transport_addr *local, nr_transport_addr *remote)
    1016             :   {
    1017           0 :     if(local->ip_version != remote->ip_version)
    1018           0 :       return(0);
    1019           0 :     if(nr_transport_addr_is_link_local(local) !=
    1020           0 :        nr_transport_addr_is_link_local(remote))
    1021           0 :       return(0);
    1022             :     /* This prevents our ice_unittest (or broken clients) from pairing a
    1023             :      * loopback with a host candidate. */
    1024           0 :     if(nr_transport_addr_is_loopback(local) !=
    1025           0 :        nr_transport_addr_is_loopback(remote))
    1026           0 :       return(0);
    1027             : 
    1028           0 :     return(1);
    1029             :   }
    1030             : 
    1031           0 : int nr_ice_component_pair_candidate(nr_ice_peer_ctx *pctx, nr_ice_component *pcomp, nr_ice_candidate *lcand, int pair_all_remote)
    1032             :   {
    1033             :     int r, _status;
    1034             :     nr_ice_candidate *pcand;
    1035           0 :     nr_ice_cand_pair *pair=0;
    1036             :     char codeword[5];
    1037             : 
    1038           0 :     nr_ice_compute_codeword(lcand->label,strlen(lcand->label),codeword);
    1039           0 :     r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/CAND(%s): Pairing local candidate %s",pctx->label,codeword,lcand->label);
    1040             : 
    1041           0 :     switch(lcand->type){
    1042             :       case HOST:
    1043           0 :         break;
    1044             :       case SERVER_REFLEXIVE:
    1045             :       case PEER_REFLEXIVE:
    1046             :         /* Don't actually pair these candidates */
    1047           0 :         goto done;
    1048             :         break;
    1049             :       case RELAYED:
    1050           0 :         break;
    1051             :       default:
    1052           0 :         assert(0);
    1053             :         ABORT(R_INTERNAL);
    1054             :         break;
    1055             :     }
    1056             : 
    1057           0 :     TAILQ_FOREACH(pcand, &pcomp->candidates, entry_comp){
    1058           0 :       if(!nr_ice_component_can_candidate_addr_pair(&lcand->addr, &pcand->addr))
    1059           0 :         continue;
    1060           0 :       if(!nr_ice_component_can_candidate_tcptype_pair(lcand->tcp_type, pcand->tcp_type))
    1061           0 :         continue;
    1062             : 
    1063             :       /*
    1064             :         Two modes, depending on |pair_all_remote|
    1065             : 
    1066             :         1. Pair remote candidates which have not been paired
    1067             :            (used in initial pairing or in processing the other side's
    1068             :            trickle candidates).
    1069             :         2. Pair any remote candidate (used when processing our own
    1070             :            trickle candidates).
    1071             :       */
    1072           0 :       if (pair_all_remote || (pcand->state == NR_ICE_CAND_PEER_CANDIDATE_UNPAIRED)) {
    1073           0 :         if (pair_all_remote) {
    1074             :           /* When a remote candidate arrives after the start of checking, but
    1075             :            * before the gathering of local candidates, it can be in UNPAIRED */
    1076           0 :           pcand->state = NR_ICE_CAND_PEER_CANDIDATE_PAIRED;
    1077             :         }
    1078             : 
    1079           0 :         nr_ice_compute_codeword(pcand->label,strlen(pcand->label),codeword);
    1080           0 :         r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/CAND(%s): Pairing with peer candidate %s", pctx->label, codeword, pcand->label);
    1081             : 
    1082           0 :         if(r=nr_ice_candidate_pair_create(pctx,lcand,pcand,&pair))
    1083           0 :           ABORT(r);
    1084             : 
    1085           0 :         if(r=nr_ice_component_insert_pair(pcomp, pair))
    1086           0 :           ABORT(r);
    1087             :       }
    1088             :     }
    1089             : 
    1090             :    done:
    1091           0 :     _status = 0;
    1092             :    abort:
    1093           0 :     return(_status);
    1094             :   }
    1095             : 
    1096           0 : int nr_ice_component_pair_candidates(nr_ice_peer_ctx *pctx, nr_ice_component *lcomp,nr_ice_component *pcomp)
    1097             :   {
    1098             :     nr_ice_candidate *lcand, *pcand;
    1099             :     nr_ice_socket *isock;
    1100             :     int r,_status;
    1101             : 
    1102           0 :     r_log(LOG_ICE,LOG_DEBUG,"Pairing candidates======");
    1103             : 
    1104             :     /* Create the candidate pairs */
    1105           0 :     lcand=TAILQ_FIRST(&lcomp->candidates);
    1106             : 
    1107           0 :     if (!lcand) {
    1108             :       /* No local candidates, initialized or not! */
    1109           0 :       ABORT(R_FAILED);
    1110             :     }
    1111             : 
    1112           0 :     while(lcand){
    1113           0 :       if (lcand->state == NR_ICE_CAND_STATE_INITIALIZED) {
    1114           0 :         if ((r = nr_ice_component_pair_candidate(pctx, pcomp, lcand, 0)))
    1115           0 :           ABORT(r);
    1116             :       }
    1117             : 
    1118           0 :       lcand=TAILQ_NEXT(lcand,entry_comp);
    1119             :     }
    1120             : 
    1121             :     /* Mark all peer candidates as paired */
    1122           0 :     pcand=TAILQ_FIRST(&pcomp->candidates);
    1123           0 :     while(pcand){
    1124           0 :       pcand->state = NR_ICE_CAND_PEER_CANDIDATE_PAIRED;
    1125             : 
    1126           0 :       pcand=TAILQ_NEXT(pcand,entry_comp);
    1127             : 
    1128             :     }
    1129             : 
    1130             :     /* Now register the STUN server callback for this component.
    1131             :        Note that this is a per-component CB so we only need to
    1132             :        do this once.
    1133             :     */
    1134           0 :     if (pcomp->state != NR_ICE_COMPONENT_RUNNING) {
    1135           0 :       isock=STAILQ_FIRST(&lcomp->sockets);
    1136           0 :       while(isock){
    1137           0 :         if(r=nr_stun_server_add_client(isock->stun_server,pctx->label,
    1138           0 :           pcomp->stream->r2l_user,&pcomp->stream->r2l_pass,nr_ice_component_stun_server_cb,pcomp)) {
    1139           0 :             ABORT(r);
    1140             :         }
    1141           0 :         isock=STAILQ_NEXT(isock,entry);
    1142             :       }
    1143             :     }
    1144             : 
    1145           0 :     pcomp->state = NR_ICE_COMPONENT_RUNNING;
    1146             : 
    1147           0 :     _status=0;
    1148             :   abort:
    1149           0 :     return(_status);
    1150             :   }
    1151             : 
    1152           0 : int nr_ice_pre_answer_enqueue(nr_ice_component *comp, nr_socket *sock, nr_stun_server_request *req, int *dont_free)
    1153             :   {
    1154           0 :     int r = 0;
    1155             :     int _status;
    1156             :     nr_ice_pre_answer_request *r1, *r2;
    1157             :     nr_transport_addr dst_addr;
    1158           0 :     nr_ice_pre_answer_request *par = 0;
    1159             : 
    1160           0 :     if (r=nr_socket_getaddr(sock, &dst_addr))
    1161           0 :       ABORT(r);
    1162             : 
    1163           0 :     STAILQ_FOREACH_SAFE(r1, &comp->pre_answer_reqs, entry, r2) {
    1164           0 :       if (!nr_transport_addr_cmp(&r1->local_addr, &dst_addr,
    1165           0 :                                  NR_TRANSPORT_ADDR_CMP_MODE_ALL) &&
    1166           0 :           !nr_transport_addr_cmp(&r1->req.src_addr, &req->src_addr,
    1167             :                                  NR_TRANSPORT_ADDR_CMP_MODE_ALL)) {
    1168           0 :         return(0);
    1169             :       }
    1170             :     }
    1171             : 
    1172           0 :     if (r=nr_ice_pre_answer_request_create(&dst_addr, req, &par))
    1173           0 :       ABORT(r);
    1174             : 
    1175           0 :     r_log(LOG_ICE,LOG_DEBUG, "ICE(%s)/STREAM(%s)/COMP(%d): Enqueuing STUN request pre-answer from %s",
    1176           0 :           comp->ctx->label, comp->stream->label, comp->component_id,
    1177           0 :           req->src_addr.as_string);
    1178             : 
    1179           0 :     *dont_free = 1;
    1180           0 :     STAILQ_INSERT_TAIL(&comp->pre_answer_reqs, par, entry);
    1181             : 
    1182           0 :     _status=0;
    1183             : abort:
    1184           0 :     return(_status);
    1185             :   }
    1186             : 
    1187             : /* Fires when we have an incoming candidate that doesn't correspond to an existing
    1188             :    remote peer. This is either pre-answer or just spurious. Store it in the
    1189             :    component for use when we see the actual answer, at which point we need
    1190             :    to do the procedures from S 7.2.1 in nr_ice_component_stun_server_cb.
    1191             :  */
    1192           0 : 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)
    1193             :   {
    1194             :     int r, _status;
    1195           0 :     nr_ice_component *comp = (nr_ice_component *)cb_arg;
    1196             : 
    1197           0 :     r_log(LOG_ICE,LOG_DEBUG,"ICE(%s)/STREAM(%s)/COMP(%d): Received STUN request pre-answer from %s",
    1198           0 :           comp->ctx->label, comp->stream->label, comp->component_id,
    1199           0 :           req->src_addr.as_string);
    1200             : 
    1201           0 :     if (r=nr_ice_pre_answer_enqueue(comp, sock, req, dont_free)) {
    1202           0 :       r_log(LOG_ICE,LOG_ERR,"ICE(%s)/STREAM(%s)/COMP(%d): Failed (%d) to enque pre-answer request from %s",
    1203           0 :           comp->ctx->label, comp->stream->label, comp->component_id, r,
    1204           0 :           req->src_addr.as_string);
    1205           0 :       ABORT(r);
    1206             :     }
    1207             : 
    1208           0 :     _status=0;
    1209             :  abort:
    1210           0 :     return(_status);
    1211             :   }
    1212             : 
    1213             : #define NR_ICE_CONSENT_TIMER_DEFAULT 5000
    1214             : #define NR_ICE_CONSENT_TIMEOUT_DEFAULT 30000
    1215             : 
    1216           0 : static void nr_ice_component_consent_failed(nr_ice_component *comp)
    1217             :   {
    1218           0 :     if (!comp->can_send) {
    1219           0 :       return;
    1220             :     }
    1221             : 
    1222           0 :     r_log(LOG_ICE,LOG_INFO,"ICE(%s)/STREAM(%s)/COMP(%d): Consent refresh failed",
    1223           0 :           comp->ctx->label, comp->stream->label, comp->component_id);
    1224           0 :     comp->can_send = 0;
    1225             : 
    1226           0 :     if (comp->consent_timeout) {
    1227           0 :       NR_async_timer_cancel(comp->consent_timeout);
    1228           0 :       comp->consent_timeout = 0;
    1229             :     }
    1230           0 :     if (comp->consent_timer) {
    1231           0 :       NR_async_timer_cancel(comp->consent_timer);
    1232           0 :       comp->consent_timer = 0;
    1233             :     }
    1234             :     /* We are turning the consent failure into a ICE component failure to
    1235             :      * alert the browser via ICE connection state change about this event. */
    1236           0 :     if (nr_ice_media_stream_component_failed(comp->stream, comp))
    1237           0 :       r_log(LOG_ICE,LOG_ERR,"ICE(%s)/STREAM(%s)/COMP(%d): failed to mark component as failed",
    1238           0 :         comp->ctx->label, comp->stream->label, comp->component_id);
    1239             :   }
    1240             : 
    1241           0 : static void nr_ice_component_consent_timeout_cb(NR_SOCKET s, int how, void *cb_arg)
    1242             :   {
    1243           0 :     nr_ice_component *comp=cb_arg;
    1244             : 
    1245           0 :     comp->consent_timeout = 0;
    1246             : 
    1247           0 :     r_log(LOG_ICE,LOG_WARNING,"ICE(%s)/STREAM(%s)/COMP(%d): Consent refresh final time out",
    1248           0 :           comp->ctx->label, comp->stream->label, comp->component_id);
    1249           0 :     nr_ice_component_consent_failed(comp);
    1250           0 :   }
    1251             : 
    1252             : 
    1253           0 : void nr_ice_component_disconnected(nr_ice_component *comp)
    1254             :   {
    1255           0 :     if (!comp->can_send) {
    1256           0 :       return;
    1257             :     }
    1258             : 
    1259           0 :     if (comp->disconnected) {
    1260           0 :       return;
    1261             :     }
    1262             : 
    1263           0 :     r_log(LOG_ICE,LOG_WARNING,"ICE(%s)/STREAM(%s)/COMP(%d): component disconnected",
    1264           0 :           comp->ctx->label, comp->stream->label, comp->component_id);
    1265           0 :     comp->disconnected = 1;
    1266             : 
    1267             :     /* a single disconnected component disconnects the stream */
    1268           0 :     nr_ice_media_stream_set_disconnected(comp->stream, NR_ICE_MEDIA_STREAM_DISCONNECTED);
    1269             :   }
    1270             : 
    1271           0 : static void nr_ice_component_consent_refreshed(nr_ice_component *comp)
    1272             :   {
    1273             :     uint16_t tval;
    1274             : 
    1275           0 :     if (!comp->can_send) {
    1276           0 :       return;
    1277             :     }
    1278             : 
    1279           0 :     gettimeofday(&comp->consent_last_seen, 0);
    1280           0 :     r_log(LOG_ICE,LOG_DEBUG,"ICE(%s)/STREAM(%s)/COMP(%d): consent_last_seen is now %lu",
    1281           0 :         comp->ctx->label, comp->stream->label, comp->component_id,
    1282             :         comp->consent_last_seen.tv_sec);
    1283             : 
    1284           0 :     comp->disconnected = 0;
    1285             : 
    1286           0 :     nr_ice_media_stream_check_if_connected(comp->stream);
    1287             : 
    1288           0 :     if (comp->consent_timeout)
    1289           0 :       NR_async_timer_cancel(comp->consent_timeout);
    1290             : 
    1291           0 :     tval = NR_ICE_CONSENT_TIMEOUT_DEFAULT;
    1292           0 :     if (comp->ctx->test_timer_divider)
    1293           0 :       tval = tval / comp->ctx->test_timer_divider;
    1294             : 
    1295           0 :     NR_ASYNC_TIMER_SET(tval, nr_ice_component_consent_timeout_cb, comp,
    1296             :                        &comp->consent_timeout);
    1297             :   }
    1298             : 
    1299           0 : static void nr_ice_component_refresh_consent_cb(NR_SOCKET s, int how, void *cb_arg)
    1300             :   {
    1301           0 :     nr_ice_component *comp=cb_arg;
    1302             : 
    1303           0 :     switch (comp->consent_ctx->state) {
    1304             :       case NR_STUN_CLIENT_STATE_FAILED:
    1305           0 :         if (comp->consent_ctx->error_code == 403) {
    1306           0 :           r_log(LOG_ICE, LOG_INFO, "ICE(%s)/STREAM(%s)/COMP(%d): Consent revoked by peer",
    1307           0 :                 comp->ctx->label, comp->stream->label, comp->component_id);
    1308           0 :           nr_ice_component_consent_failed(comp);
    1309             :         }
    1310           0 :         break;
    1311             :       case NR_STUN_CLIENT_STATE_DONE:
    1312           0 :         r_log(LOG_ICE, LOG_INFO, "ICE(%s)/STREAM(%s)/COMP(%d): Consent refreshed",
    1313           0 :               comp->ctx->label, comp->stream->label, comp->component_id);
    1314           0 :         nr_ice_component_consent_refreshed(comp);
    1315           0 :         break;
    1316             :       case NR_STUN_CLIENT_STATE_TIMED_OUT:
    1317           0 :         r_log(LOG_ICE, LOG_INFO, "ICE(%s)/STREAM(%s)/COMP(%d): A single consent refresh request timed out",
    1318           0 :               comp->ctx->label, comp->stream->label, comp->component_id);
    1319           0 :         nr_ice_component_disconnected(comp);
    1320           0 :         break;
    1321             :       default:
    1322           0 :         break;
    1323             :     }
    1324           0 :   }
    1325             : 
    1326           0 : int nr_ice_component_refresh_consent(nr_stun_client_ctx *ctx, NR_async_cb finished_cb, void *cb_arg)
    1327             :   {
    1328             :     int r,_status;
    1329             : 
    1330           0 :     nr_stun_client_reset(ctx);
    1331             : 
    1332           0 :     if (r=nr_stun_client_start(ctx, NR_ICE_CLIENT_MODE_BINDING_REQUEST, finished_cb, cb_arg))
    1333           0 :       ABORT(r);
    1334             : 
    1335           0 :     _status=0;
    1336             :   abort:
    1337           0 :     return(_status);
    1338             :   }
    1339             : 
    1340           0 : void nr_ice_component_consent_calc_consent_timer(nr_ice_component *comp)
    1341             :   {
    1342             :     uint16_t trange, trand, tval;
    1343             : 
    1344           0 :     trange = NR_ICE_CONSENT_TIMER_DEFAULT * 20 / 100;
    1345           0 :     tval = NR_ICE_CONSENT_TIMER_DEFAULT - trange;
    1346           0 :     if (!nr_crypto_random_bytes((UCHAR*)&trand, sizeof(trand)))
    1347           0 :       tval += (trand % (trange * 2));
    1348             : 
    1349           0 :     if (comp->ctx->test_timer_divider)
    1350           0 :       tval = tval / comp->ctx->test_timer_divider;
    1351             : 
    1352             :     /* The timeout of the transaction is the maximum time until we send the
    1353             :      * next consent request. */
    1354           0 :     comp->consent_ctx->maximum_transmits_timeout_ms = tval;
    1355           0 :   }
    1356             : 
    1357           0 : static void nr_ice_component_consent_timer_cb(NR_SOCKET s, int how, void *cb_arg)
    1358             :   {
    1359           0 :     nr_ice_component *comp=cb_arg;
    1360             :     int r;
    1361             : 
    1362           0 :     if (!comp->consent_ctx) {
    1363           0 :       return;
    1364             :     }
    1365             : 
    1366           0 :     if (comp->consent_timer) {
    1367           0 :       NR_async_timer_cancel(comp->consent_timer);
    1368             :     }
    1369           0 :     comp->consent_timer = 0;
    1370             : 
    1371           0 :     comp->consent_ctx->params.ice_binding_request.username =
    1372           0 :       comp->stream->l2r_user;
    1373           0 :     comp->consent_ctx->params.ice_binding_request.password =
    1374           0 :       comp->stream->l2r_pass;
    1375           0 :     comp->consent_ctx->params.ice_binding_request.control =
    1376           0 :       comp->stream->pctx->controlling?
    1377           0 :       NR_ICE_CONTROLLING:NR_ICE_CONTROLLED;
    1378           0 :     comp->consent_ctx->params.ice_binding_request.tiebreaker =
    1379           0 :       comp->stream->pctx->tiebreaker;
    1380           0 :     comp->consent_ctx->params.ice_binding_request.priority =
    1381           0 :       comp->active->local->priority;
    1382             : 
    1383           0 :     nr_ice_component_consent_calc_consent_timer(comp);
    1384             : 
    1385           0 :     if (r=nr_ice_component_refresh_consent(comp->consent_ctx,
    1386             :                                            nr_ice_component_refresh_consent_cb,
    1387             :                                            comp)) {
    1388           0 :       r_log(LOG_ICE,LOG_ERR,"ICE(%s)/STREAM(%s)/COMP(%d): Refresh consent failed with %d",
    1389           0 :             comp->ctx->label, comp->stream->label, comp->component_id, r);
    1390             :     }
    1391             : 
    1392           0 :     nr_ice_component_consent_schedule_consent_timer(comp);
    1393             : 
    1394             :   }
    1395             : 
    1396           0 : void nr_ice_component_consent_schedule_consent_timer(nr_ice_component *comp)
    1397             :   {
    1398           0 :     if (!comp->can_send) {
    1399           0 :       return;
    1400             :     }
    1401             : 
    1402           0 :     NR_ASYNC_TIMER_SET(comp->consent_ctx->maximum_transmits_timeout_ms,
    1403             :                        nr_ice_component_consent_timer_cb, comp,
    1404             :                        &comp->consent_timer);
    1405             :   }
    1406             : 
    1407           0 : void nr_ice_component_refresh_consent_now(nr_ice_component *comp)
    1408             :   {
    1409           0 :     nr_ice_component_consent_timer_cb(0, 0, comp);
    1410           0 :   }
    1411             : 
    1412           0 : void nr_ice_component_consent_destroy(nr_ice_component *comp)
    1413             :   {
    1414           0 :     if (comp->consent_timer) {
    1415           0 :       NR_async_timer_cancel(comp->consent_timer);
    1416           0 :       comp->consent_timer = 0;
    1417             :     }
    1418           0 :     if (comp->consent_timeout) {
    1419           0 :       NR_async_timer_cancel(comp->consent_timeout);
    1420           0 :       comp->consent_timeout = 0;
    1421             :     }
    1422           0 :     if (comp->consent_handle) {
    1423           0 :       nr_ice_socket_deregister(comp->active->local->isock,
    1424             :                                comp->consent_handle);
    1425           0 :       comp->consent_handle = 0;
    1426             :     }
    1427           0 :     if (comp->consent_ctx) {
    1428           0 :       nr_stun_client_ctx_destroy(&comp->consent_ctx);
    1429           0 :       comp->consent_ctx = 0;
    1430             :     }
    1431           0 :   }
    1432             : 
    1433           0 : int nr_ice_component_setup_consent(nr_ice_component *comp)
    1434             :   {
    1435             :     int r,_status;
    1436             : 
    1437           0 :     r_log(LOG_ICE,LOG_DEBUG,"ICE(%s)/STREAM(%s)/COMP(%d): Setting up refresh consent",
    1438           0 :           comp->ctx->label, comp->stream->label, comp->component_id);
    1439             : 
    1440           0 :     nr_ice_component_consent_destroy(comp);
    1441             : 
    1442           0 :     if (r=nr_stun_client_ctx_create("consent", comp->active->local->osock,
    1443           0 :                                     &comp->active->remote->addr, 0,
    1444             :                                     &comp->consent_ctx))
    1445           0 :       ABORT(r);
    1446             :     /* Consent request get send only once. */
    1447           0 :     comp->consent_ctx->maximum_transmits = 1;
    1448             : 
    1449           0 :     if (r=nr_ice_socket_register_stun_client(comp->active->local->isock,
    1450             :             comp->consent_ctx, &comp->consent_handle))
    1451           0 :       ABORT(r);
    1452             : 
    1453           0 :     comp->can_send = 1;
    1454           0 :     comp->disconnected = 0;
    1455           0 :     nr_ice_component_consent_refreshed(comp);
    1456             : 
    1457           0 :     nr_ice_component_consent_calc_consent_timer(comp);
    1458           0 :     nr_ice_component_consent_schedule_consent_timer(comp);
    1459             : 
    1460           0 :     _status=0;
    1461             :   abort:
    1462           0 :     return(_status);
    1463             :   }
    1464             : 
    1465           0 : int nr_ice_component_nominated_pair(nr_ice_component *comp, nr_ice_cand_pair *pair)
    1466             :   {
    1467             :     int r,_status;
    1468             :     nr_ice_cand_pair *p2;
    1469             : 
    1470             :     /* Are we changing what the nominated pair is? */
    1471           0 :     if(comp->nominated){
    1472           0 :       if(comp->nominated->priority >= pair->priority)
    1473           0 :         return(0);
    1474           0 :       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);
    1475             :       /* As consent doesn't hold a reference to its isock this needs to happen
    1476             :        * before making the new pair the active one. */
    1477           0 :       nr_ice_component_consent_destroy(comp);
    1478             :     }
    1479             : 
    1480             :     /* Set the new nominated pair */
    1481           0 :     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);
    1482           0 :     comp->state=NR_ICE_COMPONENT_NOMINATED;
    1483           0 :     comp->nominated=pair;
    1484           0 :     comp->active=pair;
    1485             : 
    1486           0 :     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);
    1487             : 
    1488             :     /* Cancel checks in WAITING and FROZEN per ICE S 8.1.2 */
    1489           0 :     p2=TAILQ_FIRST(&comp->stream->trigger_check_queue);
    1490           0 :     while(p2){
    1491           0 :       if((p2 != pair) &&
    1492           0 :          (p2->remote->component->component_id == comp->component_id)) {
    1493           0 :         assert(p2->state == NR_ICE_PAIR_STATE_WAITING ||
    1494             :                p2->state == NR_ICE_PAIR_STATE_CANCELLED);
    1495           0 :         r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/STREAM(%s)/COMP(%d)/CAND-PAIR(%s): cancelling FROZEN/WAITING pair %s in trigger check queue because CAND-PAIR(%s) was nominated.",comp->stream->pctx->label,comp->stream->label,comp->component_id,p2->codeword,p2->as_string,pair->codeword);
    1496             : 
    1497           0 :         if(r=nr_ice_candidate_pair_cancel(pair->pctx,p2,0))
    1498           0 :           ABORT(r);
    1499             :       }
    1500             : 
    1501           0 :       p2=TAILQ_NEXT(p2,triggered_check_queue_entry);
    1502             :     }
    1503           0 :     p2=TAILQ_FIRST(&comp->stream->check_list);
    1504           0 :     while(p2){
    1505           0 :       if((p2 != pair) &&
    1506           0 :          (p2->remote->component->component_id == comp->component_id) &&
    1507           0 :          ((p2->state == NR_ICE_PAIR_STATE_FROZEN) ||
    1508           0 :           (p2->state == NR_ICE_PAIR_STATE_WAITING))) {
    1509           0 :         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);
    1510             : 
    1511           0 :         if(r=nr_ice_candidate_pair_cancel(pair->pctx,p2,0))
    1512           0 :           ABORT(r);
    1513             :       }
    1514             : 
    1515           0 :       p2=TAILQ_NEXT(p2,check_queue_entry);
    1516             :     }
    1517           0 :     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);
    1518             : 
    1519           0 :     if(r=nr_ice_component_setup_consent(comp))
    1520           0 :       ABORT(r);
    1521             : 
    1522           0 :     if(r=nr_ice_media_stream_component_nominated(comp->stream,comp))
    1523           0 :       ABORT(r);
    1524             : 
    1525           0 :     _status=0;
    1526             :   abort:
    1527           0 :     return(_status);
    1528             :   }
    1529             : 
    1530           0 : static int nr_ice_component_have_all_pairs_failed(nr_ice_component *comp)
    1531             :   {
    1532             :     nr_ice_cand_pair *p2;
    1533             : 
    1534           0 :     p2=TAILQ_FIRST(&comp->stream->check_list);
    1535           0 :     while(p2){
    1536           0 :       if(comp->component_id==p2->local->component_id){
    1537           0 :         switch(p2->state){
    1538             :         case NR_ICE_PAIR_STATE_FROZEN:
    1539             :         case NR_ICE_PAIR_STATE_WAITING:
    1540             :         case NR_ICE_PAIR_STATE_IN_PROGRESS:
    1541             :         case NR_ICE_PAIR_STATE_SUCCEEDED:
    1542           0 :             return(0);
    1543             :         case NR_ICE_PAIR_STATE_FAILED:
    1544             :         case NR_ICE_PAIR_STATE_CANCELLED:
    1545             :             /* states that will never be recovered from */
    1546           0 :             break;
    1547             :         default:
    1548           0 :             assert(0);
    1549             :             break;
    1550             :         }
    1551             :       }
    1552             : 
    1553           0 :       p2=TAILQ_NEXT(p2,check_queue_entry);
    1554             :     }
    1555             : 
    1556           0 :     return(1);
    1557             :   }
    1558             : 
    1559           0 : int nr_ice_component_failed_pair(nr_ice_component *comp, nr_ice_cand_pair *pair)
    1560             :   {
    1561           0 :     return nr_ice_component_check_if_failed(comp);
    1562             :   }
    1563             : 
    1564           0 : int nr_ice_component_check_if_failed(nr_ice_component *comp)
    1565             :   {
    1566           0 :     if (comp->state == NR_ICE_COMPONENT_RUNNING) {
    1567             :       /* Don't do anything to streams that aren't currently running */
    1568           0 :       r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/COMP(%d): Checking whether component needs to be marked failed.",comp->stream->pctx->label,comp->stream->label,comp->component_id);
    1569             : 
    1570           0 :       if (!comp->stream->pctx->trickle_grace_period_timer &&
    1571           0 :           nr_ice_component_have_all_pairs_failed(comp)) {
    1572           0 :         r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/STREAM(%s)/COMP(%d): All pairs are failed, and grace period has elapsed. Marking component as failed.",comp->stream->pctx->label,comp->stream->label,comp->component_id);
    1573           0 :         return nr_ice_media_stream_component_failed(comp->stream,comp);
    1574             :       }
    1575             :     }
    1576             : 
    1577           0 :     return(0);
    1578             :   }
    1579             : 
    1580           0 : int nr_ice_component_select_pair(nr_ice_peer_ctx *pctx, nr_ice_component *comp)
    1581             :   {
    1582           0 :     nr_ice_cand_pair **pairs=0;
    1583           0 :     int ct=0;
    1584             :     nr_ice_cand_pair *pair;
    1585             :     int r,_status;
    1586             : 
    1587             :     /* Size the array */
    1588           0 :     pair=TAILQ_FIRST(&comp->stream->check_list);
    1589           0 :     while(pair){
    1590           0 :       if (comp->component_id == pair->local->component_id)
    1591           0 :           ct++;
    1592             : 
    1593           0 :       pair=TAILQ_NEXT(pair,check_queue_entry);
    1594             :     }
    1595             : 
    1596             :     /* Make and fill the array */
    1597           0 :     if(!(pairs=RCALLOC(sizeof(nr_ice_cand_pair *)*ct)))
    1598           0 :       ABORT(R_NO_MEMORY);
    1599             : 
    1600           0 :     ct=0;
    1601           0 :     pair=TAILQ_FIRST(&comp->stream->check_list);
    1602           0 :     while(pair){
    1603           0 :       if (comp->component_id == pair->local->component_id)
    1604           0 :           pairs[ct++]=pair;
    1605             : 
    1606           0 :       pair=TAILQ_NEXT(pair,check_queue_entry);
    1607             :     }
    1608             : 
    1609           0 :     if (pctx->handler) {
    1610           0 :       if(r=pctx->handler->vtbl->select_pair(pctx->handler->obj,
    1611           0 :         comp->stream,comp->component_id,pairs,ct))
    1612           0 :         ABORT(r);
    1613             :     }
    1614             : 
    1615           0 :     _status=0;
    1616             :   abort:
    1617           0 :     RFREE(pairs);
    1618           0 :     return(_status);
    1619             :   }
    1620             : 
    1621             : 
    1622             : /* Close the underlying sockets for everything but the nominated candidate */
    1623           0 : int nr_ice_component_finalize(nr_ice_component *lcomp, nr_ice_component *rcomp)
    1624             :   {
    1625           0 :     nr_ice_socket *isock=0;
    1626             :     nr_ice_socket *s1,*s2;
    1627             : 
    1628           0 :     if(rcomp->state==NR_ICE_COMPONENT_NOMINATED){
    1629           0 :       assert(rcomp->active == rcomp->nominated);
    1630           0 :       isock=rcomp->nominated->local->isock;
    1631             :     }
    1632             : 
    1633           0 :     STAILQ_FOREACH_SAFE(s1, &lcomp->sockets, entry, s2){
    1634           0 :       if(s1!=isock){
    1635           0 :         STAILQ_REMOVE(&lcomp->sockets,s1,nr_ice_socket_,entry);
    1636           0 :         nr_ice_socket_destroy(&s1);
    1637             :       }
    1638             :     }
    1639             : 
    1640           0 :     return(0);
    1641             :   }
    1642             : 
    1643             : 
    1644           0 : int nr_ice_component_insert_pair(nr_ice_component *pcomp, nr_ice_cand_pair *pair)
    1645             :   {
    1646             :     int r,_status;
    1647             : 
    1648             :     /* Pairs for peer reflexive are marked SUCCEEDED immediately */
    1649           0 :     if (pair->state != NR_ICE_PAIR_STATE_FROZEN &&
    1650           0 :         pair->state != NR_ICE_PAIR_STATE_SUCCEEDED){
    1651           0 :       assert(0);
    1652             :       ABORT(R_BAD_ARGS);
    1653             :     }
    1654             : 
    1655           0 :     if(r=nr_ice_candidate_pair_insert(&pair->remote->stream->check_list,pair))
    1656           0 :       ABORT(r);
    1657             : 
    1658             :     /* Make sure the check timer is running, if the stream was previously
    1659             :      * started. We will not start streams just because a pair was created,
    1660             :      * unless it is the first pair to be created across all streams. */
    1661           0 :     r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/CAND-PAIR(%s): Ensure that check timer is running for new pair %s.",pair->remote->stream->pctx->label, pair->codeword, pair->as_string);
    1662             : 
    1663           0 :     if(pair->remote->stream->ice_state == NR_ICE_MEDIA_STREAM_CHECKS_ACTIVE ||
    1664           0 :        (pair->remote->stream->ice_state == NR_ICE_MEDIA_STREAM_CHECKS_FROZEN &&
    1665           0 :         !pair->remote->stream->pctx->checks_started)){
    1666           0 :       if(nr_ice_media_stream_start_checks(pair->remote->stream->pctx, pair->remote->stream)) {
    1667           0 :         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);
    1668           0 :         ABORT(R_INTERNAL);
    1669             :       }
    1670             :     }
    1671             : 
    1672           0 :     _status=0;
    1673             :   abort:
    1674           0 :     return(_status);
    1675             :   }
    1676             : 
    1677           0 : int nr_ice_component_get_default_candidate(nr_ice_component *comp, nr_ice_candidate **candp, int ip_version)
    1678             :   {
    1679             :     int _status;
    1680             :     nr_ice_candidate *cand;
    1681           0 :     nr_ice_candidate *best_cand = NULL;
    1682             : 
    1683             :     /* We have the component. Now find the "best" candidate, making
    1684             :        use of the fact that more "reliable" candidate types have
    1685             :        higher numbers. So, we sort by type and then priority within
    1686             :        type
    1687             :     */
    1688           0 :     cand=TAILQ_FIRST(&comp->candidates);
    1689           0 :     while(cand){
    1690           0 :       if (!nr_ice_ctx_hide_candidate(comp->ctx, cand) &&
    1691           0 :           cand->addr.ip_version == ip_version) {
    1692           0 :         if (!best_cand) {
    1693           0 :           best_cand = cand;
    1694             :         }
    1695           0 :         else if (best_cand->type < cand->type) {
    1696           0 :           best_cand = cand;
    1697           0 :         } else if (best_cand->type == cand->type &&
    1698           0 :                    best_cand->priority < cand->priority) {
    1699           0 :           best_cand = cand;
    1700             :         }
    1701             :       }
    1702             : 
    1703           0 :       cand=TAILQ_NEXT(cand,entry_comp);
    1704             :     }
    1705             : 
    1706             :     /* No candidates */
    1707           0 :     if (!best_cand)
    1708           0 :       ABORT(R_NOT_FOUND);
    1709             : 
    1710           0 :     *candp = best_cand;
    1711             : 
    1712           0 :     _status=0;
    1713             :   abort:
    1714           0 :     return(_status);
    1715             : 
    1716             :   }
    1717             : 

Generated by: LCOV version 1.13