⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tsx_uas_test.c

📁 一个开源SIP协议栈
💻 C
📖 第 1 页 / 共 4 页
字号:
/* $Id: tsx_uas_test.c 974 2007-02-19 01:13:53Z bennylp $ */
/* 
 * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 */

#include "test.h"
#include <pjsip.h>
#include <pjlib.h>

#define THIS_FILE   "tsx_uas_test.c"


/*****************************************************************************
 **
 ** UAS tests.
 **
 ** This file performs various tests for UAC transactions. Each test will have
 ** a different Via branch param so that message receiver module and 
 ** transaction user module can identify which test is being carried out.
 **
 ** TEST1_BRANCH_ID
 **	Test that non-INVITE transaction returns 2xx response to the correct
 **	transport and correctly terminates the transaction.
 **	This also checks that transaction is destroyed immediately after
 **	it sends final response when reliable transport is used.
 **
 ** TEST2_BRANCH_ID
 **	As above, for non-2xx final response.
 **
 ** TEST3_BRANCH_ID
 **	Transaction correctly progressing to PROCEEDING state when provisional
 **	response is sent.
 **
 ** TEST4_BRANCH_ID
 **	Transaction retransmits last response (if any) without notifying 
 **	transaction user upon receiving request  retransmissions on TRYING
 **	state
 **
 ** TEST5_BRANCH_ID
 **	As above, in PROCEEDING state.
 **
 ** TEST6_BRANCH_ID
 **	As above, in COMPLETED state, with first sending provisional response.
 **	(Only applicable for non-reliable transports).
 **
 ** TEST7_BRANCH_ID
 **	INVITE transaction MUST retransmit non-2xx final response.
 **
 ** TEST8_BRANCH_ID
 **	As above, for INVITE's 2xx final response (this is PJSIP specific).
 **
 ** TEST9_BRANCH_ID
 **	INVITE transaction MUST cease retransmission of final response when
 **	ACK is received. (Note: PJSIP also retransmit 2xx final response 
 **	until it's terminated by user).
 **     Transaction also MUST terminate in T4 seconds.
 **	(Only applicable for non-reliable transports).
 **
 ** TEST11_BRANCH_ID
 **	Test scenario where transport fails before response is sent (i.e.
 **	in TRYING state).
 **
 ** TEST12_BRANCH_ID
 **	As above, after provisional response is sent but before final
 **	response is sent (i.e. in PROCEEDING state).
 **
 ** TEST13_BRANCH_ID
 **	As above, for INVITE, after final response has been sent but before
 **	ACK is received (i.e. in CONNECTED state).
 **
 ** TEST14_BRANCH_ID
 **	When UAS failed to deliver the response with the selected transport,
 **	it should try contacting the client with other transport or begin
 **	RFC 3263 server resolution procedure.
 **	This should be tested on:
 **	    a. TRYING state (when delivering first response).
 **	    b. PROCEEDING state (when failed to retransmit last response
 **	       upon receiving request retransmission).
 **	    c. COMPLETED state.
 **
 **/

static char *TEST1_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test1";
static char *TEST2_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test2";
static char *TEST3_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test3";
static char *TEST4_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test4";
static char *TEST5_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test5";
static char *TEST6_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test6";
static char *TEST7_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test7";
static char *TEST8_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test8";
static char *TEST9_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test9";
static char *TEST10_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test10";
static char *TEST11_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test11";
static char *TEST12_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test12";
//static char *TEST13_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test13";

#define TEST1_STATUS_CODE	200
#define TEST2_STATUS_CODE	301
#define TEST3_PROVISIONAL_CODE	PJSIP_SC_QUEUED
#define TEST3_STATUS_CODE	202
#define TEST4_STATUS_CODE	200
#define TEST4_REQUEST_COUNT	2
#define TEST5_PROVISIONAL_CODE	100
#define TEST5_STATUS_CODE	200	
#define TEST5_REQUEST_COUNT	2
#define TEST5_RESPONSE_COUNT	2
#define TEST6_PROVISIONAL_CODE	100
#define TEST6_STATUS_CODE	200	/* Must be final */
#define TEST6_REQUEST_COUNT	2
#define TEST6_RESPONSE_COUNT	3
#define TEST7_STATUS_CODE	301
#define TEST8_STATUS_CODE	302
#define TEST9_STATUS_CODE	301


#define TEST4_TITLE "test4: absorbing request retransmission"
#define TEST5_TITLE "test5: retransmit last response in PROCEEDING state"
#define TEST6_TITLE "test6: retransmit last response in COMPLETED state"


static char TARGET_URI[128];
static char FROM_URI[128];
static struct tsx_test_param *test_param;
static unsigned tp_flag;


#define TEST_TIMEOUT_ERROR	-30
#define MAX_ALLOWED_DIFF	150

static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e);
static pj_bool_t on_rx_message(pjsip_rx_data *rdata);

/* UAC transaction user module. */
static pjsip_module tsx_user = 
{
    NULL, NULL,				/* prev and next	*/
    { "Tsx-UAS-User", 12},		/* Name.		*/
    -1,					/* Id			*/
    PJSIP_MOD_PRIORITY_APPLICATION-1,	/* Priority		*/
    NULL,				/* load()		*/
    NULL,				/* start()		*/
    NULL,				/* stop()		*/
    NULL,				/* unload()		*/
    NULL,				/* on_rx_request()	*/
    NULL,				/* on_rx_response()	*/
    NULL,				/* on_tx_request()	*/
    NULL,				/* on_tx_response()	*/
    &tsx_user_on_tsx_state,		/* on_tsx_state()	*/
};

/* Module to send request. */
static pjsip_module msg_sender = 
{
    NULL, NULL,				/* prev and next	*/
    { "Msg-Sender", 10},		/* Name.		*/
    -1,					/* Id			*/
    PJSIP_MOD_PRIORITY_APPLICATION-1,	/* Priority		*/
    NULL,				/* load()		*/
    NULL,				/* start()		*/
    NULL,				/* stop()		*/
    NULL,				/* unload()		*/
    &on_rx_message,			/* on_rx_request()	*/
    &on_rx_message,			/* on_rx_response()	*/
    NULL,				/* on_tx_request()	*/
    NULL,				/* on_tx_response()	*/
    NULL,				/* on_tsx_state()	*/
};

/* Static vars, which will be reset on each test. */
static int recv_count;
static pj_time_val recv_last;
static pj_bool_t test_complete;

/* Loop transport instance. */
static pjsip_transport *loop;

/* UAS transaction key. */
static char key_buf[64];
static pj_str_t tsx_key = { key_buf, 0 };


/* General timer entry to be used by tests. */
//static pj_timer_entry timer;

/* Timer to send response via transaction. */
struct response
{
    pj_str_t	     tsx_key;
    pjsip_tx_data   *tdata;
};

/* Timer callback to send response. */
static void send_response_timer( pj_timer_heap_t *timer_heap,
				 struct pj_timer_entry *entry)
{
    pjsip_transaction *tsx;
    struct response *r = entry->user_data;
    pj_status_t status;

    tsx = pjsip_tsx_layer_find_tsx(&r->tsx_key, PJ_TRUE);
    if (!tsx) {
	PJ_LOG(3,(THIS_FILE,"    error: timer unable to find transaction"));
	pjsip_tx_data_dec_ref(r->tdata);
	return;
    }

    status = pjsip_tsx_send_msg(tsx, r->tdata);
    if (status != PJ_SUCCESS) {
	// Some tests do expect failure!
	//PJ_LOG(3,(THIS_FILE,"    error: timer unable to send response"));
	pj_mutex_unlock(tsx->mutex);
	pjsip_tx_data_dec_ref(r->tdata);
	return;
    }

    pj_mutex_unlock(tsx->mutex);
}

/* Utility to send response. */
static void send_response( pjsip_rx_data *rdata,
			   pjsip_transaction *tsx,
			   int status_code )
{
    pj_status_t status;
    pjsip_tx_data *tdata;

    status = pjsip_endpt_create_response( endpt, rdata, status_code, NULL, 
					  &tdata);
    if (status != PJ_SUCCESS) {
	app_perror("    error: unable to create response", status);
	test_complete = -196;
	return;
    }

    status = pjsip_tsx_send_msg(tsx, tdata);
    if (status != PJ_SUCCESS) {
	pjsip_tx_data_dec_ref(tdata);
	// Some tests do expect failure!
	//app_perror("    error: unable to send response", status);
	//test_complete = -197;
	return;
    }
}

/* Schedule timer to send response for the specified UAS transaction */
static void schedule_send_response( pjsip_rx_data *rdata,
				    const pj_str_t *tsx_key,
				    int status_code,
				    int msec_delay )
{
    pj_status_t status;
    pjsip_tx_data *tdata;
    pj_timer_entry *t;
    struct response *r;
    pj_time_val delay;

    status = pjsip_endpt_create_response( endpt, rdata, status_code, NULL, 
					  &tdata);
    if (status != PJ_SUCCESS) {
	app_perror("    error: unable to create response", status);
	test_complete = -198;
	return;
    }

    r = pj_pool_alloc(tdata->pool, sizeof(*r));
    pj_strdup(tdata->pool, &r->tsx_key, tsx_key);
    r->tdata = tdata;

    delay.sec = 0;
    delay.msec = msec_delay;
    pj_time_val_normalize(&delay);

    t = pj_pool_zalloc(tdata->pool, sizeof(*t));
    t->user_data = r;
    t->cb = &send_response_timer;

    status = pjsip_endpt_schedule_timer(endpt, t, &delay);
    if (status != PJ_SUCCESS) {
	pjsip_tx_data_dec_ref(tdata);
	app_perror("    error: unable to schedule timer", status);
	test_complete = -199;
	return;
    }
}


/* Find and terminate tsx with the specified key. */
static void terminate_our_tsx(int status_code)
{
    pjsip_transaction *tsx;

    tsx = pjsip_tsx_layer_find_tsx(&tsx_key, PJ_TRUE);
    if (!tsx) {
	PJ_LOG(3,(THIS_FILE,"    error: timer unable to find transaction"));
	return;
    }

    pjsip_tsx_terminate(tsx, status_code);
    pj_mutex_unlock(tsx->mutex);
}

#if 0	/* Unused for now */
/* Timer callback to terminate transaction. */
static void terminate_tsx_timer( pj_timer_heap_t *timer_heap,
				 struct pj_timer_entry *entry)
{
    terminate_our_tsx(entry->id);
}


/* Schedule timer to terminate transaction. */
static void schedule_terminate_tsx( pjsip_transaction *tsx,
				    int status_code,
				    int msec_delay )
{
    pj_time_val delay;

    delay.sec = 0;
    delay.msec = msec_delay;
    pj_time_val_normalize(&delay);

    pj_assert(pj_strcmp(&tsx->transaction_key, &tsx_key)==0);
    timer.user_data = NULL;
    timer.id = status_code;
    timer.cb = &terminate_tsx_timer;
    pjsip_endpt_schedule_timer(endpt, &timer, &delay);
}
#endif


/*
 * This is the handler to receive state changed notification from the
 * transaction. It is used to verify that the transaction behaves according
 * to the test scenario.
 */
static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e)
{
    if (pj_strcmp2(&tsx->branch, TEST1_BRANCH_ID)==0 ||
	pj_strcmp2(&tsx->branch, TEST2_BRANCH_ID)==0) 
    {
	/*
	 * TEST1_BRANCH_ID tests that non-INVITE transaction transmits final
	 * response using correct transport and terminates transaction after
	 * T4 (PJSIP_T4_TIMEOUT, 5 seconds).
	 *
	 * TEST2_BRANCH_ID does similar test for non-2xx final response.
	 */
	int status_code = (pj_strcmp2(&tsx->branch, TEST1_BRANCH_ID)==0) ?
			  TEST1_STATUS_CODE : TEST2_STATUS_CODE;

	if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {

	    test_complete = 1;

	    /* Check that status code is status_code. */
	    if (tsx->status_code != status_code) {
		PJ_LOG(3,(THIS_FILE, "    error: incorrect status code"));
		test_complete = -100;
	    }
	    
	    /* Previous state must be completed. */
	    if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) {
		PJ_LOG(3,(THIS_FILE, "    error: incorrect prev_state"));
		test_complete = -101;
	    }

	} else if (tsx->state == PJSIP_TSX_STATE_COMPLETED) {

	    /* Previous state must be TRYING. */
	    if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_TRYING) {
		PJ_LOG(3,(THIS_FILE, "    error: incorrect prev_state"));
		test_complete = -102;
	    }
	}

    }
    else
    if (pj_strcmp2(&tsx->branch, TEST3_BRANCH_ID)==0) {
	/*
	 * TEST3_BRANCH_ID tests sending provisional response.
	 */
	if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {

	    test_complete = 1;

	    /* Check that status code is status_code. */
	    if (tsx->status_code != TEST3_STATUS_CODE) {
		PJ_LOG(3,(THIS_FILE, "    error: incorrect status code"));
		test_complete = -110;
	    }
	    
	    /* Previous state must be completed. */
	    if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) {
		PJ_LOG(3,(THIS_FILE, "    error: incorrect prev_state"));
		test_complete = -111;
	    }

	} else if (tsx->state == PJSIP_TSX_STATE_PROCEEDING) {

	    /* Previous state must be TRYING. */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -