LCOV - code coverage report
Current view: top level - media/mtransport/third_party/nICEr/src/ice - ice_peer_ctx.c (source / functions) Hit Total Coverage
Test: output.info Lines: 0 387 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 27 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_peer_ctx.c,v 1.2 2008/04/28 17:59:01 ekr Exp $";
      36             : 
      37             : #include <string.h>
      38             : #include <assert.h>
      39             : #include <registry.h>
      40             : #include <nr_api.h>
      41             : #include "ice_ctx.h"
      42             : #include "ice_peer_ctx.h"
      43             : #include "ice_media_stream.h"
      44             : #include "ice_util.h"
      45             : #include "nr_crypto.h"
      46             : #include "async_timer.h"
      47             : #include "ice_reg.h"
      48             : 
      49             : static void nr_ice_peer_ctx_destroy_cb(NR_SOCKET s, int how, void *cb_arg);
      50             : static int nr_ice_peer_ctx_parse_stream_attributes_int(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, nr_ice_media_stream *pstream, char **attrs, int attr_ct);
      51             : static int nr_ice_ctx_parse_candidate(nr_ice_peer_ctx *pctx, nr_ice_media_stream *pstream, char *candidate);
      52             : static void nr_ice_peer_ctx_start_trickle_timer(nr_ice_peer_ctx *pctx);
      53             : 
      54           0 : int nr_ice_peer_ctx_create(nr_ice_ctx *ctx, nr_ice_handler *handler,char *label, nr_ice_peer_ctx **pctxp)
      55             :   {
      56             :     int r,_status;
      57           0 :     nr_ice_peer_ctx *pctx=0;
      58             : 
      59           0 :     if(!(pctx=RCALLOC(sizeof(nr_ice_peer_ctx))))
      60           0 :       ABORT(R_NO_MEMORY);
      61             : 
      62           0 :     pctx->state = NR_ICE_PEER_STATE_UNPAIRED;
      63             : 
      64           0 :     if(!(pctx->label=r_strdup(label)))
      65           0 :       ABORT(R_NO_MEMORY);
      66             : 
      67           0 :     pctx->ctx=ctx;
      68           0 :     pctx->handler=handler;
      69             : 
      70             :     /* Decide controlling vs. controlled */
      71           0 :     if(ctx->flags & NR_ICE_CTX_FLAGS_LITE){
      72           0 :       pctx->controlling=0;
      73             :     } else {
      74           0 :       pctx->controlling=1;
      75             :     }
      76           0 :     if(r=nr_crypto_random_bytes((UCHAR *)&pctx->tiebreaker,8))
      77           0 :       ABORT(r);
      78             : 
      79           0 :     STAILQ_INIT(&pctx->peer_streams);
      80             : 
      81           0 :     STAILQ_INSERT_TAIL(&ctx->peers,pctx,entry);
      82             : 
      83           0 :     *pctxp=pctx;
      84             : 
      85           0 :     _status = 0;
      86             :   abort:
      87           0 :     if(_status){
      88           0 :       nr_ice_peer_ctx_destroy_cb(0,0,pctx);
      89             :     }
      90           0 :     return(_status);
      91             :   }
      92             : 
      93             : 
      94             : 
      95           0 : int nr_ice_peer_ctx_parse_stream_attributes(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, char **attrs, int attr_ct)
      96             :   {
      97           0 :     nr_ice_media_stream *pstream=0;
      98             :     nr_ice_component *comp,*comp2;
      99             :     char *lufrag,*rufrag;
     100             :     char *lpwd,*rpwd;
     101             :     int r,_status;
     102             : 
     103             :     /*
     104             :       Note: use component_ct from our own stream since components other
     105             :       than this offered by the other side are unusable */
     106           0 :     if(r=nr_ice_media_stream_create(pctx->ctx,stream->label,stream->component_ct,&pstream))
     107           0 :       ABORT(r);
     108             : 
     109             :     /* Match up the local and remote components */
     110           0 :     comp=STAILQ_FIRST(&stream->components);
     111           0 :     comp2=STAILQ_FIRST(&pstream->components);
     112           0 :     while(comp){
     113           0 :       comp2->local_component=comp;
     114             : 
     115           0 :       comp=STAILQ_NEXT(comp,entry);
     116           0 :       comp2=STAILQ_NEXT(comp2,entry);
     117             :     }
     118             : 
     119           0 :     pstream->local_stream=stream;
     120           0 :     pstream->pctx=pctx;
     121             : 
     122           0 :     if (r=nr_ice_peer_ctx_parse_stream_attributes_int(pctx,stream,pstream,attrs,attr_ct))
     123           0 :       ABORT(r);
     124             : 
     125             :     /* Now that we have the ufrag and password, compute all the username/password
     126             :        pairs */
     127           0 :     lufrag=stream->ufrag?stream->ufrag:pctx->ctx->ufrag;
     128           0 :     lpwd=stream->pwd?stream->pwd:pctx->ctx->pwd;
     129           0 :     assert(lufrag);
     130           0 :     assert(lpwd);
     131           0 :     rufrag=pstream->ufrag?pstream->ufrag:pctx->peer_ufrag;
     132           0 :     rpwd=pstream->pwd?pstream->pwd:pctx->peer_pwd;
     133           0 :     if (!rufrag || !rpwd)
     134           0 :       ABORT(R_BAD_DATA);
     135             : 
     136           0 :     if(r=nr_concat_strings(&pstream->r2l_user,lufrag,":",rufrag,NULL))
     137           0 :       ABORT(r);
     138           0 :     if(r=nr_concat_strings(&pstream->l2r_user,rufrag,":",lufrag,NULL))
     139           0 :       ABORT(r);
     140           0 :     if(r=r_data_make(&pstream->r2l_pass, (UCHAR *)lpwd, strlen(lpwd)))
     141           0 :       ABORT(r);
     142           0 :     if(r=r_data_make(&pstream->l2r_pass, (UCHAR *)rpwd, strlen(rpwd)))
     143           0 :       ABORT(r);
     144             : 
     145           0 :     STAILQ_INSERT_TAIL(&pctx->peer_streams,pstream,entry);
     146             : 
     147           0 :     _status=0;
     148             :   abort:
     149           0 :     return(_status);
     150             :   }
     151             : 
     152           0 : static int nr_ice_peer_ctx_parse_stream_attributes_int(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, nr_ice_media_stream *pstream, char **attrs, int attr_ct)
     153             :   {
     154             :     int r;
     155             :     int i;
     156             : 
     157           0 :     for(i=0;i<attr_ct;i++){
     158           0 :       if(!strncmp(attrs[i],"ice-",4)){
     159           0 :         if(r=nr_ice_peer_ctx_parse_media_stream_attribute(pctx,pstream,attrs[i])) {
     160           0 :           r_log(LOG_ICE,LOG_WARNING,"ICE(%s): peer (%s) specified bogus ICE attribute",pctx->ctx->label,pctx->label);
     161           0 :           continue;
     162             :         }
     163             :       }
     164           0 :       else if (!strncmp(attrs[i],"candidate",9)){
     165           0 :         if(r=nr_ice_ctx_parse_candidate(pctx,pstream,attrs[i])) {
     166           0 :           r_log(LOG_ICE,LOG_WARNING,"ICE(%s): peer (%s) specified bogus candidate",pctx->ctx->label,pctx->label);
     167           0 :           continue;
     168             :         }
     169             :       }
     170             :       else {
     171           0 :         r_log(LOG_ICE,LOG_WARNING,"ICE(%s): peer (%s) specified bogus attribute: %s",pctx->ctx->label,pctx->label,attrs[i]);
     172             :       }
     173             :     }
     174             : 
     175             :     /* Doesn't fail because we just skip errors */
     176           0 :     return(0);
     177             :   }
     178             : 
     179           0 : static int nr_ice_ctx_parse_candidate(nr_ice_peer_ctx *pctx, nr_ice_media_stream *pstream, char *candidate)
     180             :   {
     181           0 :     nr_ice_candidate *cand=0;
     182             :     nr_ice_component *comp;
     183             :     int j;
     184             :     int r, _status;
     185             : 
     186           0 :     if(r=nr_ice_peer_candidate_from_attribute(pctx->ctx,candidate,pstream,&cand))
     187           0 :       ABORT(r);
     188           0 :     if(cand->component_id-1>=pstream->component_ct){
     189           0 :       r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) specified too many components",pctx->ctx->label,pctx->label);
     190           0 :       ABORT(R_BAD_DATA);
     191             :     }
     192             : 
     193             :     /* Not the fastest way to find a component, but it's what we got */
     194           0 :     j=1;
     195           0 :     for(comp=STAILQ_FIRST(&pstream->components);comp;comp=STAILQ_NEXT(comp,entry)){
     196           0 :       if(j==cand->component_id)
     197           0 :         break;
     198             : 
     199           0 :       j++;
     200             :     }
     201             : 
     202           0 :     if(!comp){
     203           0 :       r_log(LOG_ICE,LOG_WARNING,"Peer answered with more components than we offered");
     204           0 :       ABORT(R_BAD_DATA);
     205             :     }
     206             : 
     207           0 :     if (comp->state == NR_ICE_COMPONENT_DISABLED) {
     208           0 :       r_log(LOG_ICE,LOG_WARNING,"Peer offered candidates for disabled remote component");
     209           0 :       ABORT(R_BAD_DATA);
     210             :     }
     211           0 :     if (comp->local_component->state == NR_ICE_COMPONENT_DISABLED) {
     212           0 :       r_log(LOG_ICE,LOG_WARNING,"Peer offered candidates for disabled local component");
     213           0 :       ABORT(R_BAD_DATA);
     214             :     }
     215             : 
     216           0 :     cand->component=comp;
     217             : 
     218           0 :     TAILQ_INSERT_TAIL(&comp->candidates,cand,entry_comp);
     219             : 
     220           0 :     r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/CAND(%s): creating peer candidate",
     221           0 :       pctx->label,cand->label);
     222             : 
     223           0 :     _status=0;
     224             :  abort:
     225           0 :     if (_status) {
     226           0 :       nr_ice_candidate_destroy(&cand);
     227             :     }
     228           0 :     return(_status);
     229             :   }
     230             : 
     231           0 : int nr_ice_peer_ctx_find_pstream(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, nr_ice_media_stream **pstreamp)
     232             :   {
     233             :     int _status;
     234             :     nr_ice_media_stream *pstream;
     235             : 
     236             :     /* Because we don't have forward pointers, iterate through all the
     237             :        peer streams to find one that matches us */
     238           0 :      pstream=STAILQ_FIRST(&pctx->peer_streams);
     239           0 :      while(pstream) {
     240           0 :        if (pstream->local_stream == stream)
     241           0 :          break;
     242             : 
     243           0 :        pstream = STAILQ_NEXT(pstream, entry);
     244             :      }
     245           0 :      if (!pstream) {
     246           0 :        r_log(LOG_ICE,LOG_WARNING,"ICE(%s): peer (%s) has no stream matching stream %s",pctx->ctx->label,pctx->label,stream->label);
     247           0 :        ABORT(R_NOT_FOUND);
     248             :      }
     249             : 
     250           0 :     *pstreamp = pstream;
     251             : 
     252           0 :     _status=0;
     253             :  abort:
     254           0 :     return(_status);
     255             :   }
     256             : 
     257           0 : int nr_ice_peer_ctx_remove_pstream(nr_ice_peer_ctx *pctx, nr_ice_media_stream **pstreamp)
     258             :   {
     259             :     int r,_status;
     260             : 
     261           0 :     STAILQ_REMOVE(&pctx->peer_streams,*pstreamp,nr_ice_media_stream_,entry);
     262             : 
     263           0 :     if(r=nr_ice_media_stream_destroy(pstreamp)) {
     264           0 :       ABORT(r);
     265             :     }
     266             : 
     267           0 :     _status=0;
     268             :  abort:
     269           0 :     return(_status);
     270             :   }
     271             : 
     272           0 : int nr_ice_peer_ctx_parse_trickle_candidate(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, char *candidate)
     273             :   {
     274             :     nr_ice_media_stream *pstream;
     275             :     int r,_status;
     276           0 :     int needs_pairing = 0;
     277             : 
     278           0 :     r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): peer (%s) parsing trickle ICE candidate %s",pctx->ctx->label,pctx->label,candidate);
     279           0 :     r = nr_ice_peer_ctx_find_pstream(pctx, stream, &pstream);
     280           0 :     if (r)
     281           0 :       ABORT(r);
     282             : 
     283           0 :     switch(pstream->ice_state) {
     284             :       case NR_ICE_MEDIA_STREAM_UNPAIRED:
     285           0 :         break;
     286             :       case NR_ICE_MEDIA_STREAM_CHECKS_FROZEN:
     287             :       case NR_ICE_MEDIA_STREAM_CHECKS_ACTIVE:
     288           0 :         needs_pairing = 1;
     289           0 :         break;
     290             :       default:
     291           0 :         r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s), stream(%s) tried to trickle ICE in inappropriate state %d",pctx->ctx->label,pctx->label,stream->label,pstream->ice_state);
     292           0 :         ABORT(R_ALREADY);
     293             :         break;
     294             :     }
     295             : 
     296           0 :     if(r=nr_ice_ctx_parse_candidate(pctx,pstream,candidate)){
     297           0 :       ABORT(r);
     298             :     }
     299             : 
     300             :     /* If ICE is running (i.e., we are in FROZEN or ACTIVE states)
     301             :        then we need to pair this new candidate. For now we
     302             :        just re-pair the stream which is inefficient but still
     303             :        fine because we suppress duplicate pairing */
     304           0 :     if (needs_pairing) {
     305           0 :       if(r=nr_ice_media_stream_pair_candidates(pctx, stream, pstream)) {
     306           0 :         r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s), stream(%s) failed to pair trickle ICE candidates",pctx->ctx->label,pctx->label,stream->label);
     307           0 :         ABORT(r);
     308             :       }
     309             : 
     310             :       /* Start the remote trickle grace timeout if it hasn't been started by
     311             :          another trickled candidate or from the SDP. */
     312           0 :       if (!pctx->trickle_grace_period_timer) {
     313           0 :         nr_ice_peer_ctx_start_trickle_timer(pctx);
     314             :       }
     315             : 
     316             :       /* Start checks if this stream is not checking yet or if it has checked
     317             :          all the available candidates but not had a completed check for all
     318             :          components.
     319             : 
     320             :          Note that this is not compliant with RFC 5245, but consistent with
     321             :          the libjingle trickle ICE behavior. Note that we will not restart
     322             :          checks if either (a) the stream has failed or (b) all components
     323             :          have a successful pair because the switch statement above jumps
     324             :          will in both states.
     325             : 
     326             :          TODO(ekr@rtfm.com): restart checks.
     327             :          TODO(ekr@rtfm.com): update when the trickle ICE RFC is published
     328             :       */
     329           0 :       if (!pstream->timer) {
     330           0 :         if(r=nr_ice_media_stream_start_checks(pctx, pstream)) {
     331           0 :           r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s), stream(%s) failed to start checks",pctx->ctx->label,pctx->label,stream->label);
     332           0 :           ABORT(r);
     333             :         }
     334             :       }
     335             :     }
     336             : 
     337           0 :     _status=0;
     338             :  abort:
     339           0 :     return(_status);
     340             : 
     341             :   }
     342             : 
     343             : 
     344           0 : static void nr_ice_peer_ctx_trickle_wait_cb(NR_SOCKET s, int how, void *cb_arg)
     345             :   {
     346           0 :     nr_ice_peer_ctx *pctx=cb_arg;
     347             :     nr_ice_media_stream *stream;
     348             :     nr_ice_component *comp;
     349             : 
     350           0 :     pctx->trickle_grace_period_timer=0;
     351             : 
     352           0 :     r_log(LOG_ICE,LOG_INFO,"ICE(%s): peer (%s) Trickle grace period is over; marking every component with only failed pairs as failed.",pctx->ctx->label,pctx->label);
     353             : 
     354           0 :     stream=STAILQ_FIRST(&pctx->peer_streams);
     355           0 :     while(stream){
     356           0 :       comp=STAILQ_FIRST(&stream->components);
     357           0 :       while(comp){
     358           0 :         nr_ice_component_check_if_failed(comp);
     359           0 :         comp=STAILQ_NEXT(comp,entry);
     360             :       }
     361           0 :       stream=STAILQ_NEXT(stream,entry);
     362             :     }
     363           0 :   }
     364             : 
     365           0 : static void nr_ice_peer_ctx_start_trickle_timer(nr_ice_peer_ctx *pctx)
     366             :   {
     367           0 :     UINT4 grace_period_timeout=0;
     368             : 
     369           0 :     if(pctx->trickle_grace_period_timer) {
     370           0 :       NR_async_timer_cancel(pctx->trickle_grace_period_timer);
     371           0 :       pctx->trickle_grace_period_timer=0;
     372             :     }
     373             : 
     374           0 :     NR_reg_get_uint4(NR_ICE_REG_TRICKLE_GRACE_PERIOD,&grace_period_timeout);
     375             : 
     376           0 :     if (grace_period_timeout) {
     377             :       /* If we're doing trickle, we need to allow a grace period for new
     378             :        * trickle candidates to arrive in case the pairs we have fail quickly. */
     379           0 :        NR_ASYNC_TIMER_SET(grace_period_timeout,nr_ice_peer_ctx_trickle_wait_cb,pctx,&pctx->trickle_grace_period_timer);
     380             :     }
     381           0 :   }
     382             : 
     383           0 : int nr_ice_peer_ctx_pair_candidates(nr_ice_peer_ctx *pctx)
     384             :   {
     385             :     nr_ice_media_stream *stream;
     386             :     int r,_status;
     387             : 
     388           0 :     if(pctx->peer_lite && !pctx->controlling) {
     389           0 :       if(pctx->ctx->flags & NR_ICE_CTX_FLAGS_LITE){
     390           0 :         r_log(LOG_ICE,LOG_ERR,"Both sides are ICE-Lite");
     391           0 :         ABORT(R_BAD_DATA);
     392             :       }
     393           0 :       nr_ice_peer_ctx_switch_controlling_role(pctx);
     394             :     }
     395             : 
     396           0 :     r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): peer (%s) pairing candidates",pctx->ctx->label,pctx->label);
     397             : 
     398           0 :     if(STAILQ_EMPTY(&pctx->peer_streams)) {
     399           0 :         r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) received no media stream attributes",pctx->ctx->label,pctx->label);
     400           0 :         ABORT(R_FAILED);
     401             :     }
     402             : 
     403             :     /* Set this first; if we fail partway through, we do not want to end
     404             :      * up in UNPAIRED after creating some pairs. */
     405           0 :     pctx->state = NR_ICE_PEER_STATE_PAIRED;
     406             : 
     407           0 :     stream=STAILQ_FIRST(&pctx->peer_streams);
     408           0 :     while(stream){
     409           0 :       if(r=nr_ice_media_stream_pair_candidates(pctx, stream->local_stream,
     410             :         stream))
     411           0 :         ABORT(r);
     412             : 
     413           0 :       stream=STAILQ_NEXT(stream,entry);
     414             :     }
     415             : 
     416             : 
     417           0 :     _status=0;
     418             :   abort:
     419           0 :     return(_status);
     420             :   }
     421             : 
     422             : 
     423           0 : int nr_ice_peer_ctx_pair_new_trickle_candidate(nr_ice_ctx *ctx, nr_ice_peer_ctx *pctx, nr_ice_candidate *cand)
     424             :   {
     425             :     int r, _status;
     426             :     nr_ice_media_stream *pstream;
     427             : 
     428           0 :     r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) pairing local trickle ICE candidate %s",pctx->ctx->label,pctx->label,cand->label);
     429           0 :     if ((r = nr_ice_peer_ctx_find_pstream(pctx, cand->stream, &pstream)))
     430           0 :       ABORT(r);
     431             : 
     432           0 :     if ((r = nr_ice_media_stream_pair_new_trickle_candidate(pctx, pstream, cand)))
     433           0 :       ABORT(r);
     434             : 
     435             :     /* Start the remote trickle grace timeout if it hasn't been started
     436             :        already. */
     437           0 :     if (!pctx->trickle_grace_period_timer) {
     438           0 :       nr_ice_peer_ctx_start_trickle_timer(pctx);
     439             :     }
     440             : 
     441           0 :     _status=0;
     442             :  abort:
     443           0 :     return _status;
     444             :   }
     445             : 
     446           0 : int nr_ice_peer_ctx_disable_component(nr_ice_peer_ctx *pctx, nr_ice_media_stream *lstream, int component_id)
     447             :   {
     448             :     int r, _status;
     449             :     nr_ice_media_stream *pstream;
     450             :     nr_ice_component *component;
     451             : 
     452           0 :     if ((r=nr_ice_peer_ctx_find_pstream(pctx, lstream, &pstream)))
     453           0 :       ABORT(r);
     454             : 
     455             :     /* We shouldn't be calling this after we have started pairing */
     456           0 :     if (pstream->ice_state != NR_ICE_MEDIA_STREAM_UNPAIRED)
     457           0 :       ABORT(R_FAILED);
     458             : 
     459           0 :     if ((r=nr_ice_media_stream_find_component(pstream, component_id,
     460             :                                               &component)))
     461           0 :       ABORT(r);
     462             : 
     463           0 :     component->state = NR_ICE_COMPONENT_DISABLED;
     464             : 
     465           0 :     _status=0;
     466             :  abort:
     467           0 :     return(_status);
     468             :   }
     469             : 
     470           0 : static void nr_ice_peer_ctx_destroy_cb(NR_SOCKET s, int how, void *cb_arg)
     471             :   {
     472           0 :     nr_ice_peer_ctx *pctx=cb_arg;
     473             :     nr_ice_media_stream *str1,*str2;
     474             : 
     475           0 :     NR_async_timer_cancel(pctx->connected_cb_timer);
     476           0 :     RFREE(pctx->label);
     477           0 :     RFREE(pctx->peer_ufrag);
     478           0 :     RFREE(pctx->peer_pwd);
     479             : 
     480           0 :     STAILQ_FOREACH_SAFE(str1, &pctx->peer_streams, entry, str2){
     481           0 :       STAILQ_REMOVE(&pctx->peer_streams,str1,nr_ice_media_stream_,entry);
     482           0 :       nr_ice_media_stream_destroy(&str1);
     483             :     }
     484           0 :     assert(pctx->ctx);
     485           0 :     if (pctx->ctx)
     486           0 :       STAILQ_REMOVE(&pctx->ctx->peers, pctx, nr_ice_peer_ctx_, entry);
     487             : 
     488           0 :     if(pctx->trickle_grace_period_timer) {
     489           0 :       NR_async_timer_cancel(pctx->trickle_grace_period_timer);
     490           0 :       pctx->trickle_grace_period_timer=0;
     491             :     }
     492             : 
     493           0 :     RFREE(pctx);
     494           0 :   }
     495             : 
     496           0 : int nr_ice_peer_ctx_destroy(nr_ice_peer_ctx **pctxp)
     497             :   {
     498             : 
     499           0 :     if(!pctxp || !*pctxp)
     500           0 :       return(0);
     501             : 
     502             :     /* Stop calling the handler */
     503           0 :     (*pctxp)->handler = 0;
     504             : 
     505           0 :     NR_ASYNC_SCHEDULE(nr_ice_peer_ctx_destroy_cb,*pctxp);
     506             : 
     507           0 :     *pctxp=0;
     508             : 
     509           0 :     return(0);
     510             :   }
     511             : 
     512             : 
     513             : /* Start the checks for the first media stream (S 5.7)
     514             :    The rest remain FROZEN */
     515           0 : int nr_ice_peer_ctx_start_checks(nr_ice_peer_ctx *pctx)
     516             :   {
     517           0 :     return nr_ice_peer_ctx_start_checks2(pctx, 0);
     518             :   }
     519             : 
     520             : /* Start checks for some media stream.
     521             : 
     522             :    If allow_non_first == 0, then we only look at the first stream,
     523             :    which is 5245-complaint.
     524             : 
     525             :    If allow_non_first == 1 then we find the first non-empty stream
     526             :    This is not compliant with RFC 5245 but is necessary to make trickle ICE
     527             :    work plausibly
     528             : */
     529           0 : int nr_ice_peer_ctx_start_checks2(nr_ice_peer_ctx *pctx, int allow_non_first)
     530             :   {
     531             :     int r,_status;
     532             :     nr_ice_media_stream *stream;
     533           0 :     int started = 0;
     534             : 
     535             :     /* Might have added some streams */
     536           0 :     pctx->reported_connected = 0;
     537           0 :     NR_async_timer_cancel(pctx->connected_cb_timer);
     538           0 :     pctx->connected_cb_timer = 0;
     539           0 :     pctx->checks_started = 0;
     540             : 
     541           0 :     if((r=nr_ice_peer_ctx_check_if_connected(pctx))) {
     542           0 :       r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) initial connected check failed",pctx->ctx->label,pctx->label);
     543           0 :       ABORT(r);
     544             :     }
     545             : 
     546           0 :     if (pctx->reported_connected) {
     547           0 :       r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) in %s all streams were done",pctx->ctx->label,pctx->label,__FUNCTION__);
     548           0 :       return (0);
     549             :     }
     550             : 
     551           0 :     stream=STAILQ_FIRST(&pctx->peer_streams);
     552           0 :     if(!stream)
     553           0 :       ABORT(R_FAILED);
     554             : 
     555           0 :     while (stream) {
     556           0 :       assert(stream->ice_state != NR_ICE_MEDIA_STREAM_UNPAIRED);
     557             : 
     558           0 :       if (stream->ice_state == NR_ICE_MEDIA_STREAM_CHECKS_FROZEN) {
     559           0 :         if(!TAILQ_EMPTY(&stream->check_list))
     560           0 :           break;
     561             : 
     562           0 :         if(!allow_non_first){
     563             :           /* This test applies if:
     564             : 
     565             :              1. allow_non_first is 0 (i.e., non-trickle ICE)
     566             :              2. the first stream has an empty check list.
     567             : 
     568             :              But in the non-trickle ICE case, the other side should have provided
     569             :              some candidates or ICE is pretty much not going to work and we're
     570             :              just going to fail. Hence R_FAILED as opposed to R_NOT_FOUND and
     571             :              immediate termination here.
     572             :           */
     573           0 :           r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) first stream has empty check list",pctx->ctx->label,pctx->label);
     574           0 :           ABORT(R_FAILED);
     575             :         }
     576             :       }
     577             : 
     578           0 :       stream=STAILQ_NEXT(stream, entry);
     579             :     }
     580             : 
     581           0 :     if (!stream) {
     582             :       /*
     583             :          We fail above if we aren't doing trickle, and this is not all that
     584             :          unusual in the trickle case.
     585             :        */
     586           0 :       r_log(LOG_ICE,LOG_NOTICE,"ICE(%s): peer (%s) no streams with non-empty check lists",pctx->ctx->label,pctx->label);
     587             :     }
     588           0 :     else if (stream->ice_state == NR_ICE_MEDIA_STREAM_CHECKS_FROZEN) {
     589           0 :       if(r=nr_ice_media_stream_unfreeze_pairs(pctx,stream))
     590           0 :         ABORT(r);
     591           0 :       if(r=nr_ice_media_stream_start_checks(pctx,stream))
     592           0 :         ABORT(r);
     593           0 :       ++started;
     594             :     }
     595             : 
     596           0 :     stream=STAILQ_FIRST(&pctx->peer_streams);
     597           0 :     while (stream) {
     598           0 :       int serviced = 0;
     599           0 :       if (r=nr_ice_media_stream_service_pre_answer_requests(pctx, stream->local_stream, stream, &serviced))
     600           0 :         ABORT(r);
     601             : 
     602           0 :       if (serviced) {
     603           0 :         ++started;
     604             :       }
     605             :       else {
     606           0 :         r_log(LOG_ICE,LOG_NOTICE,"ICE(%s): peer (%s) no streams with pre-answer requests",pctx->ctx->label,pctx->label);
     607             :       }
     608             : 
     609             : 
     610           0 :       stream=STAILQ_NEXT(stream, entry);
     611             :     }
     612             : 
     613           0 :     if (!started) {
     614           0 :       r_log(LOG_ICE,LOG_NOTICE,"ICE(%s): peer (%s) no checks to start",pctx->ctx->label,pctx->label);
     615           0 :       ABORT(R_NOT_FOUND);
     616             :     }
     617             :     else {
     618             :       /* Start grace period timer for more remote trickle candidates. */
     619           0 :       nr_ice_peer_ctx_start_trickle_timer(pctx);
     620             :     }
     621             : 
     622           0 :     _status=0;
     623             :   abort:
     624           0 :     return(_status);
     625             :   }
     626             : 
     627           0 : void nr_ice_peer_ctx_stream_started_checks(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream)
     628             :   {
     629           0 :     if (!pctx->checks_started) {
     630           0 :       r_log(LOG_ICE,LOG_NOTICE,"ICE(%s): peer (%s) is now checking",pctx->ctx->label,pctx->label);
     631           0 :       pctx->checks_started = 1;
     632           0 :       if (pctx->handler && pctx->handler->vtbl->ice_checking) {
     633           0 :         pctx->handler->vtbl->ice_checking(pctx->handler->obj, pctx);
     634             :       }
     635             :     }
     636           0 :   }
     637             : 
     638             : #ifndef NDEBUG
     639           0 : int nr_ice_peer_ctx_dump_state(nr_ice_peer_ctx *pctx,FILE *out)
     640             :   {
     641             :     int r,_status;
     642             :     nr_ice_media_stream *stream;
     643             : 
     644           0 :     fprintf(out,"PEER %s STATE DUMP\n",pctx->label);
     645           0 :     fprintf(out,"==========================================\n");
     646           0 :     stream=STAILQ_FIRST(&pctx->peer_streams);
     647           0 :     while(stream){
     648           0 :       if(r=nr_ice_media_stream_dump_state(pctx,stream,out))
     649           0 :         ABORT(r);
     650             : 
     651           0 :       stream=STAILQ_NEXT(stream,entry);
     652             :     }
     653           0 :     fprintf(out,"==========================================\n");
     654             : 
     655           0 :     _status=0;
     656             :   abort:
     657           0 :     return(_status);
     658             :   }
     659             : #endif
     660             : 
     661           0 : void nr_ice_peer_ctx_refresh_consent_all_streams(nr_ice_peer_ctx *pctx)
     662             :   {
     663             :     nr_ice_media_stream *str;
     664             : 
     665           0 :     r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s): refreshing consent on all streams",pctx->label);
     666             : 
     667           0 :     str=STAILQ_FIRST(&pctx->peer_streams);
     668           0 :     while(str) {
     669           0 :       nr_ice_media_stream_refresh_consent_all(str);
     670           0 :       str=STAILQ_NEXT(str,entry);
     671             :     }
     672           0 :   }
     673             : 
     674           0 : void nr_ice_peer_ctx_disconnected(nr_ice_peer_ctx *pctx)
     675             :   {
     676           0 :     if (pctx->reported_connected &&
     677           0 :         pctx->handler &&
     678           0 :         pctx->handler->vtbl->ice_disconnected) {
     679           0 :       pctx->handler->vtbl->ice_disconnected(pctx->handler->obj, pctx);
     680             : 
     681           0 :       pctx->reported_connected = 0;
     682             :     }
     683           0 :   }
     684             : 
     685           0 : void nr_ice_peer_ctx_disconnect_all_streams(nr_ice_peer_ctx *pctx)
     686             :   {
     687             :     nr_ice_media_stream *str;
     688             : 
     689           0 :     r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s): disconnecting all streams",pctx->label);
     690             : 
     691           0 :     str=STAILQ_FIRST(&pctx->peer_streams);
     692           0 :     while(str) {
     693           0 :       nr_ice_media_stream_disconnect_all_components(str);
     694             : 
     695             :       /* The first stream to be disconnected will cause the peer ctx to signal
     696             :          the disconnect up. */
     697           0 :       nr_ice_media_stream_set_disconnected(str, NR_ICE_MEDIA_STREAM_DISCONNECTED);
     698             : 
     699           0 :       str=STAILQ_NEXT(str,entry);
     700             :     }
     701           0 :   }
     702             : 
     703           0 : void nr_ice_peer_ctx_connected(nr_ice_peer_ctx *pctx)
     704             :   {
     705             :     /* Fire the handler callback to say we're done */
     706           0 :     if (pctx->reported_connected &&
     707           0 :         pctx->handler &&
     708           0 :         pctx->handler->vtbl->ice_connected) {
     709           0 :       pctx->handler->vtbl->ice_connected(pctx->handler->obj, pctx);
     710             :     }
     711           0 :   }
     712             : 
     713           0 : static void nr_ice_peer_ctx_fire_connected(NR_SOCKET s, int how, void *cb_arg)
     714             :   {
     715           0 :     nr_ice_peer_ctx *pctx=cb_arg;
     716             : 
     717           0 :     pctx->connected_cb_timer=0;
     718             : 
     719           0 :     nr_ice_peer_ctx_connected(pctx);
     720           0 :   }
     721             : 
     722             : /* Examine all the streams to see if we're
     723             :    maybe miraculously connected */
     724           0 : int nr_ice_peer_ctx_check_if_connected(nr_ice_peer_ctx *pctx)
     725             :   {
     726             :     int _status;
     727             :     nr_ice_media_stream *str;
     728           0 :     int failed=0;
     729           0 :     int succeeded=0;
     730             : 
     731           0 :     str=STAILQ_FIRST(&pctx->peer_streams);
     732           0 :     while(str){
     733           0 :       if(str->ice_state==NR_ICE_MEDIA_STREAM_CHECKS_CONNECTED){
     734           0 :         succeeded++;
     735             :       }
     736           0 :       else if(str->ice_state==NR_ICE_MEDIA_STREAM_CHECKS_FAILED){
     737           0 :         failed++;
     738             :       }
     739             :       else{
     740           0 :         break;
     741             :       }
     742           0 :       str=STAILQ_NEXT(str,entry);
     743             :     }
     744             : 
     745           0 :     if(str)
     746           0 :       goto done;  /* Something isn't done */
     747             : 
     748             :     /* OK, we're finished, one way or another */
     749           0 :     r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s): all checks completed success=%d fail=%d",pctx->label,succeeded,failed);
     750             : 
     751             :     /* Schedule a connected notification for the first connected event.
     752             :        IMPORTANT: This is done in a callback because we expect destructors
     753             :        of various kinds to be fired from here */
     754           0 :     if (!pctx->reported_connected) {
     755           0 :       pctx->reported_connected = 1;
     756           0 :       assert(!pctx->connected_cb_timer);
     757           0 :       NR_ASYNC_TIMER_SET(0,nr_ice_peer_ctx_fire_connected,pctx,&pctx->connected_cb_timer);
     758             :     }
     759             : 
     760             :   done:
     761           0 :     _status=0;
     762           0 :     return(_status);
     763             :   }
     764             : 
     765             : 
     766             : /* Given a component in the main ICE ctx, find the relevant component in
     767             :    the peer_ctx */
     768           0 : int nr_ice_peer_ctx_find_component(nr_ice_peer_ctx *pctx, nr_ice_media_stream *str, int component_id, nr_ice_component **compp)
     769             :   {
     770             :     nr_ice_media_stream *pstr;
     771             :     int r,_status;
     772             : 
     773           0 :     pstr=STAILQ_FIRST(&pctx->peer_streams);
     774           0 :     while(pstr){
     775           0 :       if(pstr->local_stream==str)
     776           0 :         break;
     777             : 
     778           0 :       pstr=STAILQ_NEXT(pstr,entry);
     779             :     }
     780           0 :     if(!pstr)
     781           0 :       ABORT(R_BAD_ARGS);
     782             : 
     783           0 :     if(r=nr_ice_media_stream_find_component(pstr,component_id,compp))
     784           0 :       ABORT(r);
     785             : 
     786           0 :     _status=0;
     787             :   abort:
     788           0 :     return(_status);
     789             :   }
     790             : 
     791             : /*
     792             :    This packet may be for us.
     793             : 
     794             :    1. Find the matching peer component
     795             :    2. Examine the packet source address to see if it matches
     796             :    one of the peer candidates.
     797             :    3. Fire the relevant callback handler if there is a match
     798             : 
     799             :    Return 0 if match, R_REJECTED if no match, other errors
     800             :    if we can't even find the component or something like that.
     801             : */
     802             : 
     803           0 : int nr_ice_peer_ctx_deliver_packet_maybe(nr_ice_peer_ctx *pctx, nr_ice_component *comp, nr_transport_addr *source_addr, UCHAR *data, int len)
     804             :   {
     805             :     nr_ice_component *peer_comp;
     806             :     nr_ice_candidate *cand;
     807             :     int r,_status;
     808             : 
     809           0 :     if(r=nr_ice_peer_ctx_find_component(pctx, comp->stream, comp->component_id,
     810             :       &peer_comp))
     811           0 :       ABORT(r);
     812             : 
     813             :     /* OK, we've found the component, now look for matches */
     814           0 :     cand=TAILQ_FIRST(&peer_comp->candidates);
     815           0 :     while(cand){
     816           0 :       if(!nr_transport_addr_cmp(source_addr,&cand->addr,
     817             :         NR_TRANSPORT_ADDR_CMP_MODE_ALL))
     818           0 :         break;
     819             : 
     820           0 :       cand=TAILQ_NEXT(cand,entry_comp);
     821             :     }
     822             : 
     823           0 :     if(!cand)
     824           0 :       ABORT(R_REJECTED);
     825             : 
     826             :     // accumulate the received bytes for the active candidate pair
     827           0 :     if (peer_comp->active) {
     828           0 :       peer_comp->active->bytes_recvd += len;
     829           0 :       gettimeofday(&peer_comp->active->last_recvd, 0);
     830             :     }
     831             : 
     832             :     /* OK, there's a match. Call the handler */
     833             : 
     834           0 :     if (pctx->handler) {
     835           0 :       r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s): Delivering data", pctx->label);
     836             : 
     837           0 :       pctx->handler->vtbl->msg_recvd(pctx->handler->obj,
     838           0 :         pctx,comp->stream,comp->component_id,data,len);
     839             :     }
     840             : 
     841           0 :     _status=0;
     842             :   abort:
     843           0 :     return(_status);
     844             :   }
     845             : 
     846           0 : void nr_ice_peer_ctx_switch_controlling_role(nr_ice_peer_ctx *pctx)
     847             :   {
     848           0 :     int controlling = !(pctx->controlling);
     849           0 :     if(pctx->controlling_conflict_resolved) {
     850           0 :       r_log(LOG_ICE,LOG_WARNING,"ICE(%s): peer (%s) %s called more than once; "
     851             :             "this probably means the peer is confused. Not switching roles.",
     852           0 :             pctx->ctx->label,pctx->label,__FUNCTION__);
     853           0 :       return;
     854             :     }
     855             : 
     856           0 :     r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s): detected "
     857             :           "role conflict. Switching to %s",
     858             :           pctx->label,
     859             :           controlling ? "controlling" : "controlled");
     860             : 
     861           0 :     pctx->controlling = controlling;
     862           0 :     pctx->controlling_conflict_resolved = 1;
     863             : 
     864           0 :     if(pctx->state == NR_ICE_PEER_STATE_PAIRED) {
     865             :       /*  We have formed candidate pairs. We need to inform them. */
     866           0 :       nr_ice_media_stream *pstream=STAILQ_FIRST(&pctx->peer_streams);
     867           0 :       while(pstream) {
     868           0 :         nr_ice_media_stream_role_change(pstream);
     869           0 :         pstream = STAILQ_NEXT(pstream, entry);
     870             :       }
     871             :     }
     872             :   }
     873             : 

Generated by: LCOV version 1.13