PJ_DEF(pj_status_t) pjsua_resolve_stun_servers( unsigned count,
						pj_str_t srv[],
						pj_bool_t wait,
						void *token,
						pj_stun_resolve_cb cb)
{
    pj_pool_t *pool;
    pjsua_stun_resolve *sess;
    pj_status_t status;
    unsigned i, max_wait_ms;
    pj_timestamp start, now;

    PJ_ASSERT_RETURN(count && srv && cb, PJ_EINVAL);

    pool = pjsua_pool_create("stunres", 256, 256);
    if (!pool)
	return PJ_ENOMEM;

    sess = PJ_POOL_ZALLOC_T(pool, pjsua_stun_resolve);
    sess->pool = pool;
    sess->token = token;
    sess->cb = cb;
    sess->count = count;
    sess->blocking = wait;
    sess->waiter = pj_thread_this();
    sess->status = PJ_EPENDING;
    sess->af = pj_AF_INET();
    stun_resolve_add_ref(sess);
    sess->srv = (pj_str_t*) pj_pool_calloc(pool, count, sizeof(pj_str_t));
    for (i=0; i<count; ++i) {
	pj_strdup(pool, &sess->srv[i], &srv[i]);
    }

    PJSUA_LOCK();
    pj_list_push_back(&pjsua_var.stun_res, sess);
    PJSUA_UNLOCK();

    resolve_stun_entry(sess);

    if (!wait)
	return PJ_SUCCESS;

    /* Should limit the wait time to avoid deadlock. For example,
     * if app holds dlg/tsx lock, pjsua worker thread will block on
     * any dlg/tsx state change.
     */
    max_wait_ms = count * pjsua_var.stun_cfg.rto_msec * (1 << 7);
    pj_get_timestamp(&start);
    
    while ((sess->status == PJ_EPENDING) && (!sess->destroy_flag)) {
        /* If there is no worker thread or
         * the function is called from the only worker thread,
         * we have to handle the events here.
         */
        if (pjsua_var.thread[0] == NULL ||
            (pj_thread_this() == pjsua_var.thread[0] &&
             pjsua_var.ua_cfg.thread_cnt == 1))
            {
            pjsua_handle_events(50);
        } else {
            pj_thread_sleep(20);
        }

	pj_get_timestamp(&now);
	if (pj_elapsed_msec(&start, &now) > max_wait_ms)
	    sess->status = PJ_ETIMEDOUT;
    }

    status = sess->status;
    stun_resolve_dec_ref(sess);

    return status;
}
PJ_DEF(pj_status_t) pjsua_resolve_stun_servers( unsigned count,
						pj_str_t srv[],
						pj_bool_t wait,
						void *token,
						pj_stun_resolve_cb cb)
{
    pj_pool_t *pool;
    pjsua_stun_resolve *sess;
    pj_status_t status;
    unsigned i, max_wait_ms;
    pj_timestamp start, now;

    PJ_ASSERT_RETURN(count && srv && cb, PJ_EINVAL);

    pool = pjsua_pool_create("stunres", 256, 256);
    if (!pool)
	return PJ_ENOMEM;

    sess = PJ_POOL_ZALLOC_T(pool, pjsua_stun_resolve);
    sess->pool = pool;
    sess->token = token;
    sess->cb = cb;
    sess->count = count;
    sess->blocking = wait;
    sess->waiter = pj_thread_this();
    sess->status = PJ_EPENDING;
    sess->af = pj_AF_INET();
    stun_resolve_add_ref(sess);
    sess->srv = (pj_str_t*) pj_pool_calloc(pool, count, sizeof(pj_str_t));
    for (i=0; i<count; ++i) {
	pj_strdup(pool, &sess->srv[i], &srv[i]);
    }

    PJSUA_LOCK();
    pj_list_push_back(&pjsua_var.stun_res, sess);
    PJSUA_UNLOCK();

    resolve_stun_entry(sess);

    if (!wait)
	return PJ_SUCCESS;

     
    max_wait_ms = count * pjsua_var.stun_cfg.rto_msec * (1 << 7);
    pj_get_timestamp(&start);
    
    while ((sess->status == PJ_EPENDING) && (!sess->destroy_flag)) {
         
        if (pjsua_var.thread[0] == NULL ||
            (pj_thread_this() == pjsua_var.thread[0] &&
             pjsua_var.ua_cfg.thread_cnt == 1))
            {
            pjsua_handle_events(50);
        } else {
            pj_thread_sleep(20);
        }

	pj_get_timestamp(&now);
	if (pj_elapsed_msec(&start, &now) > max_wait_ms)
	    sess->status = PJ_ETIMEDOUT;
    }

    status = sess->status;
    stun_resolve_dec_ref(sess);

    return status;
}