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); }
static int nr_turn_client_start_refresh_timer(nr_turn_client_ctx *tctx, nr_turn_stun_ctx *sctx, UINT4 lifetime) { int _status; assert(!tctx->refresh_timer_handle); if (lifetime <= TURN_REFRESH_SLACK_SECONDS) { r_log(NR_LOG_TURN, LOG_ERR, "Too short lifetime specified for turn %u", lifetime); ABORT(R_BAD_DATA); } if (lifetime > 3600) lifetime = 3600; lifetime -= TURN_REFRESH_SLACK_SECONDS; r_log(NR_LOG_TURN, LOG_DEBUG, "TURN(%s): Setting refresh timer for %u seconds", tctx->label, lifetime); NR_ASYNC_TIMER_SET(lifetime * 1000, nr_turn_client_refresh_timer_cb, sctx, &tctx->refresh_timer_handle); _status=0; abort: if (_status) { nr_turn_client_failed(tctx); } return _status; }
static void nr_ice_candidate_pair_restart(nr_ice_peer_ctx *pctx, nr_ice_cand_pair *pair) { int r,_status; UINT4 mode; nr_ice_candidate_pair_set_state(pctx,pair,NR_ICE_PAIR_STATE_IN_PROGRESS); /* Start STUN */ if(pair->pctx->controlling && (pair->pctx->ctx->flags & NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION)) mode=NR_ICE_CLIENT_MODE_USE_CANDIDATE; else mode=NR_ICE_CLIENT_MODE_BINDING_REQUEST; nr_stun_client_reset(pair->stun_client); if(r=nr_stun_client_start(pair->stun_client,mode,nr_ice_candidate_pair_stun_cb,pair)) ABORT(r); if ((r=nr_ice_ctx_remember_id(pair->pctx->ctx, pair->stun_client->request))) { /* ignore if this fails (which it shouldn't) because it's only an * optimization and the cleanup routines are not going to do the right * thing if this fails */ assert(0); } _status=0; abort: if(_status){ /* Don't fire the CB, but schedule it to fire ASAP */ assert(!pair->stun_cb_timer); NR_ASYNC_TIMER_SET(0,nr_ice_candidate_pair_stun_cb,pair, &pair->stun_cb_timer); _status=0; } }
int NrIceResolverFake::resolve(void *obj, nr_resolver_resource *resource, int (*cb)(void *cb_arg, nr_transport_addr *addr), void *cb_arg, void **handle) { int r,_status; MOZ_ASSERT(obj); NrIceResolverFake *fake = static_cast<NrIceResolverFake *>(obj); MOZ_ASSERT(fake->allocated_resolvers_ > 0); PendingResolution *pending = new PendingResolution(fake, resource->domain_name, resource->port ? resource->port : 3478, cb, cb_arg); if ((r=NR_ASYNC_TIMER_SET(fake->delay_ms_,NrIceResolverFake::resolve_cb, (void *)pending, &pending->timer_handle_))) { delete pending; ABORT(r); } *handle = pending; _status=0; abort: return(_status); }
static int nr_turn_client_connect(nr_turn_client_ctx *ctx) { int r,_status; if (ctx->turn_server_addr.protocol != IPPROTO_TCP) ABORT(R_INTERNAL); r = nr_socket_connect(ctx->sock, &ctx->turn_server_addr); if (r == R_WOULDBLOCK) { NR_SOCKET fd; if (r=nr_socket_getfd(ctx->sock, &fd)) ABORT(r); NR_ASYNC_WAIT(fd, NR_ASYNC_WAIT_WRITE, nr_turn_client_connected_cb, ctx); NR_ASYNC_TIMER_SET(TURN_CONNECT_TIMEOUT, nr_turn_client_connect_timeout_cb, ctx, &ctx->connected_timer_handle); ABORT(R_WOULDBLOCK); } if (r) { ABORT(R_IO_ERROR); } ctx->state = NR_TURN_CLIENT_STATE_CONNECTED; _status = 0; abort: return(_status); }
int nr_stun_client_wait(nr_stun_client_ctx *ctx) { nr_stun_client_cancel(ctx); ctx->state=NR_STUN_CLIENT_STATE_WAITING; ctx->request_ct = ctx->maximum_transmits; ctx->timeout_ms = ctx->maximum_transmits_timeout_ms; NR_ASYNC_TIMER_SET(ctx->timeout_ms, nr_stun_client_timer_expired_cb, ctx, &ctx->timer_handle); return(0); }
void nr_ice_candidate_pair_role_change(nr_ice_cand_pair *pair) { pair->stun_client->params.ice_binding_request.control = pair->pctx->controlling ? NR_ICE_CONTROLLING : NR_ICE_CONTROLLED; if(pair->state == NR_ICE_PAIR_STATE_IN_PROGRESS) { /* We could try only restarting in-progress pairs when they receive their * 487, but this ends up being simpler, because any extra 487 are dropped. */ if(!pair->restart_role_change_cb_timer) NR_ASYNC_TIMER_SET(0,nr_ice_candidate_pair_restart_stun_role_change_cb,pair,&pair->restart_role_change_cb_timer); } }
static int nr_stun_client_send_request(nr_stun_client_ctx *ctx) { int r,_status; char string[256]; if (ctx->state != NR_STUN_CLIENT_STATE_RUNNING) ABORT(R_NOT_PERMITTED); r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Sending check request (my_addr=%s,peer_addr=%s)",ctx->label,ctx->my_addr.as_string,ctx->peer_addr.as_string); if (ctx->request == 0) { switch (ctx->mode) { case NR_STUN_CLIENT_MODE_BINDING_REQUEST_LONG_TERM_AUTH: ctx->params.stun_binding_request.nonce = ctx->nonce; ctx->params.stun_binding_request.realm = ctx->realm; assert(0); ABORT(R_INTERNAL); /* TODO([email protected]): Need to implement long-term auth for binding requests */ if ((r=nr_stun_build_req_lt_auth(&ctx->params.stun_binding_request, &ctx->request))) ABORT(r); break; case NR_STUN_CLIENT_MODE_BINDING_REQUEST_SHORT_TERM_AUTH: if ((r=nr_stun_build_req_st_auth(&ctx->params.stun_binding_request, &ctx->request))) ABORT(r); break; case NR_STUN_CLIENT_MODE_BINDING_REQUEST_NO_AUTH: if ((r=nr_stun_build_req_no_auth(&ctx->params.stun_binding_request, &ctx->request))) ABORT(r); break; case NR_STUN_CLIENT_MODE_KEEPALIVE: if ((r=nr_stun_build_keepalive(&ctx->params.stun_keepalive, &ctx->request))) ABORT(r); break; #ifdef USE_STUND_0_96 case NR_STUN_CLIENT_MODE_BINDING_REQUEST_STUND_0_96: if ((r=nr_stun_build_req_stund_0_96(&ctx->params.stun_binding_request_stund_0_96, &ctx->request))) ABORT(r); break; #endif /* USE_STUND_0_96 */ #ifdef USE_ICE case NR_ICE_CLIENT_MODE_USE_CANDIDATE: if ((r=nr_stun_build_use_candidate(&ctx->params.ice_binding_request, &ctx->request))) ABORT(r); break; case NR_ICE_CLIENT_MODE_BINDING_REQUEST: if ((r=nr_stun_build_req_ice(&ctx->params.ice_binding_request, &ctx->request))) ABORT(r); break; #endif /* USE_ICE */ #ifdef USE_TURN case NR_TURN_CLIENT_MODE_ALLOCATE_REQUEST: if ((r=nr_stun_build_allocate_request(&ctx->auth_params, &ctx->params.allocate_request, &ctx->request))) ABORT(r); break; case NR_TURN_CLIENT_MODE_REFRESH_REQUEST: if ((r=nr_stun_build_refresh_request(&ctx->auth_params, &ctx->params.refresh_request, &ctx->request))) ABORT(r); break; case NR_TURN_CLIENT_MODE_PERMISSION_REQUEST: if ((r=nr_stun_build_permission_request(&ctx->auth_params, &ctx->params.permission_request, &ctx->request))) ABORT(r); break; case NR_TURN_CLIENT_MODE_SEND_INDICATION: if ((r=nr_stun_build_send_indication(&ctx->params.send_indication, &ctx->request))) ABORT(r); break; #endif /* USE_TURN */ default: assert(0); ABORT(R_FAILED); break; } } if (ctx->request->length == 0) { if ((r=nr_stun_encode_message(ctx->request))) ABORT(r); } snprintf(string, sizeof(string)-1, "STUN-CLIENT(%s): Sending to %s ", ctx->label, ctx->peer_addr.as_string); r_dump(NR_LOG_STUN, LOG_DEBUG, string, (char*)ctx->request->buffer, ctx->request->length); assert(ctx->my_addr.protocol==ctx->peer_addr.protocol); if(r=nr_socket_sendto(ctx->sock, ctx->request->buffer, ctx->request->length, 0, &ctx->peer_addr)) ABORT(r); ctx->request_ct++; if (NR_STUN_GET_TYPE_CLASS(ctx->request->header.type) == NR_CLASS_INDICATION) { /* no need to set the timer because indications don't receive a * response */ } else { if (ctx->request_ct >= ctx->maximum_transmits) { /* Reliable transport only get here once. Unreliable get here for * their final timeout. */ ctx->timeout_ms += ctx->maximum_transmits_timeout_ms; } else if (ctx->timeout_ms) { /* exponential backoff */ ctx->timeout_ms *= ctx->retransmission_backoff_factor; } else { /* initial timeout unreliable transports */ ctx->timeout_ms = ctx->rto_ms; } r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Next timer will fire in %u ms",ctx->label, ctx->timeout_ms); gettimeofday(&ctx->timer_set, 0); assert(ctx->timeout_ms); NR_ASYNC_TIMER_SET(ctx->timeout_ms, nr_stun_client_timer_expired_cb, ctx, &ctx->timer_handle); } _status=0; abort: if (_status) { nr_stun_client_failed(ctx); } return(_status); }
int TestNrSocket::sendto(const void *msg, size_t len, int flags, nr_transport_addr *to) { MOZ_ASSERT(internal_socket_->my_addr().protocol != IPPROTO_TCP); UCHAR *buf = static_cast<UCHAR*>(const_cast<void*>(msg)); if (nat_->block_stun_ && nr_is_stun_message(buf, len)) { return 0; } /* TODO: improve the functionality of this in bug 1253657 */ if (!nat_->enabled_ || nat_->is_an_internal_tuple(*to)) { if (nat_->delay_stun_resp_ms_ && nr_is_stun_response_message(buf, len)) { NR_ASYNC_TIMER_SET(nat_->delay_stun_resp_ms_, process_delayed_cb, new DeferredPacket(this, msg, len, flags, to, internal_socket_), &timer_handle_); return 0; } return internal_socket_->sendto(msg, len, flags, to); } destroy_stale_port_mappings(); if (to->protocol == IPPROTO_UDP && nat_->block_udp_) { // Silently eat the packet return 0; } // Choose our port mapping based on our most selective criteria PortMapping *port_mapping = get_port_mapping(*to, std::max(nat_->filtering_type_, nat_->mapping_type_)); if (!port_mapping) { // See if we have already made the external socket we need to use. PortMapping *similar_port_mapping = get_port_mapping(*to, nat_->mapping_type_); RefPtr<NrSocketBase> external_socket; if (similar_port_mapping) { external_socket = similar_port_mapping->external_socket_; } else { external_socket = create_external_socket(*to); if (!external_socket) { MOZ_ASSERT(false); return R_INTERNAL; } } port_mapping = create_port_mapping(*to, external_socket); port_mappings_.push_back(port_mapping); if (poll_flags() & PR_POLL_READ) { // Make sure the new port mapping is ready to receive traffic if the // TestNrSocket is already waiting. port_mapping->async_wait(NR_ASYNC_WAIT_READ, socket_readable_callback, this, (char*)__FUNCTION__, __LINE__); } } // We probably don't want to propagate the flags, since this is a simulated // external IP address. return port_mapping->sendto(msg, len, *to); }
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){ r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/CAND-PAIR(%s): detected role conflict. Switching to controlled",pair->pctx->label,pair->codeword); pair->pctx->controlling=0; /* Only restart if we haven't tried this already */ if(!pair->restart_controlled_cb_timer) NR_ASYNC_TIMER_SET(0,nr_ice_candidate_pair_restart_stun_controlled_cb,pair,&pair->restart_controlled_cb_timer); 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_candidate_pair_insert(&pair->remote->stream->check_list,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; }
static int nr_stun_client_send_request(nr_stun_client_ctx *ctx) { int r,_status; char string[256]; if (ctx->state != NR_STUN_CLIENT_STATE_RUNNING) ABORT(R_NOT_PERMITTED); r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Sending(my_addr=%s,peer_addr=%s)",ctx->label,ctx->my_addr.as_string,ctx->peer_addr.as_string); if (ctx->request == 0) { switch (ctx->mode) { case NR_STUN_CLIENT_MODE_BINDING_REQUEST_LONG_TERM_AUTH: ctx->params.stun_binding_request.nonce = ctx->nonce; ctx->params.stun_binding_request.realm = ctx->realm; if ((r=nr_stun_build_req_lt_auth(&ctx->params.stun_binding_request, &ctx->request))) ABORT(r); break; case NR_STUN_CLIENT_MODE_BINDING_REQUEST_SHORT_TERM_AUTH: if ((r=nr_stun_build_req_st_auth(&ctx->params.stun_binding_request, &ctx->request))) ABORT(r); break; case NR_STUN_CLIENT_MODE_BINDING_REQUEST_NO_AUTH: if ((r=nr_stun_build_req_no_auth(&ctx->params.stun_binding_request, &ctx->request))) ABORT(r); break; case NR_STUN_CLIENT_MODE_KEEPALIVE: if ((r=nr_stun_build_keepalive(&ctx->params.stun_keepalive, &ctx->request))) ABORT(r); break; #ifdef USE_STUND_0_96 case NR_STUN_CLIENT_MODE_BINDING_REQUEST_STUND_0_96: if ((r=nr_stun_build_req_stund_0_96(&ctx->params.stun_binding_request_stund_0_96, &ctx->request))) ABORT(r); break; #endif /* USE_STUND_0_96 */ #ifdef USE_ICE case NR_ICE_CLIENT_MODE_USE_CANDIDATE: if ((r=nr_stun_build_use_candidate(&ctx->params.ice_use_candidate, &ctx->request))) ABORT(r); break; case NR_ICE_CLIENT_MODE_BINDING_REQUEST: if ((r=nr_stun_build_req_ice(&ctx->params.ice_binding_request, &ctx->request))) ABORT(r); break; #endif /* USE_ICE */ #ifdef USE_TURN case NR_TURN_CLIENT_MODE_ALLOCATE_REQUEST1: if ((r=nr_stun_build_allocate_request1(&ctx->params.allocate_request1, &ctx->request))) ABORT(r); break; case NR_TURN_CLIENT_MODE_ALLOCATE_REQUEST2: if ((r=nr_stun_build_allocate_request2(&ctx->params.allocate_request2, &ctx->request))) ABORT(r); break; case NR_TURN_CLIENT_MODE_SEND_INDICATION: if ((r=nr_stun_build_send_indication(&ctx->params.send_indication, &ctx->request))) ABORT(r); break; case NR_TURN_CLIENT_MODE_SET_ACTIVE_DEST_REQUEST: if ((r=nr_stun_build_set_active_dest_request(&ctx->params.set_active_dest_request, &ctx->request))) ABORT(r); break; case NR_TURN_CLIENT_MODE_DATA_INDICATION: if ((r=nr_stun_build_data_indication(&ctx->params.data_indication, &ctx->request))) ABORT(r); break; #endif /* USE_TURN */ default: assert(0); ABORT(R_FAILED); break; } } if (ctx->request->length == 0) { if ((r=nr_stun_encode_message(ctx->request))) ABORT(r); } snprintf(string, sizeof(string)-1, "STUN-CLIENT(%s): Sending to %s ", ctx->label, ctx->peer_addr.as_string); r_dump(NR_LOG_STUN, LOG_DEBUG, string, (char*)ctx->request->buffer, ctx->request->length); if(r=nr_socket_sendto(ctx->sock, ctx->request->buffer, ctx->request->length, 0, &ctx->peer_addr)) ABORT(r); ctx->request_ct++; if (NR_STUN_GET_TYPE_CLASS(ctx->request->header.type) == NR_CLASS_INDICATION) { /* no need to set the timer because indications don't receive a * response */ } else { if (ctx->request_ct < ctx->maximum_transmits) { ctx->timeout_ms *= ctx->retransmission_backoff_factor; ctx->timeout_ms += ctx->rto_ms; } else { ctx->timeout_ms += ctx->final_retransmit_backoff_ms; } r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Next timer will fire in %u ms",ctx->label, ctx->timeout_ms); gettimeofday(&ctx->timer_set, 0); NR_ASYNC_TIMER_SET(ctx->timeout_ms, nr_stun_client_timer_expired_cb, ctx, &ctx->timer_handle); } _status=0; abort: if (_status) { ctx->state=NR_STUN_CLIENT_STATE_FAILED; } return(_status); }