LCOV - code coverage report
Current view: top level - media/mtransport/third_party/nICEr/src/ice - ice_candidate_pair.c (source / functions) Hit Total Coverage
Test: output.info Lines: 0 300 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 19 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_candidate_pair.c,v 1.2 2008/04/28 17:59:01 ekr Exp $";
      36             : 
      37             : #include <assert.h>
      38             : #include <string.h>
      39             : #include <nr_api.h>
      40             : #include "async_timer.h"
      41             : #include "ice_ctx.h"
      42             : #include "ice_util.h"
      43             : #include "ice_codeword.h"
      44             : #include "stun.h"
      45             : 
      46             : static char *nr_ice_cand_pair_states[]={"UNKNOWN","FROZEN","WAITING","IN_PROGRESS","FAILED","SUCCEEDED","CANCELLED"};
      47             : 
      48             : static void nr_ice_candidate_pair_restart_stun_role_change_cb(NR_SOCKET s, int how, void *cb_arg);
      49             : static void nr_ice_candidate_pair_compute_codeword(nr_ice_cand_pair *pair,
      50             :   nr_ice_candidate *lcand, nr_ice_candidate *rcand);
      51             : 
      52           0 : static void nr_ice_candidate_pair_set_priority(nr_ice_cand_pair *pair)
      53             :   {
      54             :     /* Priority computation S 5.7.2 */
      55             :     UINT8 controlling_priority, controlled_priority;
      56           0 :     if(pair->pctx->controlling)
      57             :     {
      58           0 :       controlling_priority=pair->local->priority;
      59           0 :       controlled_priority=pair->remote->priority;
      60             :     }
      61             :     else{
      62           0 :       controlling_priority=pair->remote->priority;
      63           0 :       controlled_priority=pair->local->priority;
      64             :     }
      65           0 :     pair->priority=(MIN(controlling_priority, controlled_priority))<<32 |
      66           0 :       (MAX(controlling_priority, controlled_priority))<<1 |
      67           0 :       (controlled_priority > controlling_priority?0:1);
      68           0 :   }
      69             : 
      70           0 : int nr_ice_candidate_pair_create(nr_ice_peer_ctx *pctx, nr_ice_candidate *lcand,nr_ice_candidate *rcand,nr_ice_cand_pair **pairp)
      71             :   {
      72           0 :     nr_ice_cand_pair *pair=0;
      73             :     int r,_status;
      74             :     UINT4 RTO;
      75             :     nr_ice_candidate tmpcand;
      76             :     UINT8 t_priority;
      77             : 
      78           0 :     if(!(pair=RCALLOC(sizeof(nr_ice_cand_pair))))
      79           0 :       ABORT(R_NO_MEMORY);
      80             : 
      81           0 :     pair->pctx=pctx;
      82             : 
      83           0 :     nr_ice_candidate_pair_compute_codeword(pair,lcand,rcand);
      84             : 
      85           0 :     if(r=nr_concat_strings(&pair->as_string,pair->codeword,"|",lcand->addr.as_string,"|",
      86           0 :         rcand->addr.as_string,"(",lcand->label,"|",rcand->label,")", NULL))
      87           0 :       ABORT(r);
      88             : 
      89           0 :     nr_ice_candidate_pair_set_state(pctx,pair,NR_ICE_PAIR_STATE_FROZEN);
      90           0 :     pair->local=lcand;
      91           0 :     pair->remote=rcand;
      92             : 
      93           0 :     nr_ice_candidate_pair_set_priority(pair);
      94             : 
      95             :     /*
      96             :        TODO(bcampen@mozilla.com): Would be nice to log why this candidate was
      97             :        created (initial pair generation, triggered check, and new trickle
      98             :        candidate seem to be the possibilities here).
      99             :     */
     100           0 :     r_log(LOG_ICE,LOG_INFO,"ICE(%s)/CAND-PAIR(%s): Pairing candidate %s (%x):%s (%x) priority=%llu (%llx)",pctx->ctx->label,pair->codeword,lcand->addr.as_string,lcand->priority,rcand->addr.as_string,rcand->priority,pair->priority,pair->priority);
     101             : 
     102             :     /* Foundation */
     103           0 :     if(r=nr_concat_strings(&pair->foundation,lcand->foundation,"|",
     104             :       rcand->foundation,NULL))
     105           0 :       ABORT(r);
     106             : 
     107             :     /* Compute the RTO per S 16 */
     108           0 :     RTO = MAX(100, (pctx->ctx->Ta * pctx->waiting_pairs));
     109             : 
     110             :     /* Make a bogus candidate to compute a theoretical peer reflexive
     111             :      * priority per S 7.1.1.1 */
     112           0 :     memcpy(&tmpcand, lcand, sizeof(tmpcand));
     113           0 :     tmpcand.type = PEER_REFLEXIVE;
     114           0 :     if (r=nr_ice_candidate_compute_priority(&tmpcand))
     115           0 :       ABORT(r);
     116           0 :     t_priority = tmpcand.priority;
     117             : 
     118             :     /* Our sending context */
     119           0 :     if(r=nr_stun_client_ctx_create(pair->as_string,
     120             :       lcand->osock,
     121           0 :       &rcand->addr,RTO,&pair->stun_client))
     122           0 :       ABORT(r);
     123           0 :     if(!(pair->stun_client->params.ice_binding_request.username=r_strdup(rcand->stream->l2r_user)))
     124           0 :       ABORT(R_NO_MEMORY);
     125           0 :     if(r=r_data_copy(&pair->stun_client->params.ice_binding_request.password,
     126           0 :       &rcand->stream->l2r_pass))
     127           0 :       ABORT(r);
     128             :     /* TODO(ekr@rtfm.com): Do we need to frob this when we change role. Bug 890667 */
     129           0 :     pair->stun_client->params.ice_binding_request.control = pctx->controlling?
     130           0 :       NR_ICE_CONTROLLING:NR_ICE_CONTROLLED;
     131           0 :     pair->stun_client->params.ice_binding_request.priority=t_priority;
     132             : 
     133           0 :     pair->stun_client->params.ice_binding_request.tiebreaker=pctx->tiebreaker;
     134             : 
     135           0 :     *pairp=pair;
     136             : 
     137           0 :     _status=0;
     138             :   abort:
     139           0 :     if(_status){
     140           0 :       nr_ice_candidate_pair_destroy(&pair);
     141             :     }
     142           0 :     return(_status);
     143             :   }
     144             : 
     145           0 : int nr_ice_candidate_pair_destroy(nr_ice_cand_pair **pairp)
     146             :   {
     147             :     nr_ice_cand_pair *pair;
     148             : 
     149           0 :     if(!pairp || !*pairp)
     150           0 :       return(0);
     151             : 
     152           0 :     pair=*pairp;
     153           0 :     *pairp=0;
     154             : 
     155             :     // record stats back to the ice ctx on destruction
     156           0 :     if (pair->stun_client) {
     157           0 :       nr_ice_accumulate_count(&(pair->local->ctx->stats.stun_retransmits), pair->stun_client->retransmit_ct);
     158             :     }
     159             : 
     160           0 :     RFREE(pair->as_string);
     161           0 :     RFREE(pair->foundation);
     162           0 :     nr_ice_socket_deregister(pair->local->isock,pair->stun_client_handle);
     163           0 :     if (pair->stun_client) {
     164           0 :       RFREE(pair->stun_client->params.ice_binding_request.username);
     165           0 :       RFREE(pair->stun_client->params.ice_binding_request.password.data);
     166           0 :       nr_stun_client_ctx_destroy(&pair->stun_client);
     167             :     }
     168             : 
     169           0 :     NR_async_timer_cancel(pair->stun_cb_timer);
     170           0 :     NR_async_timer_cancel(pair->restart_role_change_cb_timer);
     171           0 :     NR_async_timer_cancel(pair->restart_nominated_cb_timer);
     172             : 
     173           0 :     RFREE(pair);
     174           0 :     return(0);
     175             :   }
     176             : 
     177           0 : int nr_ice_candidate_pair_unfreeze(nr_ice_peer_ctx *pctx, nr_ice_cand_pair *pair)
     178             :   {
     179           0 :     assert(pair->state==NR_ICE_PAIR_STATE_FROZEN);
     180             : 
     181           0 :     nr_ice_candidate_pair_set_state(pctx,pair,NR_ICE_PAIR_STATE_WAITING);
     182             : 
     183           0 :     return(0);
     184             :   }
     185             : 
     186           0 : static void nr_ice_candidate_pair_stun_cb(NR_SOCKET s, int how, void *cb_arg)
     187             :   {
     188             :     int r,_status;
     189           0 :     nr_ice_cand_pair *pair=cb_arg;
     190           0 :     nr_ice_cand_pair *actual_pair=0;
     191           0 :     nr_ice_candidate *cand=0;
     192             :     nr_stun_message *sres;
     193             :     nr_transport_addr *request_src;
     194             :     nr_transport_addr *request_dst;
     195             :     nr_transport_addr *response_src;
     196             :     nr_transport_addr response_dst;
     197             :     nr_stun_message_attribute *attr;
     198             : 
     199           0 :     pair->stun_cb_timer=0;
     200             : 
     201           0 :     r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/CAND-PAIR(%s): STUN cb on pair addr = %s",
     202           0 :       pair->pctx->label,pair->local->stream->label,pair->codeword,pair->as_string);
     203             : 
     204             :     /* This ordinarily shouldn't happen, but can if we're
     205             :        doing the second check to confirm nomination.
     206             :        Just bail out */
     207           0 :     if(pair->state==NR_ICE_PAIR_STATE_SUCCEEDED)
     208           0 :       goto done;
     209             : 
     210           0 :     switch(pair->stun_client->state){
     211             :       case NR_STUN_CLIENT_STATE_FAILED:
     212           0 :         sres=pair->stun_client->response;
     213           0 :         if(sres && nr_stun_message_has_attribute(sres,NR_STUN_ATTR_ERROR_CODE,&attr)&&attr->u.error_code.number==487){
     214             : 
     215             :           /*
     216             :            * Flip the controlling bit; subsequent 487s for other pairs will be
     217             :            * ignored, since we abandon their STUN transactions.
     218             :            */
     219           0 :           nr_ice_peer_ctx_switch_controlling_role(pair->pctx);
     220             : 
     221           0 :           return;
     222             :         }
     223             :         /* Fall through */
     224             :       case NR_STUN_CLIENT_STATE_TIMED_OUT:
     225           0 :         nr_ice_candidate_pair_set_state(pair->pctx,pair,NR_ICE_PAIR_STATE_FAILED);
     226           0 :         break;
     227             :       case NR_STUN_CLIENT_STATE_DONE:
     228             :         /* make sure the addresses match up S 7.1.2.2 */
     229           0 :         response_src=&pair->stun_client->peer_addr;
     230           0 :         request_dst=&pair->remote->addr;
     231           0 :         if (nr_transport_addr_cmp(response_src,request_dst,NR_TRANSPORT_ADDR_CMP_MODE_ALL)){
     232           0 :           r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s)/CAND-PAIR(%s): Peer address mismatch %s != %s",pair->pctx->label,pair->codeword,response_src->as_string,request_dst->as_string);
     233           0 :           nr_ice_candidate_pair_set_state(pair->pctx,pair,NR_ICE_PAIR_STATE_FAILED);
     234           0 :           break;
     235             :         }
     236           0 :         request_src=&pair->stun_client->my_addr;
     237           0 :         nr_socket_getaddr(pair->local->osock,&response_dst);
     238           0 :         if (nr_transport_addr_cmp(request_src,&response_dst,NR_TRANSPORT_ADDR_CMP_MODE_ALL)){
     239           0 :           r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s)/CAND-PAIR(%s): Local address mismatch %s != %s",pair->pctx->label,pair->codeword,request_src->as_string,response_dst.as_string);
     240           0 :           nr_ice_candidate_pair_set_state(pair->pctx,pair,NR_ICE_PAIR_STATE_FAILED);
     241           0 :           break;
     242             :         }
     243             : 
     244           0 :         if(strlen(pair->stun_client->results.ice_binding_response.mapped_addr.as_string)==0){
     245             :           /* we're using the mapped_addr returned by the server to lookup our
     246             :            * candidate, but if the server fails to do that we can't perform
     247             :            * the lookup -- this may be a BUG because if we've gotten here
     248             :            * then the transaction ID check succeeded, and perhaps we should
     249             :            * just assume that it's the server we're talking to and that our
     250             :            * peer is ok, but I'm not sure how that'll interact with the
     251             :            * peer reflexive logic below */
     252           0 :           r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s)/CAND-PAIR(%s): server failed to return mapped address on pair %s", pair->pctx->label,pair->codeword,pair->as_string);
     253           0 :           nr_ice_candidate_pair_set_state(pair->pctx,pair,NR_ICE_PAIR_STATE_FAILED);
     254           0 :           break;
     255             :         }
     256           0 :         else if(!nr_transport_addr_cmp(&pair->local->addr,&pair->stun_client->results.ice_binding_response.mapped_addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL)){
     257           0 :           nr_ice_candidate_pair_set_state(pair->pctx,pair,NR_ICE_PAIR_STATE_SUCCEEDED);
     258             :         }
     259           0 :         else if(pair->stun_client->state == NR_STUN_CLIENT_STATE_DONE) {
     260             :           /* OK, this didn't correspond to a pair on the check list, but
     261             :              it probably matches one of our candidates */
     262             : 
     263           0 :           cand=TAILQ_FIRST(&pair->local->component->candidates);
     264           0 :           while(cand){
     265           0 :             if(!nr_transport_addr_cmp(&cand->addr,&pair->stun_client->results.ice_binding_response.mapped_addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL)) {
     266           0 :               r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s): found pre-existing local candidate of type %d for mapped address %s", pair->pctx->label,cand->type,cand->addr.as_string);
     267           0 :               assert(cand->type != HOST);
     268           0 :               break;
     269             :             }
     270             : 
     271           0 :             cand=TAILQ_NEXT(cand,entry_comp);
     272             :           }
     273             : 
     274           0 :           if(!cand) {
     275             :             /* OK, nothing found, must be a new peer reflexive */
     276           0 :             if (pair->pctx->ctx->flags & NR_ICE_CTX_FLAGS_RELAY_ONLY) {
     277             :               /* Any STUN response with a reflexive address in it is unwanted
     278             :                  when we'll send on relay only. Bail since cand is used below. */
     279           0 :               goto done;
     280             :             }
     281           0 :             if(r=nr_ice_candidate_create(pair->pctx->ctx,
     282           0 :               pair->local->component,pair->local->isock,pair->local->osock,
     283           0 :               PEER_REFLEXIVE,pair->local->tcp_type,0,pair->local->component->component_id,&cand))
     284           0 :               ABORT(r);
     285           0 :             if(r=nr_transport_addr_copy(&cand->addr,&pair->stun_client->results.ice_binding_response.mapped_addr))
     286           0 :               ABORT(r);
     287           0 :             cand->state=NR_ICE_CAND_STATE_INITIALIZED;
     288           0 :             TAILQ_INSERT_TAIL(&pair->local->component->candidates,cand,entry_comp);
     289             :           } else {
     290             :             /* Check if we have a pair for this candidate already. */
     291           0 :             if(r=nr_ice_media_stream_find_pair(pair->remote->stream, cand, pair->remote, &actual_pair)) {
     292           0 :               r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s): no pair exists for %s and %s", pair->pctx->label,cand->addr.as_string, pair->remote->addr.as_string);
     293             :             }
     294             :           }
     295             : 
     296           0 :           if(!actual_pair) {
     297           0 :             if(r=nr_ice_candidate_pair_create(pair->pctx,cand,pair->remote, &actual_pair))
     298           0 :               ABORT(r);
     299             : 
     300           0 :             if(r=nr_ice_component_insert_pair(actual_pair->remote->component,actual_pair))
     301           0 :               ABORT(r);
     302             : 
     303             :             /* If the original pair was nominated, make us nominated too. */
     304           0 :             if(pair->peer_nominated)
     305           0 :               actual_pair->peer_nominated=1;
     306             : 
     307             :             /* Now mark the orig pair failed */
     308           0 :             nr_ice_candidate_pair_set_state(pair->pctx,pair,NR_ICE_PAIR_STATE_FAILED);
     309             :           }
     310             : 
     311           0 :           assert(actual_pair);
     312           0 :           nr_ice_candidate_pair_set_state(actual_pair->pctx,actual_pair,NR_ICE_PAIR_STATE_SUCCEEDED);
     313           0 :           pair=actual_pair;
     314             : 
     315             :         }
     316             : 
     317             :         /* Should we set nominated? */
     318           0 :         if(pair->pctx->controlling){
     319           0 :           if(pair->pctx->ctx->flags & NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION)
     320           0 :             pair->nominated=1;
     321             :         }
     322             :         else{
     323           0 :           if(pair->peer_nominated)
     324           0 :             pair->nominated=1;
     325             :         }
     326             : 
     327             : 
     328             :         /* increment the number of valid pairs in the component */
     329             :         /* We don't bother to maintain a separate valid list */
     330           0 :         pair->remote->component->valid_pairs++;
     331             : 
     332             :         /* S 7.1.2.2: unfreeze other pairs with the same foundation*/
     333           0 :         if(r=nr_ice_media_stream_unfreeze_pairs_foundation(pair->remote->stream,pair->foundation))
     334           0 :           ABORT(r);
     335             : 
     336             :         /* Deal with this pair being nominated */
     337           0 :         if(pair->nominated){
     338           0 :           if(r=nr_ice_component_nominated_pair(pair->remote->component, pair))
     339           0 :             ABORT(r);
     340             :         }
     341             : 
     342           0 :         break;
     343             :       default:
     344           0 :         ABORT(R_INTERNAL);
     345             :     }
     346             : 
     347             :     /* If we're controlling but in regular mode, ask the handler
     348             :        if he wants to nominate something and stop... */
     349           0 :     if(pair->pctx->controlling && !(pair->pctx->ctx->flags & NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION)){
     350             : 
     351           0 :       if(r=nr_ice_component_select_pair(pair->pctx,pair->remote->component)){
     352           0 :         if(r!=R_NOT_FOUND)
     353           0 :           ABORT(r);
     354             :       }
     355             :     }
     356             : 
     357             :   done:
     358           0 :     _status=0;
     359             :   abort:
     360           0 :     return;
     361             :   }
     362             : 
     363           0 : static void nr_ice_candidate_pair_restart(nr_ice_peer_ctx *pctx, nr_ice_cand_pair *pair)
     364             :   {
     365             :     int r,_status;
     366             :     UINT4 mode;
     367             : 
     368           0 :     nr_ice_candidate_pair_set_state(pctx,pair,NR_ICE_PAIR_STATE_IN_PROGRESS);
     369             : 
     370             :     /* Start STUN */
     371           0 :     if(pair->pctx->controlling && (pair->pctx->ctx->flags & NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION))
     372           0 :       mode=NR_ICE_CLIENT_MODE_USE_CANDIDATE;
     373             :     else
     374           0 :       mode=NR_ICE_CLIENT_MODE_BINDING_REQUEST;
     375             : 
     376           0 :     nr_stun_client_reset(pair->stun_client);
     377             : 
     378           0 :     if(r=nr_stun_client_start(pair->stun_client,mode,nr_ice_candidate_pair_stun_cb,pair))
     379           0 :       ABORT(r);
     380             : 
     381           0 :     if ((r=nr_ice_ctx_remember_id(pair->pctx->ctx, pair->stun_client->request))) {
     382             :       /* ignore if this fails (which it shouldn't) because it's only an
     383             :        * optimization and the cleanup routines are not going to do the right
     384             :        * thing if this fails */
     385           0 :       assert(0);
     386             :     }
     387             : 
     388           0 :     _status=0;
     389             :   abort:
     390           0 :     if(_status){
     391             :       /* Don't fire the CB, but schedule it to fire ASAP */
     392           0 :       assert(!pair->stun_cb_timer);
     393           0 :       NR_ASYNC_TIMER_SET(0,nr_ice_candidate_pair_stun_cb,pair, &pair->stun_cb_timer);
     394           0 :       _status=0;
     395             :     }
     396           0 :   }
     397             : 
     398           0 : int nr_ice_candidate_pair_start(nr_ice_peer_ctx *pctx, nr_ice_cand_pair *pair)
     399             :   {
     400             :     int r,_status;
     401             : 
     402             :     /* Register the stun ctx for when responses come in*/
     403           0 :     if(r=nr_ice_socket_register_stun_client(pair->local->isock,pair->stun_client,&pair->stun_client_handle))
     404           0 :       ABORT(r);
     405             : 
     406           0 :     nr_ice_candidate_pair_restart(pctx, pair);
     407             : 
     408           0 :     _status=0;
     409             :   abort:
     410           0 :     return(_status);
     411             :   }
     412             : 
     413           0 : static int nr_ice_candidate_copy_for_triggered_check(nr_ice_cand_pair *pair)
     414             :   {
     415             :     int r,_status;
     416             :     nr_ice_cand_pair *copy;
     417             : 
     418           0 :     if(r=nr_ice_candidate_pair_create(pair->pctx, pair->local, pair->remote, &copy))
     419           0 :       ABORT(r);
     420             : 
     421             :     /* Preserve nomination status */
     422           0 :     copy->peer_nominated= pair->peer_nominated;
     423           0 :     copy->nominated = pair->nominated;
     424             : 
     425           0 :     r_log(LOG_ICE,LOG_INFO,"CAND-PAIR(%s): Adding pair to check list and trigger check queue: %s",pair->codeword,pair->as_string);
     426           0 :     if(r=nr_ice_candidate_pair_insert(&pair->remote->stream->check_list,copy))
     427           0 :       ABORT(r);
     428           0 :     nr_ice_candidate_pair_trigger_check_append(&pair->remote->stream->trigger_check_queue,copy);
     429             : 
     430           0 :     copy->triggered = 1;
     431           0 :     nr_ice_candidate_pair_set_state(copy->pctx,copy,NR_ICE_PAIR_STATE_WAITING);
     432             : 
     433           0 :     _status=0;
     434             :   abort:
     435           0 :     return(_status);
     436             : }
     437             : 
     438           0 : int nr_ice_candidate_pair_do_triggered_check(nr_ice_peer_ctx *pctx, nr_ice_cand_pair *pair)
     439             :   {
     440             :     int r,_status;
     441             : 
     442           0 :     if(pair->state==NR_ICE_PAIR_STATE_CANCELLED) {
     443           0 :       r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/CAND_PAIR(%s): Ignoring matching but canceled pair",pctx->label,pair->codeword);
     444           0 :       return(0);
     445           0 :     } else if(pair->state==NR_ICE_PAIR_STATE_SUCCEEDED) {
     446           0 :       r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/CAND_PAIR(%s): No new trigger check for succeeded pair",pctx->label,pair->codeword);
     447           0 :       return(0);
     448             :     }
     449             : 
     450             :     /* Do not run this logic more than once on a given pair */
     451           0 :     if(!pair->triggered){
     452           0 :       r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/CAND-PAIR(%s): triggered check on %s",pctx->label,pair->codeword,pair->as_string);
     453             : 
     454           0 :       pair->triggered=1;
     455             : 
     456           0 :       switch(pair->state){
     457             :         case NR_ICE_PAIR_STATE_FAILED:
     458             :           /* OK, there was a pair, it's just invalid: According to Section
     459             :            * 7.2.1.4, we need to resurrect it */
     460           0 :           r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/CAND-PAIR(%s): received STUN check on failed pair, resurrecting: %s",pctx->label,pair->codeword,pair->as_string);
     461             :           /* fall through */
     462             :         case NR_ICE_PAIR_STATE_FROZEN:
     463           0 :           nr_ice_candidate_pair_set_state(pctx,pair,NR_ICE_PAIR_STATE_WAITING);
     464             :           /* fall through even further */
     465             :         case NR_ICE_PAIR_STATE_WAITING:
     466             :           /* Append it additionally to the trigger check queue */
     467           0 :           r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/CAND-PAIR(%s): Inserting pair to trigger check queue: %s",pctx->label,pair->codeword,pair->as_string);
     468           0 :           nr_ice_candidate_pair_trigger_check_append(&pair->remote->stream->trigger_check_queue,pair);
     469           0 :           break;
     470             :         case NR_ICE_PAIR_STATE_IN_PROGRESS:
     471             :           /* Instead of trying to maintain two stun contexts on the same pair,
     472             :            * and handling heterogenous responses and error conditions, we instead
     473             :            * create a second pair that is identical except that it has the
     474             :            * |triggered| bit set. We also cancel the original pair, but it can
     475             :            * still succeed on its own in the special waiting state. */
     476           0 :           if(r=nr_ice_candidate_copy_for_triggered_check(pair))
     477           0 :             ABORT(r);
     478           0 :           nr_ice_candidate_pair_cancel(pair->pctx,pair,1);
     479           0 :           break;
     480             :         default:
     481             :           /* all states are handled - a new/unknown state should not
     482             :            * automatically enter the start_checks() below */
     483           0 :           assert(0);
     484             :           break;
     485             :       }
     486             : 
     487             :       /* Ensure that the timers are running to start checks on the topmost entry
     488             :        * of the triggered check queue. */
     489           0 :       if(r=nr_ice_media_stream_start_checks(pair->pctx,pair->remote->stream))
     490           0 :         ABORT(r);
     491             :     }
     492             : 
     493           0 :     _status=0;
     494             :   abort:
     495           0 :     return(_status);
     496             :   }
     497             : 
     498           0 : int nr_ice_candidate_pair_cancel(nr_ice_peer_ctx *pctx,nr_ice_cand_pair *pair, int move_to_wait_state)
     499             :   {
     500           0 :     if(pair->state != NR_ICE_PAIR_STATE_FAILED){
     501             :       /* If it's already running we need to terminate the stun */
     502           0 :       if(pair->state==NR_ICE_PAIR_STATE_IN_PROGRESS){
     503           0 :         if(move_to_wait_state) {
     504           0 :           nr_stun_client_wait(pair->stun_client);
     505             :         } else {
     506           0 :           nr_stun_client_cancel(pair->stun_client);
     507             :         }
     508             :       }
     509           0 :       nr_ice_candidate_pair_set_state(pctx,pair,NR_ICE_PAIR_STATE_CANCELLED);
     510             :     }
     511             : 
     512           0 :     return(0);
     513             :   }
     514             : 
     515           0 : int nr_ice_candidate_pair_select(nr_ice_cand_pair *pair)
     516             :   {
     517             :     int r,_status;
     518             : 
     519           0 :     if(!pair){
     520           0 :       r_log(LOG_ICE,LOG_ERR,"ICE-PAIR: No pair chosen");
     521           0 :       ABORT(R_BAD_ARGS);
     522             :     }
     523             : 
     524           0 :     if(pair->state!=NR_ICE_PAIR_STATE_SUCCEEDED){
     525           0 :       r_log(LOG_ICE,LOG_ERR,"ICE-PEER(%s)/CAND-PAIR(%s): tried to install non-succeeded pair, ignoring: %s",pair->pctx->label,pair->codeword,pair->as_string);
     526             :     }
     527             :     else{
     528             :       /* Ok, they chose one */
     529             :       /* 1. Send a new request with nominated. Do it as a scheduled
     530             :             event to avoid reentrancy issues. Only do this if it hasn't
     531             :             happened already (though this shouldn't happen.)
     532             :       */
     533           0 :       if(!pair->restart_nominated_cb_timer)
     534           0 :         NR_ASYNC_TIMER_SET(0,nr_ice_candidate_pair_restart_stun_nominated_cb,pair,&pair->restart_nominated_cb_timer);
     535             : 
     536             :       /* 2. Tell ourselves this pair is ready */
     537           0 :       if(r=nr_ice_component_nominated_pair(pair->remote->component, pair))
     538           0 :         ABORT(r);
     539             :     }
     540             : 
     541           0 :     _status=0;
     542             :   abort:
     543           0 :     return(_status);
     544             :  }
     545             : 
     546           0 : int nr_ice_candidate_pair_set_state(nr_ice_peer_ctx *pctx, nr_ice_cand_pair *pair, int state)
     547             :   {
     548             :     int r,_status;
     549             : 
     550           0 :     r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/CAND-PAIR(%s): setting pair to state %s: %s",
     551           0 :       pctx->label,pair->codeword,nr_ice_cand_pair_states[state],pair->as_string);
     552             : 
     553             :     /* NOTE: This function used to reference pctx->state instead of
     554             :        pair->state and the assignment to pair->state was at the top
     555             :        of this function. Because pctx->state was never changed, this seems to have
     556             :        been a typo. The natural logic is "if the state changed
     557             :        decrement the counter" so this implies we should be checking
     558             :        the pair state rather than the pctx->state.
     559             : 
     560             :        This didn't cause big problems because waiting_pairs was only
     561             :        used for pacing, so the pacing just was kind of broken.
     562             : 
     563             :        This note is here as a reminder until we do more testing
     564             :        and make sure that in fact this was a typo.
     565             :     */
     566           0 :     if(pair->state!=NR_ICE_PAIR_STATE_WAITING){
     567           0 :       if(state==NR_ICE_PAIR_STATE_WAITING)
     568           0 :         pctx->waiting_pairs++;
     569             :     }
     570             :     else{
     571           0 :       if(state!=NR_ICE_PAIR_STATE_WAITING)
     572           0 :         pctx->waiting_pairs--;
     573             : 
     574           0 :       assert(pctx->waiting_pairs>=0);
     575             :     }
     576           0 :     pair->state=state;
     577             : 
     578             : 
     579           0 :     if(pair->state==NR_ICE_PAIR_STATE_FAILED ||
     580           0 :        pair->state==NR_ICE_PAIR_STATE_CANCELLED){
     581           0 :       if(r=nr_ice_component_failed_pair(pair->remote->component, pair))
     582           0 :         ABORT(r);
     583             :     }
     584             : 
     585           0 :     _status=0;
     586             :   abort:
     587           0 :     return(_status);
     588             :   }
     589             : 
     590           0 : int nr_ice_candidate_pair_dump_state(nr_ice_cand_pair *pair, FILE *out)
     591             :   {
     592             :     /*r_log(LOG_ICE,LOG_DEBUG,"CAND-PAIR(%s): pair %s: state=%s, priority=0x%llx\n",pair->codeword,pair->as_string,nr_ice_cand_pair_states[pair->state],pair->priority);*/
     593             : 
     594           0 :     return(0);
     595             :   }
     596             : 
     597             : 
     598           0 : int nr_ice_candidate_pair_trigger_check_append(nr_ice_cand_pair_head *head,nr_ice_cand_pair *pair)
     599             :   {
     600           0 :     if(pair->triggered_check_queue_entry.tqe_next ||
     601           0 :        pair->triggered_check_queue_entry.tqe_prev)
     602           0 :       return(0);
     603             : 
     604           0 :     TAILQ_INSERT_TAIL(head,pair,triggered_check_queue_entry);
     605             : 
     606           0 :     return(0);
     607             :   }
     608             : 
     609           0 : int nr_ice_candidate_pair_insert(nr_ice_cand_pair_head *head,nr_ice_cand_pair *pair)
     610             :   {
     611             :     nr_ice_cand_pair *c1;
     612             : 
     613           0 :     c1=TAILQ_FIRST(head);
     614           0 :     while(c1){
     615           0 :       if(c1->priority < pair->priority){
     616           0 :         TAILQ_INSERT_BEFORE(c1,pair,check_queue_entry);
     617           0 :         break;
     618             :       }
     619             : 
     620           0 :       c1=TAILQ_NEXT(c1,check_queue_entry);
     621             :     }
     622           0 :     if(!c1) TAILQ_INSERT_TAIL(head,pair,check_queue_entry);
     623             : 
     624           0 :     return(0);
     625             :   }
     626             : 
     627           0 : void nr_ice_candidate_pair_restart_stun_nominated_cb(NR_SOCKET s, int how, void *cb_arg)
     628             :   {
     629           0 :     nr_ice_cand_pair *pair=cb_arg;
     630             :     int r,_status;
     631             : 
     632           0 :     pair->restart_nominated_cb_timer=0;
     633             : 
     634           0 :     r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/STREAM(%s)/CAND-PAIR(%s)/COMP(%d): Restarting pair as nominated: %s",pair->pctx->label,pair->local->stream->label,pair->codeword,pair->remote->component->component_id,pair->as_string);
     635             : 
     636           0 :     nr_stun_client_reset(pair->stun_client);
     637             : 
     638           0 :     if(r=nr_stun_client_start(pair->stun_client,NR_ICE_CLIENT_MODE_USE_CANDIDATE,nr_ice_candidate_pair_stun_cb,pair))
     639           0 :       ABORT(r);
     640             : 
     641           0 :     if(r=nr_ice_ctx_remember_id(pair->pctx->ctx, pair->stun_client->request))
     642           0 :       ABORT(r);
     643             : 
     644           0 :     _status=0;
     645             :   abort:
     646           0 :     return;
     647             :   }
     648             : 
     649           0 : static void nr_ice_candidate_pair_restart_stun_role_change_cb(NR_SOCKET s, int how, void *cb_arg)
     650             :  {
     651           0 :     nr_ice_cand_pair *pair=cb_arg;
     652             : 
     653           0 :     pair->restart_role_change_cb_timer=0;
     654             : 
     655           0 :     r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/STREAM(%s)/CAND-PAIR(%s):COMP(%d): Restarting pair as %s: %s",pair->pctx->label,pair->local->stream->label,pair->codeword,pair->remote->component->component_id,pair->pctx->controlling ? "CONTROLLING" : "CONTROLLED",pair->as_string);
     656             : 
     657           0 :     nr_ice_candidate_pair_restart(pair->pctx, pair);
     658           0 :   }
     659             : 
     660           0 : void nr_ice_candidate_pair_role_change(nr_ice_cand_pair *pair)
     661             :   {
     662           0 :     pair->stun_client->params.ice_binding_request.control = pair->pctx->controlling ? NR_ICE_CONTROLLING : NR_ICE_CONTROLLED;
     663           0 :     nr_ice_candidate_pair_set_priority(pair);
     664             : 
     665           0 :     if(pair->state == NR_ICE_PAIR_STATE_IN_PROGRESS) {
     666             :       /* We could try only restarting in-progress pairs when they receive their
     667             :        * 487, but this ends up being simpler, because any extra 487 are dropped.
     668             :        */
     669           0 :       if(!pair->restart_role_change_cb_timer)
     670           0 :         NR_ASYNC_TIMER_SET(0,nr_ice_candidate_pair_restart_stun_role_change_cb,pair,&pair->restart_role_change_cb_timer);
     671             :     }
     672           0 :   }
     673             : 
     674           0 : static void nr_ice_candidate_pair_compute_codeword(nr_ice_cand_pair *pair,
     675             :   nr_ice_candidate *lcand, nr_ice_candidate *rcand)
     676             :   {
     677             :     char as_string[2048];
     678             : 
     679           0 :     snprintf(as_string,
     680             :              sizeof(as_string),
     681             :              "%s|%s(%s|%s)",
     682           0 :              lcand->addr.as_string,
     683           0 :              rcand->addr.as_string,
     684             :              lcand->label,
     685             :              rcand->label);
     686             : 
     687           0 :     nr_ice_compute_codeword(as_string,strlen(as_string),pair->codeword);
     688           0 :   }
     689             : 

Generated by: LCOV version 1.13