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); }
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; }