static void timeout(void *arg) { struct turnc *turnc = arg; int err; err = refresh_request(turnc, turnc->lifetime, true, refresh_resp_handler, turnc); if (err) turnc->th(err, 0, NULL, NULL, NULL, NULL, turnc->arg); }
static void destructor(void *arg) { struct turnc *turnc = arg; if (turnc->allocated) (void)refresh_request(turnc, 0, true, NULL, NULL); tmr_cancel(&turnc->tmr); mem_deref(turnc->ct); hash_flush(turnc->perms); mem_deref(turnc->perms); mem_deref(turnc->chans); mem_deref(turnc->username); mem_deref(turnc->password); mem_deref(turnc->nonce); mem_deref(turnc->realm); mem_deref(turnc->stun); mem_deref(turnc->uh); mem_deref(turnc->sock); }
static void refresh_resp_handler(int err, uint16_t scode, const char *reason, const struct stun_msg *msg, void *arg) { struct turnc *turnc = arg; struct stun_attr *ltm; if (err || turnc_request_loops(&turnc->ls, scode)) goto out; switch (scode) { case 0: ltm = stun_msg_attr(msg, STUN_ATTR_LIFETIME); if (ltm) turnc->lifetime = ltm->v.lifetime; refresh_timer(turnc); return; case 401: case 438: err = turnc_keygen(turnc, msg); if (err) break; err = refresh_request(turnc, turnc->lifetime, false, refresh_resp_handler, turnc); if (err) break; return; default: break; } out: turnc->th(err, scode, reason, NULL, NULL, msg, turnc->arg); }
static bool request_handler(struct restund_msgctx *ctx, int proto, void *sock, const struct sa *src, const struct sa *dst, const struct stun_msg *msg) { const uint16_t met = stun_msg_method(msg); struct allocation *al; int err = 0; switch (met) { case STUN_METHOD_ALLOCATE: case STUN_METHOD_REFRESH: case STUN_METHOD_CREATEPERM: case STUN_METHOD_CHANBIND: break; default: return false; } if (ctx->ua.typec > 0) { err = stun_ereply(proto, sock, src, 0, msg, 420, "Unknown Attribute", ctx->key, ctx->keylen, ctx->fp, 2, STUN_ATTR_UNKNOWN_ATTR, &ctx->ua, STUN_ATTR_SOFTWARE, restund_software); goto out; } al = allocation_find(proto, src, dst); if (!al && met != STUN_METHOD_ALLOCATE) { restund_debug("turn: allocation does not exist\n"); err = stun_ereply(proto, sock, src, 0, msg, 437, "Allocation Mismatch", ctx->key, ctx->keylen, ctx->fp, 1, STUN_ATTR_SOFTWARE, restund_software); goto out; } if (al && al->username && ctx->key) { struct stun_attr *usr = stun_msg_attr(msg, STUN_ATTR_USERNAME); if (!usr || strcmp(usr->v.username, al->username)) { restund_debug("turn: wrong credetials\n"); err = stun_ereply(proto, sock, src, 0, msg, 441, "Wrong Credentials", ctx->key, ctx->keylen, ctx->fp, 1, STUN_ATTR_SOFTWARE,restund_software); goto out; } } switch (met) { case STUN_METHOD_ALLOCATE: allocate_request(&turnd, al, ctx, proto, sock, src, dst, msg); break; case STUN_METHOD_REFRESH: refresh_request(&turnd, al, ctx, proto, sock, src, msg); break; case STUN_METHOD_CREATEPERM: createperm_request(al, ctx, proto, sock, src, msg); break; case STUN_METHOD_CHANBIND: chanbind_request(al, ctx, proto, sock, src, msg); break; } out: if (err) { restund_warning("turn reply error: %m\n", err); } return true; }
/* * Clean up the request list, every so often. * * This is done by walking through ALL of the list, and * - marking any requests which are finished, and expired * - killing any processes which are NOT finished after a delay * - deleting any marked requests. */ struct timeval *rl_clean_list(time_t now) { /* * Static variables, so that we don't do all of this work * more than once per second. * * Note that we have 'tv' and 'last_tv'. 'last_tv' is * pointed to by 'last_tv_ptr', and depending on the * system implementation of select(), it MAY be modified. * * In that was, we want to use the ORIGINAL value, from * 'tv', and wipe out the (possibly modified) last_tv. */ static time_t last_cleaned_list = 0; static struct timeval tv, *last_tv_ptr = NULL; static struct timeval last_tv; rl_walk_t info; info.now = now; info.smallest = -1; /* * If we've already set up the timeout or cleaned the * request list this second, then don't do it again. We * simply return the sleep delay from last time. * * Note that if we returned NULL last time, there was nothing * to do. BUT we've been woken up since then, which can only * happen if we received a packet. And if we've received a * packet, then there's some work to do in the future. * * FIXME: We can probably use gettimeofday() for finer clock * resolution, as the current method will cause it to sleep * too long... */ if ((last_tv_ptr != NULL) && (last_cleaned_list == now) && (tv.tv_sec != 0)) { int i; /* * If we're NOT walking the entire request list, * then we want to iteratively check the request * list. * * If there is NO previous request, go look for one. */ if (!last_request) last_request = rl_next(last_request); /* * On average, there will be one request per * 'cleanup_delay' requests, which needs to be * serviced. * * And only do this servicing, if we have a request * to service. */ if (last_request) for (i = 0; i < mainconfig.cleanup_delay; i++) { REQUEST *next; /* * This function call MAY delete the * request pointed to by 'last_request'. */ next = rl_next(last_request); refresh_request(last_request, &info); last_request = next; /* * Nothing to do any more, exit. */ if (!last_request) break; } last_tv = tv; DEBUG2("Waking up in %d seconds...", (int) last_tv_ptr->tv_sec); return last_tv_ptr; } last_cleaned_list = now; last_request = NULL; DEBUG2("--- Walking the entire request list ---"); /* * Hmmm... this is Big Magic. We make it seem like * there's an additional second to wait, for a whole * host of reasons which I can't explain adequately, * but which cause the code to Just Work Right. */ info.now--; rl_walk(refresh_request, &info); /* * We haven't found a time at which we need to wake up. * Return NULL, so that the select() call will sleep forever. */ if (info.smallest < 0) { /* * If we're not proxying, then there really isn't anything * to do. * * If we ARE proxying, then we can safely sleep * forever if we're told to NEVER send proxy retries * ourselves, until the NAS kicks us again. * * Otherwise, there are no outstanding requests, then * we can sleep forever. This happens when we get * woken up with a bad packet. It's discarded, so if * there are no live requests, we can safely sleep * forever. */ if ((!mainconfig.proxy_requests) || mainconfig.proxy_synchronous || (rl_num_requests() == 0)) { DEBUG2("Nothing to do. Sleeping until we see a request."); last_tv_ptr = NULL; return NULL; } /* * We ARE proxying. In that case, we avoid a race condition * where a child thread handling a request proxies the * packet, and sets the retry delay. In that case, we're * supposed to wake up in N seconds, but we can't, as * we're sleeping forever. * * Instead, we prevent the problem by waking up anyhow * at the 'proxy_retry_delay' time, even if there's * nothing to do. In the worst case, this will cause * the server to wake up every N seconds, to do a small * amount of unnecessary work. */ info.smallest = mainconfig.proxy_retry_delay; } /* * Set the time (in seconds) for how long we're * supposed to sleep. */ tv.tv_sec = info.smallest; tv.tv_usec = 0; DEBUG2("Waking up in %d seconds...", (int) info.smallest); /* * Remember how long we should sleep for. */ last_tv = tv; last_tv_ptr = &last_tv; return last_tv_ptr; }