int nr_ice_candidate_pair_select(nr_ice_cand_pair *pair)
  {
    int r,_status;

    if(!pair){
      r_log(LOG_ICE,LOG_ERR,"ICE-PAIR: No pair chosen");
      ABORT(R_BAD_ARGS);
    }

    if(pair->state!=NR_ICE_PAIR_STATE_SUCCEEDED){
      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);
    }
    else{
      /* Ok, they chose one */
      /* 1. Send a new request with nominated. Do it as a scheduled
            event to avoid reentrancy issues. Only do this if it hasn't
            happened already (though this shouldn't happen.)
      */
      if(!pair->restart_nominated_cb_timer)
        NR_ASYNC_TIMER_SET(0,nr_ice_candidate_pair_restart_stun_nominated_cb,pair,&pair->restart_nominated_cb_timer);

      /* 2. Tell ourselves this pair is ready */
      if(r=nr_ice_component_nominated_pair(pair->remote->component, pair))
        ABORT(r);
    }

    _status=0;
  abort:
    return(_status);
 }
Beispiel #2
0
int nr_ice_candidate_pair_select(nr_ice_cand_pair *pair)
  {
    int r,_status;
   
    if(!pair){
      r_log(LOG_ICE,LOG_ERR,"ICE-PAIR: No pair chosen");
      ABORT(R_BAD_ARGS);
    }

    if(pair->state!=NR_ICE_PAIR_STATE_SUCCEEDED){
      r_log(LOG_ICE,LOG_ERR,"ICE-PEER(%s): tried to install non-succeeded pair %s, ignoring",pair->pctx->label,pair->as_string);
    }
    else{
      /* Ok, they chose one */
      /* 1. Send a new request with nominated. Do it as a scheduled
            event to avoid reentrancy issues  */
      NR_ASYNC_SCHEDULE(nr_ice_candidate_pair_restart_stun_nominated_cb,pair);
      /* 2. Tell ourselves this pair is ready */
      if(r=nr_ice_component_nominated_pair(pair->remote->component, pair))
        ABORT(r);
    }

    _status=0;
  abort:
    return(_status);
 }
static void nr_ice_candidate_pair_stun_cb(NR_SOCKET s, int how, void *cb_arg)
  {
    int r,_status;
    nr_ice_cand_pair *pair=cb_arg,*orig_pair;
    nr_ice_candidate *cand=0;
    nr_stun_message *sres;
    nr_transport_addr *request_src;
    nr_transport_addr *request_dst;
    nr_transport_addr *response_src;
    nr_transport_addr response_dst;
    nr_stun_message_attribute *attr;

    pair->stun_cb_timer=0;

    r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/CAND-PAIR(%s): STUN cb on pair addr = %s",
      pair->pctx->label,pair->local->stream->label,pair->codeword,pair->as_string);

    /* This ordinarily shouldn't happen, but can if we're
       doing the second check to confirm nomination.
       Just bail out */
    if(pair->state==NR_ICE_PAIR_STATE_SUCCEEDED)
      goto done;

    switch(pair->stun_client->state){
      case NR_STUN_CLIENT_STATE_FAILED:
        sres=pair->stun_client->response;
        if(sres && nr_stun_message_has_attribute(sres,NR_STUN_ATTR_ERROR_CODE,&attr)&&attr->u.error_code.number==487){

          /*
           * Flip the controlling bit; subsequent 487s for other pairs will be
           * ignored, since we abandon their STUN transactions.
           */
          nr_ice_peer_ctx_switch_controlling_role(pair->pctx);

          return;
        }
        /* Fall through */
      case NR_STUN_CLIENT_STATE_TIMED_OUT:
        nr_ice_candidate_pair_set_state(pair->pctx,pair,NR_ICE_PAIR_STATE_FAILED);
        break;
      case NR_STUN_CLIENT_STATE_DONE:
        /* make sure the addresses match up S 7.1.2.2 */
        response_src=&pair->stun_client->peer_addr;
        request_dst=&pair->remote->addr;
        if (nr_transport_addr_cmp(response_src,request_dst,NR_TRANSPORT_ADDR_CMP_MODE_ALL)){
          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);
          nr_ice_candidate_pair_set_state(pair->pctx,pair,NR_ICE_PAIR_STATE_FAILED);
          break;
        }
        request_src=&pair->stun_client->my_addr;
        nr_socket_getaddr(pair->local->osock,&response_dst);
        if (nr_transport_addr_cmp(request_src,&response_dst,NR_TRANSPORT_ADDR_CMP_MODE_ALL)){
          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);
          nr_ice_candidate_pair_set_state(pair->pctx,pair,NR_ICE_PAIR_STATE_FAILED);
          break;
        }

        if(strlen(pair->stun_client->results.ice_binding_response.mapped_addr.as_string)==0){
          /* we're using the mapped_addr returned by the server to lookup our
           * candidate, but if the server fails to do that we can't perform
           * the lookup -- this may be a BUG because if we've gotten here
           * then the transaction ID check succeeded, and perhaps we should
           * just assume that it's the server we're talking to and that our
           * peer is ok, but I'm not sure how that'll interact with the
           * peer reflexive logic below */
          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);
          nr_ice_candidate_pair_set_state(pair->pctx,pair,NR_ICE_PAIR_STATE_FAILED);
          break;
        }
        else if(!nr_transport_addr_cmp(&pair->local->addr,&pair->stun_client->results.ice_binding_response.mapped_addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL)){
          nr_ice_candidate_pair_set_state(pair->pctx,pair,NR_ICE_PAIR_STATE_SUCCEEDED);
        }
        else{
          /* OK, this didn't correspond to a pair on the check list, but
             it probably matches one of our candidates */

          cand=TAILQ_FIRST(&pair->local->component->candidates);
          while(cand){
            if(!nr_transport_addr_cmp(&cand->addr,&pair->stun_client->results.ice_binding_response.mapped_addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL))
              break;

            cand=TAILQ_NEXT(cand,entry_comp);
          }

          /* OK, nothing found, must be peer reflexive */
          if(!cand){
            if(r=nr_ice_candidate_create(pair->pctx->ctx,
              pair->local->component,pair->local->isock,pair->local->osock,
              PEER_REFLEXIVE,0,pair->local->component->component_id,&cand))
              ABORT(r);
            if(r=nr_transport_addr_copy(&cand->addr,&pair->stun_client->results.ice_binding_response.mapped_addr))
              ABORT(r);
            cand->state=NR_ICE_CAND_STATE_INITIALIZED;
            TAILQ_INSERT_TAIL(&pair->local->component->candidates,cand,entry_comp);
          }

          /* Note: we stomp the existing pair! */
          orig_pair=pair;
          if(r=nr_ice_candidate_pair_create(pair->pctx,cand,pair->remote,
            &pair))
            ABORT(r);

          nr_ice_candidate_pair_set_state(pair->pctx,pair,NR_ICE_PAIR_STATE_SUCCEEDED);

          if(r=nr_ice_component_insert_pair(pair->remote->component,pair))
            ABORT(r);

          /* If the original pair was nominated, make us nominated,
             since we replace him*/
          if(orig_pair->peer_nominated)
            pair->peer_nominated=1;


          /* Now mark the orig pair failed */
          nr_ice_candidate_pair_set_state(orig_pair->pctx,orig_pair,NR_ICE_PAIR_STATE_FAILED);

        }

        /* Should we set nominated? */
        if(pair->pctx->controlling){
          if(pair->pctx->ctx->flags & NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION)
            pair->nominated=1;
        }
        else{
          if(pair->peer_nominated)
            pair->nominated=1;
        }


        /* increment the number of valid pairs in the component */
        /* We don't bother to maintain a separate valid list */
        pair->remote->component->valid_pairs++;

        /* S 7.1.2.2: unfreeze other pairs with the same foundation*/
        if(r=nr_ice_media_stream_unfreeze_pairs_foundation(pair->remote->stream,pair->foundation))
          ABORT(r);

        /* Deal with this pair being nominated */
        if(pair->nominated){
          if(r=nr_ice_component_nominated_pair(pair->remote->component, pair))
            ABORT(r);
        }

        break;
      default:
        ABORT(R_INTERNAL);
    }

    /* If we're controlling but in regular mode, ask the handler
       if he wants to nominate something and stop... */
    if(pair->pctx->controlling && !(pair->pctx->ctx->flags & NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION)){

      if(r=nr_ice_component_select_pair(pair->pctx,pair->remote->component)){
        if(r!=R_NOT_FOUND)
          ABORT(r);
      }
    }

  done:
    _status=0;
  abort:
    return;
  }