Beispiel #1
0
static int destroy_test(pj_stun_config  *stun_cfg,
			pj_bool_t with_dns_srv,
			pj_bool_t in_callback)
{
    struct test_session_cfg test_cfg = 
    {
	{   /* Client cfg */
	    /* DNS SRV */   /* Destroy on state */
	    PJ_TRUE,	    0xFFFF
	},
	{   /* Server cfg */
	    0xFFFFFFFF,	    /* flags */
	    PJ_TRUE,	    /* respond to allocate  */
	    PJ_TRUE	    /* respond to refresh   */
	}
    };
    struct test_session *sess;
    int target_state;
    int rc;

    PJ_LOG(3,("", "  destroy test %s %s",
	          (in_callback? "in callback" : ""),
		  (with_dns_srv? "with DNS srv" : "")
		  ));

    test_cfg.client.enable_dns_srv = with_dns_srv;

    for (target_state=PJ_TURN_STATE_RESOLVING; target_state<=PJ_TURN_STATE_READY; ++target_state) {
	enum { TIMEOUT = 60 };
	pjlib_state pjlib_state;
	pj_turn_session_info info;
	pj_time_val tstart;

	capture_pjlib_state(stun_cfg, &pjlib_state);

	PJ_LOG(3,("", "   %s", pj_turn_state_name((pj_turn_state_t)target_state)));

	if (in_callback)
	    test_cfg.client.destroy_on_state = target_state;

	rc = create_test_session(stun_cfg, &test_cfg, &sess);
	if (rc != 0)
	    return rc;

	if (in_callback) {
	    pj_gettimeofday(&tstart);
	    rc = 0;
	    while (sess->turn_sock) {
		pj_time_val now;

		poll_events(stun_cfg, 100, PJ_FALSE);

		pj_gettimeofday(&now);
		if (now.sec - tstart.sec > TIMEOUT) {
		    rc = -7;
		    break;
		}
	    }

	} else {
	    pj_gettimeofday(&tstart);
	    rc = 0;
	    while (sess->turn_sock) {
		pj_time_val now;

		poll_events(stun_cfg, 1, PJ_FALSE);

		pj_turn_sock_get_info(sess->turn_sock, &info);
		
		if (info.state >= target_state) {
		    pj_turn_sock_destroy(sess->turn_sock);
		    break;
		}

		pj_gettimeofday(&now);
		if (now.sec - tstart.sec > TIMEOUT) {
		    rc = -8;
		    break;
		}
	    }
	}


	if (rc != 0) {
	    PJ_LOG(3,("", "    error: timeout"));
	    return rc;
	}

	poll_events(stun_cfg, 1000, PJ_FALSE);
	destroy_session(sess);

	rc = check_pjlib_state(stun_cfg, &pjlib_state);
	if (rc != 0) {
	    PJ_LOG(3,("", "    error: memory/timer-heap leak detected"));
	    return rc;
	}
    }

    return 0;
}
Beispiel #2
0
static int perform_test(const char *title,
			pj_stun_config *stun_cfg,
			unsigned server_flag,
		        struct test_cfg *caller_cfg,
		        struct test_cfg *callee_cfg)
{
    pjlib_state pjlib_state;
    struct test_sess *sess;
    int rc;

    PJ_LOG(3,("", INDENT "%s", title));

    capture_pjlib_state(stun_cfg, &pjlib_state);

    rc = create_sess(stun_cfg, server_flag, caller_cfg, callee_cfg, &sess);
    if (rc != 0)
	return rc;

#define ALL_READY   (sess->caller.result.init_status!=PJ_EPENDING && \
		     sess->callee.result.init_status!=PJ_EPENDING)

    /* Wait until both ICE transports are initialized */
    WAIT_UNTIL(30, ALL_READY, rc);

    if (!ALL_READY) {
	PJ_LOG(3,("", INDENT "err: init timed-out"));
	destroy_sess(sess, 500);
	return -100;
    }

    if (sess->caller.result.init_status != sess->caller.cfg.expected.init_status) {
	app_perror(INDENT "err: caller init", sess->caller.result.init_status);
	destroy_sess(sess, 500);
	return -102;
    }
    if (sess->callee.result.init_status != sess->callee.cfg.expected.init_status) {
	app_perror(INDENT "err: callee init", sess->callee.result.init_status);
	destroy_sess(sess, 500);
	return -104;
    }

    /* Failure condition */
    if (sess->caller.result.init_status != PJ_SUCCESS ||
	sess->callee.result.init_status != PJ_SUCCESS)
    {
	rc = 0;
	goto on_return;
    }

    /* Init ICE on caller */
    rc = pj_ice_strans_init_ice(sess->caller.ice, sess->caller.cfg.role, 
				&sess->caller.ufrag, &sess->caller.pass);
    if (rc != PJ_SUCCESS) {
	app_perror(INDENT "err: caller pj_ice_strans_init_ice()", rc);
	destroy_sess(sess, 500);
	return -100;
    }

    /* Init ICE on callee */
    rc = pj_ice_strans_init_ice(sess->callee.ice, sess->callee.cfg.role, 
				&sess->callee.ufrag, &sess->callee.pass);
    if (rc != PJ_SUCCESS) {
	app_perror(INDENT "err: callee pj_ice_strans_init_ice()", rc);
	destroy_sess(sess, 500);
	return -110;
    }

    /* Start ICE on callee */
    rc = start_ice(&sess->callee, &sess->caller);
    if (rc != PJ_SUCCESS) {
	destroy_sess(sess, 500);
	return -120;
    }

    /* Wait for callee's answer_delay */
    poll_events(stun_cfg, sess->callee.cfg.answer_delay, PJ_FALSE);

    /* Start ICE on caller */
    rc = start_ice(&sess->caller, &sess->callee);
    if (rc != PJ_SUCCESS) {
	destroy_sess(sess, 500);
	return -130;
    }

    /* Wait until negotiation is complete on both endpoints */
#define ALL_DONE    (sess->caller.result.nego_status!=PJ_EPENDING && \
		     sess->callee.result.nego_status!=PJ_EPENDING)
    WAIT_UNTIL(30, ALL_DONE, rc);

    if (!ALL_DONE) {
	PJ_LOG(3,("", INDENT "err: negotiation timed-out"));
	destroy_sess(sess, 500);
	return -140;
    }

    if (sess->caller.result.nego_status != sess->caller.cfg.expected.nego_status) {
	app_perror(INDENT "err: caller negotiation failed", sess->caller.result.nego_status);
	destroy_sess(sess, 500);
	return -150;
    }

    if (sess->callee.result.nego_status != sess->callee.cfg.expected.nego_status) {
	app_perror(INDENT "err: callee negotiation failed", sess->callee.result.nego_status);
	destroy_sess(sess, 500);
	return -160;
    }

    /* Verify that both agents have agreed on the same pair */
    rc = check_pair(&sess->caller, &sess->callee, -170);
    if (rc != 0) {
	destroy_sess(sess, 500);
	return rc;
    }
    rc = check_pair(&sess->callee, &sess->caller, -180);
    if (rc != 0) {
	destroy_sess(sess, 500);
	return rc;
    }

    /* Looks like everything is okay */

    /* Destroy ICE stream transports first to let it de-allocate
     * TURN relay (otherwise there'll be timer/memory leak, unless
     * we wait for long time in the last poll_events() below).
     */
    if (sess->caller.ice) {
	pj_ice_strans_destroy(sess->caller.ice);
	sess->caller.ice = NULL;
    }

    if (sess->callee.ice) {
	pj_ice_strans_destroy(sess->callee.ice);
	sess->callee.ice = NULL;
    }

on_return:
    /* Wait.. */
    poll_events(stun_cfg, 500, PJ_FALSE);

    /* Now destroy everything */
    destroy_sess(sess, 500);

    /* Flush events */
    poll_events(stun_cfg, 100, PJ_FALSE);

    rc = check_pjlib_state(stun_cfg, &pjlib_state);
    if (rc != 0) {
	return rc;
    }

    return 0;
}
Beispiel #3
0
static int state_progression_test(pj_stun_config  *stun_cfg)
{
    struct test_session_cfg test_cfg = 
    {
	{   /* Client cfg */
	    /* DNS SRV */   /* Destroy on state */
	    PJ_TRUE,	    0xFFFF
	},
	{   /* Server cfg */
	    0xFFFFFFFF,	    /* flags */
	    PJ_TRUE,	    /* respond to allocate  */
	    PJ_TRUE	    /* respond to refresh   */
	}
    };
    struct test_session *sess;
    unsigned i;
    int rc;

    PJ_LOG(3,("", "  state progression tests"));

    for (i=0; i<=1; ++i) {
	enum { TIMEOUT = 60 };
	pjlib_state pjlib_state;
	pj_turn_session_info info;
	struct test_result result;
	pj_time_val tstart;

	PJ_LOG(3,("", "   %s DNS SRV resolution",
	              (i==0? "without" : "with")));

	capture_pjlib_state(stun_cfg, &pjlib_state);

	test_cfg.client.enable_dns_srv = i;

	rc = create_test_session(stun_cfg, &test_cfg, &sess);
	if (rc != 0)
	    return rc;

	pj_bzero(&info, sizeof(info));

	/* Wait until state is READY */
	pj_gettimeofday(&tstart);
	while (sess->turn_sock) {
	    pj_time_val now;

	    poll_events(stun_cfg, 10, PJ_FALSE);
	    rc = pj_turn_sock_get_info(sess->turn_sock, &info);
	    if (rc!=PJ_SUCCESS)
		break;

	    if (info.state >= PJ_TURN_STATE_READY)
		break;

	    pj_gettimeofday(&now);
	    if (now.sec - tstart.sec > TIMEOUT) {
		PJ_LOG(3,("", "    timed-out"));
		break;
	    }
	}

	if (info.state != PJ_TURN_STATE_READY) {
	    PJ_LOG(3,("", "    error: state is not READY"));
	    destroy_session(sess);
	    return -130;
	}

	/* Deallocate */
	pj_turn_sock_destroy(sess->turn_sock);

	/* Wait for couple of seconds.
	 * We can't poll the session info since the session may have
	 * been destroyed
	 */
	poll_events(stun_cfg, 2000, PJ_FALSE);
	sess->turn_sock = NULL;
	pj_memcpy(&result, &sess->result, sizeof(result));
	destroy_session(sess);

	/* Check the result */
	if ((result.state_called & (1<<PJ_TURN_STATE_RESOLVING)) == 0) {
	    PJ_LOG(3,("", "    error: PJ_TURN_STATE_RESOLVING is not called"));
	    return -140;
	}

	if ((result.state_called & (1<<PJ_TURN_STATE_RESOLVED)) == 0) {
	    PJ_LOG(3,("", "    error: PJ_TURN_STATE_RESOLVED is not called"));
	    return -150;
	}

	if ((result.state_called & (1<<PJ_TURN_STATE_ALLOCATING)) == 0) {
	    PJ_LOG(3,("", "    error: PJ_TURN_STATE_ALLOCATING is not called"));
	    return -155;
	}

	if ((result.state_called & (1<<PJ_TURN_STATE_READY)) == 0) {
	    PJ_LOG(3,("", "    error: PJ_TURN_STATE_READY is not called"));
	    return -160;
	}

	if ((result.state_called & (1<<PJ_TURN_STATE_DEALLOCATING)) == 0) {
	    PJ_LOG(3,("", "    error: PJ_TURN_STATE_DEALLOCATING is not called"));
	    return -170;
	}

	if ((result.state_called & (1<<PJ_TURN_STATE_DEALLOCATED)) == 0) {
	    PJ_LOG(3,("", "    error: PJ_TURN_STATE_DEALLOCATED is not called"));
	    return -180;
	}

	if ((result.state_called & (1<<PJ_TURN_STATE_DESTROYING)) == 0) {
	    PJ_LOG(3,("", "    error: PJ_TURN_STATE_DESTROYING is not called"));
	    return -190;
	}

	poll_events(stun_cfg, 500, PJ_FALSE);
	rc = check_pjlib_state(stun_cfg, &pjlib_state);
	if (rc != 0) {
	    PJ_LOG(3,("", "    error: memory/timer-heap leak detected"));
	    return rc;
	}
    }

    return 0;
}
Beispiel #4
0
static int perform_test2(const char *title,
			 pj_stun_config *stun_cfg,
                         unsigned server_flag,
		         struct test_cfg *caller_cfg,
		         struct test_cfg *callee_cfg,
		         struct sess_param *test_param)
{
    pjlib_state pjlib_state;
    struct test_sess *sess;
    unsigned i;
    int rc;

    PJ_LOG(3,(THIS_FILE, INDENT "%s", title));

    capture_pjlib_state(stun_cfg, &pjlib_state);

    rc = create_sess(stun_cfg, server_flag, caller_cfg, callee_cfg, test_param, &sess);
    if (rc != 0)
	return rc;

#define ALL_READY   (sess->caller.result.init_status!=PJ_EPENDING && \
		     sess->callee.result.init_status!=PJ_EPENDING)

    /* Wait until both ICE transports are initialized */
    WAIT_UNTIL(30000, ALL_READY, rc);

    if (!ALL_READY) {
	PJ_LOG(3,(THIS_FILE, INDENT "err: init timed-out"));
	destroy_sess(sess, 500);
	return -100;
    }

    if (sess->caller.result.init_status != sess->caller.cfg.expected.init_status) {
	app_perror(INDENT "err: caller init", sess->caller.result.init_status);
	destroy_sess(sess, 500);
	return -102;
    }
    if (sess->callee.result.init_status != sess->callee.cfg.expected.init_status) {
	app_perror(INDENT "err: callee init", sess->callee.result.init_status);
	destroy_sess(sess, 500);
	return -104;
    }

    /* Failure condition */
    if (sess->caller.result.init_status != PJ_SUCCESS ||
	sess->callee.result.init_status != PJ_SUCCESS)
    {
	rc = 0;
	goto on_return;
    }
    /* Init ICE on caller */
    rc = pj_ice_strans_init_ice(sess->caller.ice, sess->caller.cfg.role, 
				&sess->caller.ufrag, &sess->caller.pass);
    if (rc != PJ_SUCCESS) {
	app_perror(INDENT "err: caller pj_ice_strans_init_ice()", rc);
	destroy_sess(sess, 500);
	return -100;
    }

    /* Init ICE on callee */
    rc = pj_ice_strans_init_ice(sess->callee.ice, sess->callee.cfg.role, 
				&sess->callee.ufrag, &sess->callee.pass);
    if (rc != PJ_SUCCESS) {
	app_perror(INDENT "err: callee pj_ice_strans_init_ice()", rc);
	destroy_sess(sess, 500);
	return -110;
    }
    /* Start ICE on callee */
    rc = start_ice(&sess->callee, &sess->caller);
    if (rc != PJ_SUCCESS) {
	destroy_sess(sess, 500);
	return -120;
    }
    /* Wait for callee's answer_delay */
    poll_events(stun_cfg, sess->callee.cfg.answer_delay, PJ_FALSE);
    /* Start ICE on caller */
    rc = start_ice(&sess->caller, &sess->callee);
    if (rc != PJ_SUCCESS) {
	destroy_sess(sess, 500);
	return -130;
    }

    for (i=0; i<sess->param->worker_cnt; ++i) {
	pj_status_t status;

	status = pj_thread_create(sess->pool, "worker_thread",
				  worker_thread_proc, sess, 0, 0,
				  &sess->worker_threads[i]);
	if (status != PJ_SUCCESS) {
	    PJ_LOG(3,(THIS_FILE, INDENT "err: create thread"));
	    destroy_sess(sess, 500);
	    return -135;
	}
    }

    if (sess->param->destroy_after_create)
	goto on_destroy;

    if (sess->param->destroy_after_one_done) {
	while (sess->caller.result.init_status==PJ_EPENDING &&
	       sess->callee.result.init_status==PJ_EPENDING)
	{
	    if (sess->param->worker_cnt)
		pj_thread_sleep(0);
	    else
		poll_events(stun_cfg, 0, PJ_FALSE);
	}
	goto on_destroy;
    }
    
    WAIT_UNTIL(30000, ALL_DONE, rc);
    if (!ALL_DONE) {
	PJ_LOG(3,(THIS_FILE, INDENT "err: negotiation timed-out"));
	destroy_sess(sess, 500);
	return -140;
    }

    if (sess->caller.result.nego_status != sess->caller.cfg.expected.nego_status) {
	app_perror(INDENT "err: caller negotiation failed", sess->caller.result.nego_status);
	destroy_sess(sess, 500);
	return -150;
    }

    if (sess->callee.result.nego_status != sess->callee.cfg.expected.nego_status) {
	app_perror(INDENT "err: callee negotiation failed", sess->callee.result.nego_status);
	destroy_sess(sess, 500);
	return -160;
    }

    /* Verify that both agents have agreed on the same pair */
    rc = check_pair(&sess->caller, &sess->callee, -170);
    if (rc != 0) {
	destroy_sess(sess, 500);
	return rc;
    }
    rc = check_pair(&sess->callee, &sess->caller, -180);
    if (rc != 0) {
	destroy_sess(sess, 500);
	return rc;
    }

    /* Looks like everything is okay */
on_destroy:

    /* Destroy ICE stream transports first to let it de-allocate
     * TURN relay (otherwise there'll be timer/memory leak, unless
     * we wait for long time in the last poll_events() below).
     */
    if (sess->caller.ice) {
	pj_ice_strans_destroy(sess->caller.ice);
	sess->caller.ice = NULL;
    }

    if (sess->callee.ice) {
	pj_ice_strans_destroy(sess->callee.ice);
	sess->callee.ice = NULL;
    }

on_return:
    /* Wait.. */
    poll_events(stun_cfg, 200, PJ_FALSE);

    /* Now destroy everything */
    destroy_sess(sess, 500);

    /* Flush events */
    poll_events(stun_cfg, 100, PJ_FALSE);

    rc = check_pjlib_state(stun_cfg, &pjlib_state);
    if (rc != 0) {
	return rc;
    }

    return rc;
}