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

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /*
     2 Copyright (c) 2007, Adobe Systems, Incorporated
     3 All rights reserved.
     5 Redistribution and use in source and binary forms, with or without
     6 modification, are permitted provided that the following conditions are
     7 met:
     9 * Redistributions of source code must retain the above copyright
    10   notice, this list of conditions and the following disclaimer.
    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.
    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.
    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 */
    35 static char *RCSSTRING __UNUSED__="$Id: ice_component.c,v 1.2 2008/04/28 17:59:01 ekr Exp $";
    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_buffered_stun.h"
    48 #include "ice_reg.h"
    50 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);
    51 static int nr_ice_pre_answer_request_destroy(nr_ice_pre_answer_request **parp);
    53 /* This function takes ownership of the contents of req (but not req itself) */
    54 static int nr_ice_pre_answer_request_create(nr_socket *sock, nr_stun_server_request *req, nr_ice_pre_answer_request **parp)
    55   {
    56     int r, _status;
    57     nr_ice_pre_answer_request *par = 0;
    58     nr_stun_message_attribute *attr;
    60     if (!(par = RCALLOC(sizeof(nr_ice_pre_answer_request))))
    61       ABORT(R_NO_MEMORY);
    63     par->req = *req; /* Struct assignment */
    64     memset(req, 0, sizeof(*req)); /* Zero contents to avoid confusion */
    66     if (r=nr_socket_getaddr(sock, &par->local_addr))
    67       ABORT(r);
    68     if (!nr_stun_message_has_attribute(par->req.request, NR_STUN_ATTR_USERNAME, &attr))
    69       ABORT(R_INTERNAL);
    70     if (!(par->username = r_strdup(attr->u.username)))
    71       ABORT(R_NO_MEMORY);
    73     *parp=par;
    74     _status=0;
    75  abort:
    76     if (_status) {
    77       /* Erase the request so we don't free it */
    78       memset(&par->req, 0, sizeof(nr_stun_server_request));
    79       nr_ice_pre_answer_request_destroy(&par);
    80     }
    82     return(_status);
    83   }
    85 static int nr_ice_pre_answer_request_destroy(nr_ice_pre_answer_request **parp)
    86   {
    87     nr_ice_pre_answer_request *par;
    89     if (!parp || !*parp)
    90       return(0);
    92     par = *parp;
    93     *parp = 0;
    95     nr_stun_message_destroy(&par->req.request);
    96     nr_stun_message_destroy(&par->req.response);
    98     RFREE(par->username);
   100     return(0);
   101   }
   103 int nr_ice_component_create(nr_ice_media_stream *stream, int component_id, nr_ice_component **componentp)
   104   {
   105     int _status;
   106     nr_ice_component *comp=0;
   108     if(!(comp=RCALLOC(sizeof(nr_ice_component))))
   109       ABORT(R_NO_MEMORY);
   111     comp->state=NR_ICE_COMPONENT_UNPAIRED;
   112     comp->component_id=component_id;
   113     comp->stream=stream;
   114     comp->ctx=stream->ctx;
   116     STAILQ_INIT(&comp->sockets);
   117     TAILQ_INIT(&comp->candidates);
   118     STAILQ_INIT(&comp->pre_answer_reqs);
   120     STAILQ_INSERT_TAIL(&stream->components,comp,entry);
   122     _status=0;
   123   abort:
   124     return(_status);
   125   }
   127 int nr_ice_component_destroy(nr_ice_component **componentp)
   128   {
   129     nr_ice_component *component;
   130     nr_ice_socket *s1,*s2;
   131     nr_ice_candidate *c1,*c2;
   132     nr_ice_pre_answer_request *r1,*r2;
   134     if(!componentp || !*componentp)
   135       return(0);
   137     component=*componentp;
   138     *componentp=0;
   140     /* Detach ourselves from the sockets */
   141     if (component->local_component){
   142       nr_ice_socket *isock=STAILQ_FIRST(&component->local_component->sockets);
   143       while(isock){
   144         nr_stun_server_remove_client(isock->stun_server, component);
   145         isock=STAILQ_NEXT(isock, entry);
   146       }
   147     }
   149     /* candidates MUST be destroyed before the sockets so that
   150        they can deregister */
   151     TAILQ_FOREACH_SAFE(c1, &component->candidates, entry_comp, c2){
   152       TAILQ_REMOVE(&component->candidates,c1,entry_comp);
   153       nr_ice_candidate_destroy(&c1);
   154     }
   156     STAILQ_FOREACH_SAFE(s1, &component->sockets, entry, s2){
   157       STAILQ_REMOVE(&component->sockets,s1,nr_ice_socket_,entry);
   158       nr_ice_socket_destroy(&s1);
   159     }
   161     STAILQ_FOREACH_SAFE(r1, &component->pre_answer_reqs, entry, r2){
   162       STAILQ_REMOVE(&component->pre_answer_reqs,r1,nr_ice_pre_answer_request_, entry);
   163       nr_ice_pre_answer_request_destroy(&r1);
   164     }
   166     if(component->keepalive_timer)
   167       NR_async_timer_cancel(component->keepalive_timer);
   168     nr_stun_client_ctx_destroy(&component->keepalive_ctx);
   170     RFREE(component);
   171     return(0);
   172   }
   174 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)
   175   {
   176     nr_socket *sock;
   177     nr_ice_socket *isock=0;
   178     nr_ice_candidate *cand=0;
   179     int i;
   180     int j;
   181     char label[256];
   182     int r,_status;
   184     /* Now one ice_socket for each address */
   185     for(i=0;i<addr_ct;i++){
   186       char suppress;
   188       if(r=NR_reg_get2_char(NR_ICE_REG_SUPPRESS_INTERFACE_PRFX,addrs[i].addr.ifname,&suppress)){
   189         if(r!=R_NOT_FOUND)
   190           ABORT(r);
   191       }
   192       else{
   193         if(suppress)
   194           continue;
   195       }
   196       r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): host address %s",ctx->label,addrs[i].addr.as_string);
   197       if(r=nr_socket_local_create(&addrs[i].addr,&sock)){
   198         r_log(LOG_ICE,LOG_WARNING,"ICE(%s): couldn't create socket for address %s",ctx->label,addrs[i].addr.as_string);
   199         continue;
   200       }
   202       if(r=nr_ice_socket_create(ctx,component,sock,&isock))
   203         ABORT(r);
   204       /* Create one host candidate */
   205       if(r=nr_ice_candidate_create(ctx,component,isock,sock,HOST,0,
   206         component->component_id,&cand))
   207         ABORT(r);
   209       TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
   210       component->candidate_ct++;
   211       cand=0;
   213       /* And a srvrflx candidate for each STUN server */
   214       for(j=0;j<ctx->stun_server_ct;j++){
   215         if(r=nr_ice_candidate_create(ctx,component,
   216           isock,sock,SERVER_REFLEXIVE,
   217           &ctx->stun_servers[j],component->component_id,&cand))
   218           ABORT(r);
   219         TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
   220         component->candidate_ct++;
   221         cand=0;
   222       }
   224 #ifdef USE_TURN
   225       /* And both a srvrflx and relayed candidate for each TURN server */
   226       for(j=0;j<ctx->turn_server_ct;j++){
   227         nr_socket *turn_sock;
   228         nr_ice_candidate *srvflx_cand;
   230         /* Skip non-UDP */
   231         if (ctx->turn_servers[j].transport != IPPROTO_UDP)
   232           continue;
   234         /* srvrflx */
   235         if(r=nr_ice_candidate_create(ctx,component,
   236           isock,sock,SERVER_REFLEXIVE,
   237           &ctx->turn_servers[j].turn_server,component->component_id,&cand))
   238           ABORT(r);
   239         cand->state=NR_ICE_CAND_STATE_INITIALIZING; /* Don't start */
   240         cand->done_cb=nr_ice_initialize_finished_cb;
   241         cand->cb_arg=cand;
   243         TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
   244         component->candidate_ct++;
   245         srvflx_cand=cand;
   247         /* relayed*/
   248         if(r=nr_socket_turn_create(sock, &turn_sock))
   249           ABORT(r);
   250         if(r=nr_ice_candidate_create(ctx,component,
   251           isock,turn_sock,RELAYED,
   252           &ctx->turn_servers[j].turn_server,component->component_id,&cand))
   253            ABORT(r);
   254         cand->u.relayed.srvflx_candidate=srvflx_cand;
   255         cand->u.relayed.server=&ctx->turn_servers[j];
   256         TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
   257         component->candidate_ct++;
   259         cand=0;
   260       }
   261 #endif /* USE_TURN */
   263       /* Create a STUN server context for this socket */
   264       snprintf(label, sizeof(label), "server(%s)", addrs[i].addr.as_string);
   265       if(r=nr_stun_server_ctx_create(label,sock,&isock->stun_server))
   266         ABORT(r);
   267       if(r=nr_ice_socket_register_stun_server(isock,isock->stun_server,&isock->stun_server_handle))
   268         ABORT(r);
   270       /* Add the default STUN credentials so that we can respond before
   271          we hear about the peer. */
   272       if(r=nr_stun_server_add_default_client(isock->stun_server, lufrag, pwd, nr_ice_component_stun_server_default_cb, component))
   273         ABORT(r);
   275       STAILQ_INSERT_TAIL(&component->sockets,isock,entry);
   276     }
   278     _status = 0;
   279  abort:
   280     return(_status);
   281   }
   283 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)
   284   {
   285     nr_ice_socket *isock=0;
   286     nr_ice_candidate *cand=0;
   287     int i;
   288     int j;
   289     char label[256];
   290     int r,_status;
   292     /* Create a new relayed candidate for each addr/TURN server pair */
   293     for(i=0;i<addr_ct;i++){
   294       char suppress;
   296       if(r=NR_reg_get2_char(NR_ICE_REG_SUPPRESS_INTERFACE_PRFX,addrs[i].addr.ifname,&suppress)){
   297         if(r!=R_NOT_FOUND)
   298           ABORT(r);
   299       }
   300       else{
   301         if(suppress)
   302           continue;
   303       }
   305 #ifdef USE_TURN
   306       for(j=0;j<ctx->turn_server_ct;j++){
   307         nr_transport_addr addr;
   308         nr_socket *sock;
   309         nr_socket *buffered_sock;
   310         nr_socket *turn_sock;
   312         /* Skip non-TCP */
   313         if (ctx->turn_servers[j].transport != IPPROTO_TCP)
   314           continue;
   316         /* Create a local socket */
   317         if ((r=nr_transport_addr_copy(&addr, &addrs[i].addr)))
   318           ABORT(r);
   319         addr.protocol = IPPROTO_TCP;
   320         if ((r=nr_transport_addr_fmt_addr_string(&addr)))
   321           ABORT(r);
   322         if((r=nr_socket_local_create(&addr, &sock))){
   323           r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): couldn't create socket for address %s",ctx->label,addr.as_string);
   324           continue;
   325         }
   326         /* Wrap it */
   327         if((r=nr_socket_buffered_stun_create(sock, NR_STUN_MAX_MESSAGE_SIZE, &buffered_sock)))
   328           ABORT(r);
   330         /* The TURN socket */
   331         if(r=nr_socket_turn_create(buffered_sock, &turn_sock))
   332           ABORT(r);
   334         /* Create an ICE socket */
   335         if((r=nr_ice_socket_create(ctx, component, buffered_sock, &isock)))
   336           ABORT(r);
   338         /* Attach ourselves to it */
   339         if(r=nr_ice_candidate_create(ctx,component,
   340           isock,turn_sock,RELAYED,
   341           &ctx->turn_servers[j].turn_server,component->component_id,&cand))
   342           ABORT(r);
   343         cand->u.relayed.srvflx_candidate=NULL;
   344         cand->u.relayed.server=&ctx->turn_servers[j];
   345         TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
   346         component->candidate_ct++;
   347         cand=0;
   349         /* Create a STUN server context for this socket */
   350         snprintf(label, sizeof(label), "server(%s)", addr.as_string);
   351         if(r=nr_stun_server_ctx_create(label,sock,&isock->stun_server))
   352           ABORT(r);
   353         if(r=nr_ice_socket_register_stun_server(isock,isock->stun_server,&isock->stun_server_handle))
   354           ABORT(r);
   356        /* Add the default STUN credentials so that we can respond before
   357           we hear about the peer.*/
   358         if(r=nr_stun_server_add_default_client(isock->stun_server, lufrag, pwd, nr_ice_component_stun_server_default_cb, component))
   359           ABORT(r);
   361         STAILQ_INSERT_TAIL(&component->sockets,isock,entry);
   362       }
   363     }
   364 #endif
   366     _status = 0;
   367  abort:
   368     return(_status);
   369   }
   372 /* Make all the candidates we can make at the beginning */
   373 int nr_ice_component_initialize(struct nr_ice_ctx_ *ctx,nr_ice_component *component)
   374   {
   375     int r,_status;
   376     nr_local_addr *addrs=ctx->local_addrs;
   377     int addr_ct=ctx->local_addr_ct;
   378     char *lufrag;
   379     char *lpwd;
   380     Data pwd;
   381     nr_ice_candidate *cand;
   383     r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): initializing component with id %d",ctx->label,component->component_id);
   385     if(addr_ct==0){
   386       r_log(LOG_ICE,LOG_ERR,"ICE(%s): no local addresses available",ctx->label);
   387       ABORT(R_NOT_FOUND);
   388     }
   390     /* Note: we need to recompute these because
   391        we have not yet computed the values in the peer media stream.*/
   392     lufrag=component->stream->ufrag ? component->stream->ufrag : ctx->ufrag;
   393     assert(lufrag);
   394     if (!lufrag)
   395       ABORT(R_INTERNAL);
   396     lpwd=component->stream->pwd ? component->stream->pwd :ctx->pwd;
   397     assert(lpwd);
   398     if (!lpwd)
   399       ABORT(R_INTERNAL);
   400     INIT_DATA(pwd, (UCHAR *)lpwd, strlen(lpwd));
   402     /* Initialize the UDP candidates */
   403     if (r=nr_ice_component_initialize_udp(ctx, component, addrs, addr_ct, lufrag, &pwd))
   404       ABORT(r);
   405     /* And the TCP candidates */
   406     if (r=nr_ice_component_initialize_tcp(ctx, component, addrs, addr_ct, lufrag, &pwd))
   407       ABORT(r);
   409     /* count the candidates that will be initialized */
   410     cand=TAILQ_FIRST(&component->candidates);
   411     if(!cand){
   412       r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): couldn't create any valid candidates",ctx->label);
   413       ABORT(R_NOT_FOUND);
   414     }
   416     while(cand){
   417       ctx->uninitialized_candidates++;
   418       cand=TAILQ_NEXT(cand,entry_comp);
   419     }
   421     /* Now initialize all the candidates */
   422     cand=TAILQ_FIRST(&component->candidates);
   423     while(cand){
   424       if(cand->state!=NR_ICE_CAND_STATE_INITIALIZING){
   425         if(r=nr_ice_candidate_initialize(cand,nr_ice_initialize_finished_cb,cand)){
   426           if(r!=R_WOULDBLOCK){
   427             ctx->uninitialized_candidates--;
   428             cand->state=NR_ICE_CAND_STATE_FAILED;
   429           }
   430         }
   431       }
   432       cand=TAILQ_NEXT(cand,entry_comp);
   433     }
   434     _status=0;
   435  abort:
   436     return(_status);
   437   }
   439 static int nr_ice_any_peer_paired(nr_ice_candidate* cand) {
   440   nr_ice_peer_ctx* pctx=STAILQ_FIRST(&cand->ctx->peers);
   441   while(pctx && pctx->state == NR_ICE_PEER_STATE_UNPAIRED){
   442     /* Is it worth actually looking through the check lists? Probably not. */
   443     pctx=STAILQ_NEXT(pctx,entry);
   444   }
   445   return pctx != NULL;
   446 }
   448 /*
   449   Compare this newly initialized candidate against the other initialized
   450   candidates and discard the lower-priority one if they are redundant.
   452    This algorithm combined with the other algorithms, favors
   453    host > srflx > relay
   454  */
   455 int nr_ice_component_maybe_prune_candidate(nr_ice_ctx *ctx, nr_ice_component *comp, nr_ice_candidate *c1, int *was_pruned)
   456   {
   457     nr_ice_candidate *c2, *tmp = NULL;
   459     *was_pruned = 0;
   460     c2 = TAILQ_FIRST(&comp->candidates);
   461     while(c2){
   462       if((c1 != c2) &&
   463          (c2->state == NR_ICE_CAND_STATE_INITIALIZED) &&
   464          !nr_transport_addr_cmp(&c1->base,&c2->base,NR_TRANSPORT_ADDR_CMP_MODE_ALL) &&
   465          !nr_transport_addr_cmp(&c1->addr,&c2->addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL)){
   467         if((c1->type == c2->type) ||
   468            (c1->type==HOST && c2->type == SERVER_REFLEXIVE) ||
   469            (c2->type==HOST && c1->type == SERVER_REFLEXIVE)){
   471           /*
   472              These are redundant. Remove the lower pri one, or if pairing has
   473              already occurred, remove the newest one.
   475              Since this algorithmis run whenever a new candidate
   476              is initialized, there should at most one duplicate.
   477            */
   478           if ((c1->priority <= c2->priority) || nr_ice_any_peer_paired(c2)) {
   479             tmp = c1;
   480             *was_pruned = 1;
   481           }
   482           else {
   483             tmp = c2;
   484           }
   485           break;
   486         }
   487       }
   489       c2=TAILQ_NEXT(c2,entry_comp);
   490     }
   492     if (tmp) {
   493       r_log(LOG_ICE,LOG_DEBUG,"ICE(%s)/CAND(%s): Removing redundant candidate",
   494             ctx->label,tmp->label);
   496       TAILQ_REMOVE(&comp->candidates,tmp,entry_comp);
   497       comp->candidate_ct--;
   498       TAILQ_REMOVE(&tmp->isock->candidates,tmp,entry_sock);
   500       nr_ice_candidate_destroy(&tmp);
   501     }
   503     return 0;
   504   }
   506 /* Section 7.2.1 */
   507 static int nr_ice_component_process_incoming_check(nr_ice_component *comp, nr_transport_addr *local_addr, nr_stun_server_request *req, int *error)
   508   {
   509     nr_ice_cand_pair *pair;
   510     nr_ice_candidate *pcand=0;
   511     nr_stun_message *sreq=req->request;
   512     nr_stun_message_attribute *attr;
   513     int component_id_matched;
   514     int local_addr_matched;
   515     int remote_addr_matched;
   516     nr_ice_cand_pair *found_invalid=0;
   517     int r=0,_status;
   519     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);
   521     if (comp->state == NR_ICE_COMPONENT_DISABLED)
   522       ABORT(R_REJECTED);
   524     /* Check for role conficts (7.2.1.1) */
   525     if(comp->stream->pctx->controlling){
   526       if(nr_stun_message_has_attribute(sreq,NR_STUN_ATTR_ICE_CONTROLLING,&attr)){
   527         /* OK, there is a conflict. Who's right? */
   528         r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s): role conflict, both controlling",comp->stream->pctx->label);
   530         if(attr->u.ice_controlling > comp->stream->pctx->tiebreaker){
   531           /* They are: switch */
   532           r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s): switching to controlled",comp->stream->pctx->label);
   534           comp->stream->pctx->controlling=0;
   535         }
   536         else {
   537           /* We are: throw an error */
   538           r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s): returning 487 role conflict",comp->stream->pctx->label);
   540           *error=487;
   541           ABORT(R_REJECTED);
   542         }
   543       }
   544     }
   545     else{
   546       if(nr_stun_message_has_attribute(sreq,NR_STUN_ATTR_ICE_CONTROLLED,&attr)){
   547         /* OK, there is a conflict. Who's right? */
   548         r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s): role conflict, both controlled",comp->stream->pctx->label);
   550         if(attr->u.ice_controlling < comp->stream->pctx->tiebreaker){
   551           r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s): switching to controlling",comp->stream->pctx->label);
   553           /* They are: switch */
   554           comp->stream->pctx->controlling=1;
   555         }
   556         else {
   557           /* We are: throw an error */
   558           r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s): returning 487 role conflict",comp->stream->pctx->label);
   560           *error=487;
   561           ABORT(R_REJECTED);
   562         }
   563       }
   564     }
   566     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);
   568     pair=TAILQ_FIRST(&comp->stream->check_list);
   569     while(pair){
   570       component_id_matched = 0;
   571       local_addr_matched = 0;
   572       remote_addr_matched = 0;
   574       if(pair->remote->component->component_id!=comp->component_id)
   575         goto next_pair;
   576       component_id_matched = 1;
   578       if(nr_transport_addr_cmp(&pair->local->base,local_addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL))
   579         goto next_pair;
   580       local_addr_matched=1;
   583       if(nr_transport_addr_cmp(&pair->remote->addr,&req->src_addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL))
   584         goto next_pair;
   585       remote_addr_matched = 1;
   587       if(pair->state==NR_ICE_PAIR_STATE_FAILED){
   588         found_invalid=pair;
   589         goto next_pair;
   590       }
   592       if (local_addr_matched && remote_addr_matched){
   593         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);
   594         break; /* OK, this is a known pair */
   595       }
   597     next_pair:
   598       pair=TAILQ_NEXT(pair,entry);
   599     }
   601     if(!pair){
   602       if(!found_invalid){
   603         /* First find our local component candidate */
   604         nr_ice_candidate *cand;
   606         r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s): no matching pair",comp->stream->pctx->label);
   607         cand=TAILQ_FIRST(&comp->local_component->candidates);
   608         while(cand){
   609           if(!nr_transport_addr_cmp(&cand->addr,local_addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL))
   610             break;
   612           cand=TAILQ_NEXT(cand,entry_comp);
   613         }
   615         /* Well, this really shouldn't happen, but it's an error from the
   616            other side, so we just throw an error and keep going */
   617         if(!cand){
   618           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);
   620           *error=400;
   621           ABORT(R_NOT_FOUND);
   622         }
   624         /* We now need to make a peer reflexive */
   625         if(r=nr_ice_peer_peer_rflx_candidate_create(comp->stream->pctx->ctx,"prflx",comp,&req->src_addr,&pcand)) {
   626           *error=(r==R_NO_MEMORY)?500:400;
   627           ABORT(r);
   628         }
   629         if(!nr_stun_message_has_attribute(sreq,NR_STUN_ATTR_PRIORITY,&attr)){
   630           r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s): Rejecting stun request without priority",comp->stream->pctx->label);
   631           *error=487;
   632           ABORT(R_BAD_DATA);
   633         }
   634         pcand->priority=attr->u.priority;
   635         pcand->state=NR_ICE_CAND_PEER_CANDIDATE_PAIRED;
   637         if(r=nr_ice_candidate_pair_create(comp->stream->pctx,cand,pcand,
   638              &pair)) {
   639           *error=(r==R_NO_MEMORY)?500:400;
   640           ABORT(r);
   641         }
   642         nr_ice_candidate_pair_set_state(pair->pctx,pair,NR_ICE_PAIR_STATE_FROZEN);
   644         if(r=nr_ice_component_insert_pair(comp,pair)) {
   645           *error=(r==R_NO_MEMORY)?500:400;
   646           nr_ice_candidate_pair_destroy(&pair);
   647           ABORT(r);
   648         }
   650         /* Do this last, since any call to ABORT will destroy pcand */
   651         TAILQ_INSERT_TAIL(&comp->candidates,pcand,entry_comp);
   652         pcand=0;
   653       }
   654       else{
   655         /* OK, there was a pair, it's just invalid: According to Section
   656            7.2.1.4, we need to resurrect it
   657         */
   658         if(found_invalid->state == NR_ICE_PAIR_STATE_FAILED){
   659           pair=found_invalid;
   661           r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/CAND-PAIR(%s): received STUN check on invalid pair, resurrecting: %s",comp->stream->pctx->label,pair->codeword,pair->as_string);
   662           nr_ice_candidate_pair_set_state(pair->pctx,pair,NR_ICE_PAIR_STATE_WAITING);
   663         }
   664         else{
   665           /* This shouldn't happen */
   666           r_log(LOG_ICE,LOG_ERR,"ICE-PEER(%s)/CAND-PAIR(%s): received STUN check on invalid pair that was not in state FAILED; this should not happen: %s",comp->stream->pctx->label,pair->codeword,pair->as_string);
   667           *error=500;
   668           ABORT(R_BAD_DATA);
   669         }
   670       }
   671     }
   673     /* OK, we've got a pair to work with. Turn it on */
   674     assert(pair);
   675     if(nr_stun_message_has_attribute(sreq,NR_STUN_ATTR_USE_CANDIDATE,0)){
   676       if(comp->stream->pctx->controlling){
   677         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);
   678       }
   679       else{
   680         /* If this is the first time we've noticed this is nominated...*/
   681         pair->peer_nominated=1;
   683         if(pair->state==NR_ICE_PAIR_STATE_SUCCEEDED && !pair->nominated){
   684           pair->nominated=1;
   686           if(r=nr_ice_component_nominated_pair(pair->remote->component, pair)) {
   687             *error=(r==R_NO_MEMORY)?500:400;
   688             ABORT(r);
   689           }
   690         }
   691       }
   692     }
   694     if(r=nr_ice_candidate_pair_do_triggered_check(comp->stream->pctx,pair)) {
   695       *error=(r==R_NO_MEMORY)?500:400;
   696       ABORT(r);
   697     }
   699     _status=0;
   700   abort:
   701     if(_status){
   702       nr_ice_candidate_destroy(&pcand);
   703       assert(*error != 0);
   704       if(r!=R_NO_MEMORY) assert(*error != 500);
   705     }
   706     return(_status);
   707   }
   709 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)
   710   {
   711     nr_ice_component *comp=cb_arg;
   712     nr_transport_addr local_addr;
   713     int r,_status;
   715     /* Find the candidate pair that this maps to */
   716     if(r=nr_socket_getaddr(sock,&local_addr)) {
   717       *error=500;
   718       ABORT(r);
   719     }
   721     if (r=nr_ice_component_process_incoming_check(comp, &local_addr, req, error))
   722       ABORT(r);
   724     _status=0;
   725  abort:
   726     return(_status);
   727   }
   729 int nr_ice_component_service_pre_answer_requests(nr_ice_peer_ctx *pctx, nr_ice_component *pcomp, char *username, int *serviced)
   730   {
   731     nr_ice_pre_answer_request *r1,*r2;
   732     nr_ice_component *comp = pcomp->local_component;
   733     int r,_status;
   735     if (serviced)
   736       *serviced = 0;
   738     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);
   740     STAILQ_FOREACH_SAFE(r1, &comp->pre_answer_reqs, entry, r2) {
   741       if (!strcmp(r1->username, username)) {
   742         int error = 0;
   744         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);
   745         r = nr_ice_component_process_incoming_check(pcomp, &r1->local_addr, &r1->req, &error);
   746         if (r) {
   747           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);
   748         }
   749         (*serviced)++;
   750         STAILQ_REMOVE(&comp->pre_answer_reqs,r1,nr_ice_pre_answer_request_, entry);
   751         nr_ice_pre_answer_request_destroy(&r1);
   752       }
   753     }
   755     _status=0;
   756      return(_status);
   757   }
   759 int nr_ice_component_pair_candidate(nr_ice_peer_ctx *pctx, nr_ice_component *pcomp, nr_ice_candidate *lcand, int pair_all_remote)
   760   {
   761     int r, _status;
   762     nr_ice_candidate *pcand;
   763     nr_ice_cand_pair *pair=0;
   764     char codeword[5];
   766     nr_ice_compute_codeword(lcand->label,strlen(lcand->label),codeword);
   767     r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/CAND(%s): Pairing local candidate %s",pctx->label,codeword,lcand->label);
   769     switch(lcand->type){
   770       case HOST:
   771         break;
   772       case SERVER_REFLEXIVE:
   773       case PEER_REFLEXIVE:
   774         /* Don't actually pair these candidates */
   775         goto done;
   776         break;
   777       case RELAYED:
   778         break;
   779       default:
   780         assert(0);
   781         ABORT(R_INTERNAL);
   782         break;
   783     }
   785     pcand=TAILQ_FIRST(&pcomp->candidates);
   786     while(pcand){
   787       /*
   788         Two modes, depending on |pair_all_remote|
   790         1. Pair remote candidates which have not been paired
   791            (used in initial pairing or in processing the other side's
   792            trickle candidates).
   793         2. Pair any remote candidate (used when processing our own
   794            trickle candidates).
   795       */
   796       if (pair_all_remote || (pcand->state == NR_ICE_CAND_PEER_CANDIDATE_UNPAIRED)) {
   797         /* If we are pairing our own trickle candidates, the remote candidate should
   798            all be paired */
   799         if (pair_all_remote)
   800           assert (pcand->state == NR_ICE_CAND_PEER_CANDIDATE_PAIRED);
   802         nr_ice_compute_codeword(pcand->label,strlen(pcand->label),codeword);
   803         r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/CAND(%s): Pairing with peer candidate %s", pctx->label, codeword, pcand->label);
   805         if(r=nr_ice_candidate_pair_create(pctx,lcand,pcand,&pair))
   806           ABORT(r);
   808         if(r=nr_ice_component_insert_pair(pcomp, pair))
   809           ABORT(r);
   810       }
   812       pcand=TAILQ_NEXT(pcand,entry_comp);
   813     }
   815    done:
   816     _status = 0;
   817    abort:
   818     return(_status);
   819   }
   821 int nr_ice_component_pair_candidates(nr_ice_peer_ctx *pctx, nr_ice_component *lcomp,nr_ice_component *pcomp)
   822   {
   823     nr_ice_candidate *lcand, *pcand;
   824     nr_ice_socket *isock;
   825     int r,_status;
   827     r_log(LOG_ICE,LOG_DEBUG,"Pairing candidates======");
   829     /* Create the candidate pairs */
   830     lcand=TAILQ_FIRST(&lcomp->candidates);
   831     while(lcand){
   832       if (lcand->state == NR_ICE_CAND_STATE_INITIALIZED) {
   833         if ((r = nr_ice_component_pair_candidate(pctx, pcomp, lcand, 0)))
   834           ABORT(r);
   835       }
   837       lcand=TAILQ_NEXT(lcand,entry_comp);
   838     }
   840     /* Mark all peer candidates as paired */
   841     pcand=TAILQ_FIRST(&pcomp->candidates);
   842     while(pcand){
   843       pcand->state = NR_ICE_CAND_PEER_CANDIDATE_PAIRED;
   845       pcand=TAILQ_NEXT(pcand,entry_comp);
   847     }
   849     /* Now register the STUN server callback for this component.
   850        Note that this is a per-component CB so we only need to
   851        do this once.
   852     */
   853     if (pcomp->state != NR_ICE_COMPONENT_RUNNING) {
   854       isock=STAILQ_FIRST(&lcomp->sockets);
   855       while(isock){
   856         if(r=nr_stun_server_add_client(isock->stun_server,pctx->label,
   857           pcomp->stream->r2l_user,&pcomp->stream->r2l_pass,nr_ice_component_stun_server_cb,pcomp)) {
   858             ABORT(r);
   859         }
   860         isock=STAILQ_NEXT(isock,entry);
   861       }
   862     }
   864     pcomp->state = NR_ICE_COMPONENT_RUNNING;
   866     _status=0;
   867   abort:
   868     return(_status);
   869   }
   871 /* Fires when we have an incoming candidate that doesn't correspond to an existing
   872    remote peer. This is either pre-answer or just spurious. Store it in the
   873    component for use when we see the actual answer, at which point we need
   874    to do the procedures from S 7.2.1 in nr_ice_component_stun_server_cb.
   875  */
   876 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)
   877   {
   878     int r, _status;
   879     nr_ice_component *comp = (nr_ice_component *)cb_arg;
   880     nr_ice_pre_answer_request *par = 0;
   881     r_log(LOG_ICE,LOG_DEBUG,"ICE(%s)/STREAM(%s)/COMP(%d): Received STUN request pre-answer from %s",
   882           comp->ctx->label, comp->stream->label, comp->component_id, req->src_addr.as_string);
   884     if (r=nr_ice_pre_answer_request_create(sock, req, &par))
   885       ABORT(r);
   887     *dont_free = 1;
   888     STAILQ_INSERT_TAIL(&comp->pre_answer_reqs, par, entry);
   890     _status=0;
   891  abort:
   892     return 0;
   893   }
   895 int nr_ice_component_nominated_pair(nr_ice_component *comp, nr_ice_cand_pair *pair)
   896   {
   897     int r,_status;
   898     int fire_cb=0;
   899     nr_ice_cand_pair *p2;
   901     if(!comp->nominated)
   902       fire_cb=1;
   904     /* Are we changing what the nominated pair is? */
   905     if(comp->nominated){
   906       if(comp->nominated->priority > pair->priority)
   907         return(0);
   908       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);
   909     }
   911     /* Set the new nominated pair */
   912     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);
   913     comp->state=NR_ICE_COMPONENT_NOMINATED;
   914     comp->nominated=pair;
   915     comp->active=pair;
   917     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);
   919     /* Cancel checks in WAITING and FROZEN per ICE S 8.1.2 */
   920     p2=TAILQ_FIRST(&comp->stream->check_list);
   921     while(p2){
   922       if((p2 != pair) &&
   923          (p2->remote->component->component_id == comp->component_id) &&
   924          ((p2->state == NR_ICE_PAIR_STATE_FROZEN) ||
   925 	  (p2->state == NR_ICE_PAIR_STATE_WAITING))) {
   926         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);
   928         if(r=nr_ice_candidate_pair_cancel(pair->pctx,p2))
   929           ABORT(r);
   930       }
   932       p2=TAILQ_NEXT(p2,entry);
   933     }
   934     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);
   936     if(r=nr_ice_media_stream_component_nominated(comp->stream,comp))
   937       ABORT(r);
   939     _status=0;
   940   abort:
   941     return(_status);
   942   }
   944 int nr_ice_component_failed_pair(nr_ice_component *comp, nr_ice_cand_pair *pair)
   945   {
   946     int r,_status;
   947     nr_ice_cand_pair *p2;
   949     assert(pair->state == NR_ICE_PAIR_STATE_FAILED);
   951     p2=TAILQ_FIRST(&comp->stream->check_list);
   952     while(p2){
   953       if(comp->component_id==p2->local->component_id){
   954         switch(p2->state){
   955         case NR_ICE_PAIR_STATE_FROZEN:
   956         case NR_ICE_PAIR_STATE_WAITING:
   957         case NR_ICE_PAIR_STATE_IN_PROGRESS:
   958             /* answer component status cannot be determined yet */
   959             goto done;
   960             break;
   961         case NR_ICE_PAIR_STATE_SUCCEEDED:
   962             /* the component will succeed */
   963             goto done;
   964             break;
   965         case NR_ICE_PAIR_STATE_FAILED:
   966         case NR_ICE_PAIR_STATE_CANCELLED:
   967             /* states that will never be recovered from */
   968             break;
   969         default:
   970             assert(0);
   971             break;
   972         }
   973       }
   975       p2=TAILQ_NEXT(p2,entry);
   976     }
   978     /* all the pairs in the component are in their final states with
   979      * none of them being SUCCEEDED, so the component fails entirely,
   980      * tell the media stream that this component has failed */
   982     if(r=nr_ice_media_stream_component_failed(comp->stream,comp))
   983       ABORT(r);
   985   done:
   986     _status=0;
   987   abort:
   988     return(_status);
   989   }
   991 int nr_ice_component_select_pair(nr_ice_peer_ctx *pctx, nr_ice_component *comp)
   992   {
   993     nr_ice_cand_pair **pairs=0;
   994     int ct=0;
   995     nr_ice_cand_pair *pair;
   996     int r,_status;
   998     /* Size the array */
   999     pair=TAILQ_FIRST(&comp->stream->check_list);
  1000     while(pair){
  1001       if (comp->component_id == pair->local->component_id)
  1002           ct++;
  1004       pair=TAILQ_NEXT(pair,entry);
  1007     /* Make and fill the array */
  1008     if(!(pairs=RCALLOC(sizeof(nr_ice_cand_pair *)*ct)))
  1009       ABORT(R_NO_MEMORY);
  1011     ct=0;
  1012     pair=TAILQ_FIRST(&comp->stream->check_list);
  1013     while(pair){
  1014       if (comp->component_id == pair->local->component_id)
  1015           pairs[ct++]=pair;
  1017       pair=TAILQ_NEXT(pair,entry);
  1020     if (pctx->handler) {
  1021       if(r=pctx->handler->vtbl->select_pair(pctx->handler->obj,
  1022         comp->stream,comp->component_id,pairs,ct))
  1023         ABORT(r);
  1026     _status=0;
  1027   abort:
  1028     RFREE(pairs);
  1029     return(_status);
  1033 static void nr_ice_component_keepalive_cb(NR_SOCKET s, int how, void *cb_arg)
  1035     nr_ice_component *comp=cb_arg;
  1036     UINT4 keepalive_timeout;
  1038     assert(comp->keepalive_ctx);
  1040     if(NR_reg_get_uint4(NR_ICE_REG_KEEPALIVE_TIMER,&keepalive_timeout)){
  1041       keepalive_timeout=15000; /* Default */
  1045     if(comp->keepalive_needed)
  1046       nr_stun_client_force_retransmit(comp->keepalive_ctx);
  1048     comp->keepalive_needed=1;
  1049     NR_ASYNC_TIMER_SET(keepalive_timeout,nr_ice_component_keepalive_cb,cb_arg,&comp->keepalive_timer);
  1053 /* Close the underlying sockets for everything but the nominated candidate */
  1054 int nr_ice_component_finalize(nr_ice_component *lcomp, nr_ice_component *rcomp)
  1056     nr_ice_socket *isock=0;
  1057     int r,_status;
  1058     nr_ice_socket *s1,*s2;
  1060     if(rcomp->state==NR_ICE_COMPONENT_NOMINATED){
  1061       assert(rcomp->active == rcomp->nominated);
  1062       isock=rcomp->nominated->local->isock;
  1065     STAILQ_FOREACH_SAFE(s1, &lcomp->sockets, entry, s2){
  1066       if(s1!=isock){
  1067         STAILQ_REMOVE(&lcomp->sockets,s1,nr_ice_socket_,entry);
  1068         nr_ice_socket_destroy(&s1);
  1072     /* Set up the keepalives for the chosen socket */
  1073     if(r=nr_stun_client_ctx_create("keepalive",rcomp->nominated->local->osock,
  1074       &rcomp->nominated->remote->addr,0,&rcomp->keepalive_ctx))
  1075       ABORT(r);
  1076     if(r=nr_stun_client_start(rcomp->keepalive_ctx,NR_STUN_CLIENT_MODE_KEEPALIVE,0,0))
  1077       ABORT(r);
  1078     nr_ice_component_keepalive_cb(0,0,rcomp);
  1081     _status=0;
  1082   abort:
  1084     return(_status);
  1088 int nr_ice_component_insert_pair(nr_ice_component *pcomp, nr_ice_cand_pair *pair)
  1090     int r,_status;
  1092     /* Pairs for peer reflexive are marked SUCCEEDED immediately */
  1093     if (pair->state != NR_ICE_PAIR_STATE_FROZEN &&
  1094         pair->state != NR_ICE_PAIR_STATE_SUCCEEDED){
  1095       assert(0);
  1096       ABORT(R_BAD_ARGS);
  1099     if(r=nr_ice_candidate_pair_insert(&pair->remote->stream->check_list,pair))
  1100       ABORT(r);
  1102     /* Make sure the check timer is running, if the stream was previously
  1103      * started. We will not start streams just because a pair was created. */
  1104     if(pair->remote->stream->ice_state == NR_ICE_MEDIA_STREAM_CHECKS_ACTIVE){
  1105       if(nr_ice_media_stream_start_checks(pair->remote->stream->pctx, pair->remote->stream)) {
  1106         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);
  1107         ABORT(R_INTERNAL);
  1111     _status=0;
  1112   abort:
  1113     return(_status);

mercurial