static void nr_turn_client_connected_cb(NR_SOCKET s, int how, void *cb_arg) { int r, _status; nr_turn_client_ctx *ctx = (nr_turn_client_ctx *)cb_arg; /* Cancel the connection failure timer */ NR_async_timer_cancel(ctx->connected_timer_handle); ctx->connected_timer_handle=0; /* Assume we connected successfully */ if (ctx->state == NR_TURN_CLIENT_STATE_ALLOCATION_WAIT) { if ((r=nr_turn_stun_ctx_start(STAILQ_FIRST(&ctx->stun_ctxs)))) ABORT(r); ctx->state = NR_TURN_CLIENT_STATE_ALLOCATING; } else { ctx->state = NR_TURN_CLIENT_STATE_CONNECTED; } _status = 0; abort: if (_status) { nr_turn_client_failed(ctx); } }
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_turn_client_error_cb(NR_SOCKET s, int how, void *arg) { nr_turn_stun_ctx *ctx = (nr_turn_stun_ctx *)arg; r_log(NR_LOG_TURN, LOG_WARNING, "TURN(%s): mode %d, %s", ctx->tctx->label, ctx->mode, __FUNCTION__); nr_turn_client_failed(ctx->tctx); }
static void nr_turn_client_connect_timeout_cb(NR_SOCKET s, int how, void *cb_arg) { nr_turn_client_ctx *ctx = (nr_turn_client_ctx *)cb_arg; r_log(NR_LOG_TURN, LOG_INFO, "TURN(%s): connect timeout", ctx->label); ctx->connected_timer_handle = 0; /* This also cancels waiting on the file descriptor */ nr_turn_client_failed(ctx); }
int nr_turn_client_allocate(nr_turn_client_ctx *ctx, NR_async_cb finished_cb, void *cb_arg) { nr_turn_stun_ctx *stun = 0; int r,_status; if(ctx->state == NR_TURN_CLIENT_STATE_FAILED || ctx->state == NR_TURN_CLIENT_STATE_CANCELLED){ /* TURN TCP contexts can fail before we ever try to form an allocation, * since the TCP connection can fail. It is also conceivable that a TURN * TCP context could be cancelled before we are done forming all * allocations (although we do not do this at the time this code was * written) */ assert(ctx->turn_server_addr.protocol == IPPROTO_TCP); ABORT(R_NOT_FOUND); } assert(ctx->state == NR_TURN_CLIENT_STATE_INITTED); ctx->finished_cb=finished_cb; ctx->cb_arg=cb_arg; if ((r=nr_turn_stun_ctx_create(ctx, NR_TURN_CLIENT_MODE_ALLOCATE_REQUEST, nr_turn_client_allocate_cb, nr_turn_client_error_cb, &stun))) ABORT(r); stun->stun->params.allocate_request.lifetime_secs = TURN_LIFETIME_REQUEST_SECONDS; if (ctx->state == NR_TURN_CLIENT_STATE_INITTED) { if ((r=nr_turn_stun_ctx_start(stun))) ABORT(r); ctx->state = NR_TURN_CLIENT_STATE_ALLOCATING; } else { ABORT(R_ALREADY); } _status=0; abort: if (_status) { nr_turn_client_failed(ctx); } return(_status); }
static void nr_turn_client_allocate_cb(NR_SOCKET s, int how, void *arg) { nr_turn_stun_ctx *ctx = (nr_turn_stun_ctx *)arg; nr_turn_stun_ctx *refresh_ctx; NR_async_cb tmp_finished_cb; int r,_status; ctx->tctx->state = NR_TURN_CLIENT_STATE_ALLOCATED; if ((r=nr_transport_addr_copy( &ctx->tctx->relay_addr, &ctx->stun->results.allocate_response.relay_addr))) ABORT(r); if ((r=nr_transport_addr_copy( &ctx->tctx->mapped_addr, &ctx->stun->results.allocate_response.mapped_addr))) ABORT(r); if ((r=nr_turn_client_refresh_setup(ctx->tctx, &refresh_ctx))) ABORT(r); if ((r=nr_turn_client_start_refresh_timer( ctx->tctx, refresh_ctx, ctx->stun->results.allocate_response.lifetime_secs))) ABORT(r); r_log(NR_LOG_TURN, LOG_INFO, "TURN(%s): Succesfully allocated addr %s lifetime=%u", ctx->tctx->label, ctx->tctx->relay_addr.as_string, ctx->stun->results.allocate_response.lifetime_secs); _status=0; abort: if (_status) { nr_turn_client_failed(ctx->tctx); } tmp_finished_cb = ctx->tctx->finished_cb; ctx->tctx->finished_cb = 0; /* So we don't call it again */ tmp_finished_cb(0, 0, ctx->tctx->cb_arg); }
int nr_turn_client_allocate(nr_turn_client_ctx *ctx, NR_async_cb finished_cb, void *cb_arg) { nr_turn_stun_ctx *stun = 0; int r,_status; assert(ctx->state == NR_TURN_CLIENT_STATE_INITTED || ctx->state == NR_TURN_CLIENT_STATE_CONNECTED); ctx->finished_cb=finished_cb; ctx->cb_arg=cb_arg; if ((r=nr_turn_stun_ctx_create(ctx, NR_TURN_CLIENT_MODE_ALLOCATE_REQUEST, nr_turn_client_allocate_cb, nr_turn_client_error_cb, &stun))) ABORT(r); stun->stun->params.allocate_request.lifetime_secs = TURN_LIFETIME_REQUEST_SECONDS; switch(ctx->state) { case NR_TURN_CLIENT_STATE_INITTED: /* We are waiting for connect before we can allocate */ ctx->state = NR_TURN_CLIENT_STATE_ALLOCATION_WAIT; break; case NR_TURN_CLIENT_STATE_CONNECTED: if ((r=nr_turn_stun_ctx_start(stun))) ABORT(r); ctx->state = NR_TURN_CLIENT_STATE_ALLOCATING; break; default: ABORT(R_ALREADY); } _status=0; abort: if (_status) { nr_turn_client_failed(ctx); } return(_status); }
static void nr_turn_client_refresh_timer_cb(NR_SOCKET s, int how, void *arg) { nr_turn_stun_ctx *ctx = (nr_turn_stun_ctx *)arg; int r,_status; r_log(NR_LOG_TURN, LOG_DEBUG, "TURN(%s): Refresh timer fired", ctx->tctx->label); ctx->tctx->refresh_timer_handle=0; if ((r=nr_turn_stun_ctx_start(ctx))) { ABORT(r); } _status=0; abort: if (_status) { nr_turn_client_failed(ctx->tctx); } return; }
static void nr_turn_client_refresh_cb(NR_SOCKET s, int how, void *arg) { int r, _status; nr_turn_stun_ctx *ctx = (nr_turn_stun_ctx *)arg; /* Save lifetime from the reset */ UINT4 lifetime = ctx->stun->results.refresh_response.lifetime_secs; r_log(NR_LOG_TURN, LOG_DEBUG, "TURN(%s): Refresh succeeded. lifetime=%u", ctx->tctx->label, lifetime); if ((r=nr_turn_client_start_refresh_timer( ctx->tctx, ctx, lifetime))) ABORT(r); _status=0; abort: if (_status) { nr_turn_client_failed(ctx->tctx); } }