Exemple #1
0
pj_status_t create_stun_config(pj_pool_t *pool, pj_stun_config *stun_cfg)
{
    pj_ioqueue_t *ioqueue;
    pj_timer_heap_t *timer_heap;
    pj_lock_t *lock;
    pj_status_t status;

    status = pj_ioqueue_create(pool, 64, &ioqueue);
    if (status != PJ_SUCCESS) {
	app_perror("   pj_ioqueue_create()", status);
	return status;
    }

    status = pj_timer_heap_create(pool, 256, &timer_heap);
    if (status != PJ_SUCCESS) {
	app_perror("   pj_timer_heap_create()", status);
	pj_ioqueue_destroy(ioqueue);
	return status;
    }

    pj_lock_create_recursive_mutex(pool, NULL, &lock);
    pj_timer_heap_set_lock(timer_heap, lock, PJ_TRUE);

    pj_stun_config_init(stun_cfg, mem, 0, ioqueue, timer_heap);

    return PJ_SUCCESS;
}
Exemple #2
0
int stun_sock_test(void)
{
    struct pjlib_state pjlib_state;
    pj_stun_config stun_cfg;
    pj_ioqueue_t *ioqueue = NULL;
    pj_timer_heap_t *timer_heap = NULL;
    pj_pool_t *pool = NULL;
    pj_status_t status;
    int ret = 0;

    pool = pj_pool_create(mem, NULL, 512, 512, NULL);

    status = pj_ioqueue_create(pool, 12, &ioqueue);
    if (status != PJ_SUCCESS) {
	app_perror("   pj_ioqueue_create()", status);
	ret = -4;
	goto on_return;
    }

    status = pj_timer_heap_create(pool, 100, &timer_heap);
    if (status != PJ_SUCCESS) {
	app_perror("   pj_timer_heap_create()", status);
	ret = -8;
	goto on_return;
    }
    
    pj_stun_config_init(&stun_cfg, mem, 0, ioqueue, timer_heap);

    DO_TEST(timeout_test(&stun_cfg, PJ_FALSE));
    DO_TEST(timeout_test(&stun_cfg, PJ_TRUE));

    DO_TEST(missing_attr_test(&stun_cfg, PJ_FALSE));
    DO_TEST(missing_attr_test(&stun_cfg, PJ_TRUE));

    DO_TEST(keep_alive_test(&stun_cfg));

on_return:
    if (timer_heap) pj_timer_heap_destroy(timer_heap);
    if (ioqueue) pj_ioqueue_destroy(ioqueue);
    if (pool) pj_pool_release(pool);
    return ret;
}
Exemple #3
0
pj_status_t create_stun_config(pj_pool_t *pool, pj_stun_config *stun_cfg)
{
    pj_ioqueue_t *ioqueue;
    pj_timer_heap_t *timer_heap;
    pj_status_t status;

    status = pj_ioqueue_create(pool, 64, &ioqueue);
    if (status != PJ_SUCCESS) {
	app_perror("   pj_ioqueue_create()", status);
	return status;
    }

    status = pj_timer_heap_create(pool, 256, &timer_heap);
    if (status != PJ_SUCCESS) {
	app_perror("   pj_timer_heap_create()", status);
	pj_ioqueue_destroy(ioqueue);
	return status;
    }

    pj_stun_config_init(stun_cfg, mem, 0, ioqueue, timer_heap);

    return PJ_SUCCESS;
}
Exemple #4
0
int sess_auth_test(void)
{
    pj_pool_t *pool;
    int rc;

    PJ_LOG(3,(THIS_FILE, "  STUN session authentication test"));

    /* Init STUN config */
    pj_stun_config_init(0, &stun_cfg, mem, 0, NULL, NULL);

    /* Create pool and timer heap */
    pool = pj_pool_create(mem, "authtest", 200, 200, NULL);
    if (pj_timer_heap_create(pool, 20, &stun_cfg.timer_heap)) {
	pj_pool_release(pool);
	return -5;
    }

    /* Basic retransmission test */
    rc = run_client_test("Retransmission",  // title
			 PJ_FALSE,	    // server responding
			 PJ_STUN_AUTH_NONE, // server auth
			 PJ_STUN_AUTH_NONE, // client auth
			 NULL,		    // realm
			 NULL,		    // username
			 NULL,		    // nonce
			 NULL,		    // password
			 PJ_FALSE,	    // dummy MI
			 PJ_TRUE,	    // expected error
			 PJNATH_ESTUNTIMEDOUT,// expected code
			 NULL,		    // expected realm
			 NULL,		    // expected nonce
			 &retransmit_check  // more check
			 );
    if (rc != 0) {
	goto done;
    }

    /*
     * Short term credential.
     * draft-ietf-behave-rfc3489bis-15#section-10.1.2
     */

    /*
     * If the message does not contain both a MESSAGE-INTEGRITY and a
     * USERNAME attribute, If the message is a request, the server MUST
     * reject the request with an error response.  This response MUST
     * use an error code of 400 (Bad Request).
     */
    rc = run_client_test("Missing MESSAGE-INTEGRITY (short term)",  // title
			 PJ_TRUE,	    // server responding
			 PJ_STUN_AUTH_SHORT_TERM, // server auth
			 PJ_STUN_AUTH_NONE, // client auth
			 NULL,		    // realm
			 NULL,		    // username
			 NULL,		    // nonce
			 NULL,		    // password
			 PJ_FALSE,	    // dummy MI
			 PJ_TRUE,	    // expected error
			 PJ_STATUS_FROM_STUN_CODE(400),// expected code
			 NULL,		    // expected realm
			 NULL,		    // expected nonce
			 NULL		    // more check
			 );
    if (rc != 0) {
	goto done;
    }

    /* If the USERNAME does not contain a username value currently valid
     * within the server: If the message is a request, the server MUST 
     * reject the request with an error response.  This response MUST use
     * an error code of 401 (Unauthorized).
     */
    rc = run_client_test("USERNAME mismatch (short term)",  // title
			 PJ_TRUE,	    // server responding
			 PJ_STUN_AUTH_SHORT_TERM, // server auth
			 PJ_STUN_AUTH_SHORT_TERM, // client auth
			 NULL,		    // realm
			 "anotheruser",	    // username
			 NULL,		    // nonce
			 "anotherpass",	    // password
			 PJ_FALSE,	    // dummy MI
			 PJ_TRUE,	    // expected error
			 PJ_STATUS_FROM_STUN_CODE(401),// expected code
			 NULL,		    // expected realm
			 NULL,		    // expected nonce
			 NULL		    // more check
			 );
    if (rc != 0) {
	goto done;
    }

    /* Using the password associated with the username, compute the value
     * for the message-integrity as described in Section 15.4.  If the
     * resulting value does not match the contents of the MESSAGE-
     * INTEGRITY attribute:
     *
     * - If the message is a request, the server MUST reject the request
     *   with an error response.  This response MUST use an error code
     *   of 401 (Unauthorized).
     */
    rc = run_client_test("MESSAGE-INTEGRITY mismatch (short term)",  // title
			 PJ_TRUE,	    // server responding
			 PJ_STUN_AUTH_SHORT_TERM, // server auth
			 PJ_STUN_AUTH_SHORT_TERM, // client auth
			 NULL,		    // realm
			 USERNAME,	    // username
			 NULL,		    // nonce
			 "anotherpass",	    // password
			 PJ_FALSE,	    // dummy MI
			 PJ_TRUE,	    // expected error
			 PJ_STATUS_FROM_STUN_CODE(401),// expected code
			 NULL,		    // expected realm
			 NULL,		    // expected nonce
			 NULL		    // more check
			 );
    if (rc != 0) {
	goto done;
    }

    /* USERNAME is not present, server must respond with 400 (Bad
     * Request).
     */
    rc = run_client_test("Missing USERNAME (short term)",// title
			 PJ_TRUE,	    // server responding
			 PJ_STUN_AUTH_SHORT_TERM, // server auth
			 PJ_STUN_AUTH_NONE, // client auth
			 NULL,		    // realm
			 NULL,		    // username
			 NULL,		    // nonce
			 NULL,		    // password
			 PJ_TRUE,	    // dummy MI
			 PJ_TRUE,	    // expected error
			 PJ_STATUS_FROM_STUN_CODE(400),	    // expected code
			 NULL,		    // expected realm
			 NULL,		    // expected nonce
			 NULL		    // more check
			 );
    if (rc != 0) {
	goto done;
    }

    /* Successful short term authentication */
    rc = run_client_test("Successful scenario (short term)",  // title
			 PJ_TRUE,	    // server responding
			 PJ_STUN_AUTH_SHORT_TERM, // server auth
			 PJ_STUN_AUTH_SHORT_TERM, // client auth
			 NULL,		    // realm
			 USERNAME,	    // username
			 NULL,		    // nonce
			 PASSWORD,	    // password
			 PJ_FALSE,	    // dummy MI
			 PJ_FALSE,	    // expected error
			 PJ_SUCCESS,	    // expected code
			 NULL,		    // expected realm
			 NULL,		    // expected nonce
			 NULL		    // more check
			 );
    if (rc != 0) {
	goto done;
    }

    /*
     * (our own) Extended tests for long term credential
     */

    /* When server wants to use short term credential, but request has
     * REALM, reject with .... 401 ???
     */
    rc = run_client_test("Unwanted REALM (short term)",  // title
			 PJ_TRUE,	    // server responding
			 PJ_STUN_AUTH_SHORT_TERM, // server auth
			 PJ_STUN_AUTH_NONE, // client auth
			 REALM,		    // realm
			 USERNAME,	    // username
			 NULL,		    // nonce
			 PASSWORD,	    // password
			 PJ_TRUE,	    // dummy MI
			 PJ_TRUE,	    // expected error
			 PJ_STATUS_FROM_STUN_CODE(401),	    // expected code
			 NULL,		    // expected realm
			 NULL,		    // expected nonce
			 &long_term_check2  // more check
			 );
    if (rc != 0) {
	goto done;
    }


    /*
     * Long term credential.
     * draft-ietf-behave-rfc3489bis-15#section-10.2.2
     */

    /* If the message does not contain a MESSAGE-INTEGRITY attribute, the
     * server MUST generate an error response with an error code of 401
     * (Unauthorized).  This response MUST include a REALM value.  It is
     * RECOMMENDED that the REALM value be the domain name of the
     * provider of the STUN server.  The response MUST include a NONCE,
     * selected by the server.  The response SHOULD NOT contain a
     * USERNAME or MESSAGE-INTEGRITY attribute.
     */
    rc = run_client_test("Missing M-I (long term)",  // title
			 PJ_TRUE,	    // server responding
			 PJ_STUN_AUTH_LONG_TERM, // server auth
			 PJ_STUN_AUTH_NONE, // client auth
			 NULL,		    // client realm
			 NULL,		    // client username
			 NULL,		    // client nonce
			 NULL,		    // client password
			 PJ_FALSE,	    // client dummy MI
			 PJ_TRUE,	    // expected error
			 PJ_STATUS_FROM_STUN_CODE(401), // expected code
			 REALM,		    // expected realm
			 NONCE,		    // expected nonce
			 &long_term_check1  // more check
			 );
    if (rc != 0) {
	goto done;
    }

    /* If the message contains a MESSAGE-INTEGRITY attribute, but is
     * missing the USERNAME, REALM or NONCE attributes, the server MUST
     * generate an error response with an error code of 400 (Bad
     * Request).  This response SHOULD NOT include a USERNAME, NONCE,
     * REALM or MESSAGE-INTEGRITY attribute.
     */
    /* Missing USERNAME */
    rc = run_client_test("Missing USERNAME (long term)",  // title
			 PJ_TRUE,	    // server responding
			 PJ_STUN_AUTH_LONG_TERM, // server auth
			 PJ_STUN_AUTH_NONE, // client auth
			 REALM,		    // client realm
			 NULL,		    // client username
			 NONCE,		    // client nonce
			 PASSWORD,	    // client password
			 PJ_TRUE,	    // client dummy MI
			 PJ_TRUE,	    // expected error
			 PJ_STATUS_FROM_STUN_CODE(400), // expected code
			 NULL,		    // expected realm
			 NULL,		    // expected nonce
			 &long_term_check2  // more check
			 );
    if (rc != 0) {
	goto done;
    }

    /* Missing REALM */
    rc = run_client_test("Missing REALM (long term)",  // title
			 PJ_TRUE,	    // server responding
			 PJ_STUN_AUTH_LONG_TERM, // server auth
			 PJ_STUN_AUTH_NONE, // client auth
			 NULL,		    // client realm
			 USERNAME,	    // client username
			 NONCE,		    // client nonce
			 PASSWORD,	    // client password
			 PJ_TRUE,	    // client dummy MI
			 PJ_TRUE,	    // expected error
			 PJ_STATUS_FROM_STUN_CODE(400), // expected code
			 NULL,		    // expected realm
			 NULL,		    // expected nonce
			 &long_term_check2  // more check
			 );
    if (rc != 0) {
	goto done;
    }

    /* Missing NONCE */
    rc = run_client_test("Missing NONCE (long term)",  // title
			 PJ_TRUE,	    // server responding
			 PJ_STUN_AUTH_LONG_TERM, // server auth
			 PJ_STUN_AUTH_NONE, // client auth
			 REALM,		    // client realm
			 USERNAME,	    // client username
			 NULL,		    // client nonce
			 PASSWORD,	    // client password
			 PJ_TRUE,	    // client dummy MI
			 PJ_TRUE,	    // expected error
			 PJ_STATUS_FROM_STUN_CODE(400), // expected code
			 NULL,		    // expected realm
			 NULL,		    // expected nonce
			 &long_term_check2  // more check
			 );
    if (rc != 0) {
	goto done;
    }

    /* If the NONCE is no longer valid, the server MUST generate an error
     * response with an error code of 438 (Stale Nonce).  This response
     * MUST include a NONCE and REALM attribute and SHOULD NOT incude the
     * USERNAME or MESSAGE-INTEGRITY attribute.  Servers can invalidate
     * nonces in order to provide additional security.  See Section 4.3
     * of [RFC2617] for guidelines.    
     */
    // how??

    /* If the username in the USERNAME attribute is not valid, the server
     * MUST generate an error response with an error code of 401
     * (Unauthorized).  This response MUST include a REALM value.  It is
     * RECOMMENDED that the REALM value be the domain name of the
     * provider of the STUN server.  The response MUST include a NONCE,
     * selected by the server.  The response SHOULD NOT contain a
     * USERNAME or MESSAGE-INTEGRITY attribute.
     */
    rc = run_client_test("Invalid username (long term)",  // title
			 PJ_TRUE,	    // server responding
			 PJ_STUN_AUTH_LONG_TERM, // server auth
			 PJ_STUN_AUTH_LONG_TERM, // client auth
			 REALM,		    // client realm
			 "anotheruser",	    // client username
			 "a nonce",	    // client nonce
			 "somepassword",    // client password
			 PJ_FALSE,	    // client dummy MI
			 PJ_TRUE,	    // expected error
			 PJ_STATUS_FROM_STUN_CODE(401), // expected code
			 REALM,		    // expected realm
			 NONCE,		    // expected nonce
			 &long_term_check1  // more check
			 );
    if (rc != 0) {
	goto done;
    }

    /* Successful long term authentication */
    rc = run_client_test("Successful scenario (long term)",  // title
			 PJ_TRUE,	    // server responding
			 PJ_STUN_AUTH_LONG_TERM, // server auth
			 PJ_STUN_AUTH_LONG_TERM, // client auth
			 REALM,		    // client realm
			 USERNAME,	    // client username
			 "anothernonce",    // client nonce
			 PASSWORD,	    // client password
			 PJ_FALSE,	    // client dummy MI
			 PJ_FALSE,	    // expected error
			 0,		    // expected code
			 NULL,		    // expected realm
			 NULL,		    // expected nonce
			 &long_term_check3  // more check
			 );
    if (rc != 0) {
	goto done;
    }

    /*
     * (our own) Extended tests for long term credential
     */

    /* If REALM doesn't match, server must respond with 401
     */
#if 0
    // STUN session now will just use the realm sent in the
    // response, so this test will fail because it will
    // authenticate successfully.

    rc = run_client_test("Invalid REALM (long term)",  // title
			 PJ_TRUE,	    // server responding
			 PJ_STUN_AUTH_LONG_TERM, // server auth
			 PJ_STUN_AUTH_LONG_TERM, // client auth
			 "anotherrealm",    // client realm
			 USERNAME,	    // client username
			 NONCE,		    // client nonce
			 PASSWORD,	    // client password
			 PJ_FALSE,	    // client dummy MI
			 PJ_TRUE,	    // expected error
			 PJ_STATUS_FROM_STUN_CODE(401), // expected code
			 REALM,		    // expected realm
			 NONCE,		    // expected nonce
			 &long_term_check1  // more check
			 );
    if (rc != 0) {
	goto done;
    }
#endif

    /* Invalid HMAC */

    /* Valid static short term, without NONCE */

    /* Valid static short term, WITH NONCE */

    /* Valid static long term (with NONCE */

    /* Valid dynamic short term (without NONCE) */

    /* Valid dynamic short term (with NONCE) */

    /* Valid dynamic long term (with NONCE) */


done:
    pj_timer_heap_destroy(stun_cfg.timer_heap);
    pj_pool_release(pool);
    return rc;
}
Exemple #5
0
static int stun_destroy_test(void)
{
    enum { LOOP = 500 };
    struct stun_test_session test_sess;
    pj_sockaddr bind_addr;
    int addr_len;
    pj_caching_pool cp;
    pj_pool_t *pool;
    unsigned i;
    pj_status_t status;
    int rc = 0;

    PJ_LOG(3,(THIS_FILE, "  STUN destroy concurrency test"));

    pj_bzero(&test_sess, sizeof(test_sess));

    pj_caching_pool_init(&cp, NULL, 0);
    pool = pj_pool_create(&cp.factory, "testsess", 512, 512, NULL);

    pj_stun_config_init(&test_sess.stun_cfg, &cp.factory, 0, NULL, NULL);

    status = pj_timer_heap_create(pool, 1023, &test_sess.stun_cfg.timer_heap);
    pj_assert(status == PJ_SUCCESS);

    status = pj_lock_create_recursive_mutex(pool, NULL, &test_sess.lock);
    pj_assert(status == PJ_SUCCESS);

    pj_timer_heap_set_lock(test_sess.stun_cfg.timer_heap, test_sess.lock, PJ_TRUE);
    pj_assert(status == PJ_SUCCESS);

    status = pj_ioqueue_create(pool, 512, &test_sess.stun_cfg.ioqueue);
    pj_assert(status == PJ_SUCCESS);

    pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &test_sess.server_sock);
    pj_sockaddr_init(pj_AF_INET(), &bind_addr, NULL, 0);
    status = pj_sock_bind(test_sess.server_sock, &bind_addr, pj_sockaddr_get_len(&bind_addr));
    pj_assert(status == PJ_SUCCESS);

    addr_len = sizeof(bind_addr);
    status = pj_sock_getsockname(test_sess.server_sock, &bind_addr, &addr_len);
    pj_assert(status == PJ_SUCCESS);

    test_sess.server_port = pj_sockaddr_get_port(&bind_addr);

    status = pj_event_create(pool, NULL, PJ_TRUE, PJ_FALSE, &test_sess.server_event);
    pj_assert(status == PJ_SUCCESS);

    for (i=0; i<SERVER_THREAD_CNT; ++i) {
	status = pj_thread_create(pool, NULL,
	                          &server_thread_proc, &test_sess,
	                          0, 0, &test_sess.server_threads[i]);
	pj_assert(status == PJ_SUCCESS);
    }

    for (i=0; i<WORKER_THREAD_CNT; ++i) {
	status = pj_thread_create(pool, NULL,
	                          &worker_thread_proc, &test_sess,
	                          0, 0, &test_sess.worker_threads[i]);
	pj_assert(status == PJ_SUCCESS);
    }

    /* Test 1: Main thread calls destroy while callback is processing response */
    PJ_LOG(3,(THIS_FILE, "    Destroy in main thread while callback is running"));
    for (i=0; i<LOOP; ++i) {
	int sleep = pj_rand() % 5;

	PJ_LOG(3,(THIS_FILE, "      Try %-3d of %d", i+1, LOOP));

	/* Test 1: destroy at the same time when receiving response */
	pj_bzero(&test_sess.param, sizeof(test_sess.param));
	test_sess.param.client_sleep_after_start = 20;
	test_sess.param.client_sleep_before_destroy = sleep;
	test_sess.param.server_wait_for_event = PJ_TRUE;
	stun_destroy_test_session(&test_sess);
	PJ_LOG(3,(THIS_FILE,
		  "        stun test a: sleep delay:%d: clients with response: %d",
		  sleep, test_sess.param.client_got_response));

	/* Test 2: destroy at the same time with STUN retransmit timer */
	test_sess.param.server_drop_request = PJ_TRUE;
	test_sess.param.client_sleep_after_start = 0;
	test_sess.param.client_sleep_before_destroy = PJ_STUN_RTO_VALUE;
	test_sess.param.server_wait_for_event = PJ_FALSE;
	stun_destroy_test_session(&test_sess);
	PJ_LOG(3,(THIS_FILE, "        stun test b: retransmit concurrency"));

	/* Test 3: destroy at the same time with receiving response
	 * AND STUN retransmit timer */
	test_sess.param.client_got_response = 0;
	test_sess.param.server_drop_request = PJ_FALSE;
	test_sess.param.client_sleep_after_start = PJ_STUN_RTO_VALUE;
	test_sess.param.client_sleep_before_destroy = 0;
	test_sess.param.server_wait_for_event = PJ_TRUE;
	stun_destroy_test_session(&test_sess);
	PJ_LOG(3,(THIS_FILE,
		  "        stun test c: clients with response: %d",
		  test_sess.param.client_got_response));

	pj_thread_sleep(10);

	ice_one_conc_test(&test_sess.stun_cfg, PJ_FALSE);

	pj_thread_sleep(10);
    }

    /* Avoid compiler warning */
    goto on_return;


on_return:
    test_sess.thread_quit_flag = PJ_TRUE;

    for (i=0; i<SERVER_THREAD_CNT; ++i) {
	pj_thread_join(test_sess.server_threads[i]);
    }

    for (i=0; i<WORKER_THREAD_CNT; ++i) {
	pj_thread_join(test_sess.worker_threads[i]);
    }

    pj_event_destroy(test_sess.server_event);
    pj_sock_close(test_sess.server_sock);
    pj_ioqueue_destroy(test_sess.stun_cfg.ioqueue);
    pj_timer_heap_destroy(test_sess.stun_cfg.timer_heap);

    pj_pool_release(pool);
    pj_caching_pool_destroy(&cp);

    PJ_LOG(3,(THIS_FILE, "    Done. rc=%d", rc));
    return rc;
}
static int init()
{
    int i;
    pj_status_t status;

    CHECK( pj_init() );
    CHECK( pjlib_util_init() );
    CHECK( pjnath_init() );

    /* Check that server is specified */
    if (!o.srv_addr) {
	printf("Error: server must be specified\n");
	return PJ_EINVAL;
    }

    pj_caching_pool_init(&g.cp, &pj_pool_factory_default_policy, 0);

    g.pool = pj_pool_create(&g.cp.factory, "main", 1000, 1000, NULL);

    /* Init global STUN config */
    pj_stun_config_init(&g.stun_config, &g.cp.factory, 0, NULL, NULL);

    /* Create global timer heap */
    CHECK( pj_timer_heap_create(g.pool, 1000, &g.stun_config.timer_heap) );

    /* Create global ioqueue */
    CHECK( pj_ioqueue_create(g.pool, 16, &g.stun_config.ioqueue) );

    /* 
     * Create peers
     */
    for (i=0; i<(int)PJ_ARRAY_SIZE(g.peer); ++i) {
	pj_stun_sock_cb stun_sock_cb;
	char name[] = "peer0";
	pj_uint16_t port;
	pj_stun_sock_cfg ss_cfg;
	pj_str_t server;

	pj_bzero(&stun_sock_cb, sizeof(stun_sock_cb));
	stun_sock_cb.on_rx_data = &stun_sock_on_rx_data;
	stun_sock_cb.on_status = &stun_sock_on_status;

	g.peer[i].mapped_addr.addr.sa_family = pj_AF_INET();

	pj_stun_sock_cfg_default(&ss_cfg);
#if 1
	/* make reading the log easier */
	ss_cfg.ka_interval = 300;
#endif

	name[strlen(name)-1] = '0'+i;
	status = pj_stun_sock_create(&g.stun_config, name, pj_AF_INET(), 
				     &stun_sock_cb, &ss_cfg,
				     &g.peer[i], &g.peer[i].stun_sock);
	if (status != PJ_SUCCESS) {
	    my_perror("pj_stun_sock_create()", status);
	    return status;
	}

	if (o.stun_server) {
	    server = pj_str(o.stun_server);
	    port = PJ_STUN_PORT;
	} else {
	    server = pj_str(o.srv_addr);
	    port = (pj_uint16_t)(o.srv_port?atoi(o.srv_port):PJ_STUN_PORT);
	}
	status = pj_stun_sock_start(g.peer[i].stun_sock, &server, 
				    port,  NULL);
	if (status != PJ_SUCCESS) {
	    my_perror("pj_stun_sock_start()", status);
	    return status;
	}
    }

    /* Start the worker thread */
    CHECK( pj_thread_create(g.pool, "stun", &worker_thread, NULL, 0, 0, &g.thread) );


    return PJ_SUCCESS;
}
Exemple #7
0
/*
 * Create server.
 */
PJ_DEF(pj_status_t) pj_turn_srv_create(pj_pool_factory *pf, 
				       pj_turn_srv **p_srv)
{
    pj_pool_t *pool;
    pj_stun_session_cb sess_cb;
    pj_turn_srv *srv;
    unsigned i;
    pj_status_t status;

    PJ_ASSERT_RETURN(pf && p_srv, PJ_EINVAL);

    /* Create server and init core settings */
    pool = pj_pool_create(pf, "srv%p", 1000, 1000, NULL);
    srv = PJ_POOL_ZALLOC_T(pool, pj_turn_srv);
    srv->obj_name = pool->obj_name;
    srv->core.pf = pf;
    srv->core.pool = pool;
    srv->core.tls_key = srv->core.tls_data = -1;
    
    /* Create ioqueue */
    status = pj_ioqueue_create(pool, MAX_HANDLES, &srv->core.ioqueue);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Server mutex */
    status = pj_lock_create_recursive_mutex(pool, srv->obj_name, 
					    &srv->core.lock);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Allocate TLS */
    status = pj_thread_local_alloc(&srv->core.tls_key);
    if (status != PJ_SUCCESS)
	goto on_error;

    status = pj_thread_local_alloc(&srv->core.tls_data);
    if (status != PJ_SUCCESS)
	goto on_error;
    
    /* Create timer heap */
    status = pj_timer_heap_create(pool, MAX_TIMER, &srv->core.timer_heap);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Configure lock for the timer heap */
    pj_timer_heap_set_lock(srv->core.timer_heap, srv->core.lock, PJ_FALSE);

    /* Array of listeners */
    srv->core.listener = (pj_turn_listener**)
			 pj_pool_calloc(pool, MAX_LISTENERS, 
					sizeof(srv->core.listener[0]));

    /* Create hash tables */
    srv->tables.alloc = pj_hash_create(pool, MAX_CLIENTS);
    srv->tables.res = pj_hash_create(pool, MAX_CLIENTS);

    /* Init ports settings */
    srv->ports.min_udp = srv->ports.next_udp = MIN_PORT;
    srv->ports.max_udp = MAX_PORT;
    srv->ports.min_tcp = srv->ports.next_tcp = MIN_PORT;
    srv->ports.max_tcp = MAX_PORT;

    /* Init STUN config */
    pj_stun_config_init(&srv->core.stun_cfg, pf, 0, srv->core.ioqueue,
		        srv->core.timer_heap);

    /* Init STUN credential */
    srv->core.cred.type = PJ_STUN_AUTH_CRED_DYNAMIC;
    srv->core.cred.data.dyn_cred.user_data = srv;
    srv->core.cred.data.dyn_cred.get_auth = &pj_turn_get_auth;
    srv->core.cred.data.dyn_cred.get_password = &pj_turn_get_password;
    srv->core.cred.data.dyn_cred.verify_nonce = &pj_turn_verify_nonce;

    /* Create STUN session to handle new allocation */
    pj_bzero(&sess_cb, sizeof(sess_cb));
    sess_cb.on_rx_request = &on_rx_stun_request;
    sess_cb.on_send_msg = &on_tx_stun_msg;

    status = pj_stun_session_create(&srv->core.stun_cfg, srv->obj_name,
				    &sess_cb, PJ_FALSE, NULL,
				    &srv->core.stun_sess);
    if (status != PJ_SUCCESS) {
	goto on_error;
    }

    pj_stun_session_set_user_data(srv->core.stun_sess, srv);
    pj_stun_session_set_credential(srv->core.stun_sess, PJ_STUN_AUTH_LONG_TERM,
				   &srv->core.cred);


    /* Array of worker threads */
    srv->core.thread_cnt = MAX_THREADS;
    srv->core.thread = (pj_thread_t**)
		       pj_pool_calloc(pool, srv->core.thread_cnt, 
				      sizeof(pj_thread_t*));

    /* Start the worker threads */
    for (i=0; i<srv->core.thread_cnt; ++i) {
	status = pj_thread_create(pool, srv->obj_name, &server_thread_proc, 
				  srv, 0, 0, &srv->core.thread[i]);
	if (status != PJ_SUCCESS)
	    goto on_error;
    }

    /* We're done. Application should add listeners now */
    PJ_LOG(4,(srv->obj_name, "TURN server v%s is running", 
	      pj_get_version()));

    *p_srv = srv;
    return PJ_SUCCESS;

on_error:
    pj_turn_srv_destroy(srv);
    return status;
}