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

📄 sip_transaction.c

📁 基于sip协议的网络电话源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* $Id: sip_transaction.c 1251 2007-05-04 10:52:41Z 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 <pjsip/sip_transaction.h>#include <pjsip/sip_util.h>#include <pjsip/sip_module.h>#include <pjsip/sip_endpoint.h>#include <pjsip/sip_errno.h>#include <pjsip/sip_event.h>#include <pj/hash.h>#include <pj/pool.h>#include <pj/os.h>#include <pj/string.h>#include <pj/assert.h>#include <pj/guid.h>#include <pj/log.h>#define THIS_FILE   "sip_transaction.c"#if 0#define TSX_TRACE_(expr)    PJ_LOG(3,expr)#else#define TSX_TRACE_(expr)#endif/* When this macro is set, transaction will keep the hashed value * so that future lookup (to unregister transaction) does not need * to recalculate the hash again. It should gains a little bit of * performance, so generally we'd want this. */#define PRECALC_HASH/* Defined in sip_util_statefull.c */extern pjsip_module mod_stateful_util;/***************************************************************************** ** ** Declarations and static variable definitions section. ** ***************************************************************************** **//* Prototypes. */static pj_status_t mod_tsx_layer_load(pjsip_endpoint *endpt);static pj_status_t mod_tsx_layer_start(void);static pj_status_t mod_tsx_layer_stop(void);static pj_status_t mod_tsx_layer_unload(void);static pj_bool_t   mod_tsx_layer_on_rx_request(pjsip_rx_data *rdata);static pj_bool_t   mod_tsx_layer_on_rx_response(pjsip_rx_data *rdata);/* Transaction layer module definition. */static struct mod_tsx_layer{    struct pjsip_module  mod;    pj_pool_t		*pool;    pjsip_endpoint	*endpt;    pj_mutex_t		*mutex;    pj_hash_table_t	*htable;} mod_tsx_layer = {   {	NULL, NULL,			/* List's prev and next.    */	{ "mod-tsx-layer", 13 },	/* Module name.		    */	-1,				/* Module ID		    */	PJSIP_MOD_PRIORITY_TSX_LAYER,	/* Priority.		    */	mod_tsx_layer_load,		/* load().		    */	mod_tsx_layer_start,		/* start()		    */	mod_tsx_layer_stop,		/* stop()		    */	mod_tsx_layer_unload,		/* unload()		    */	mod_tsx_layer_on_rx_request,	/* on_rx_request()	    */	mod_tsx_layer_on_rx_response,	/* on_rx_response()	    */	NULL    }};/* Thread Local Storage ID for transaction lock */static long pjsip_tsx_lock_tls_id;/* Transaction state names */static const char *state_str[] = {    "Null",    "Calling",    "Trying",    "Proceeding",    "Completed",    "Confirmed",    "Terminated",    "Destroyed",};/* Role names */static const char *role_name[] = {    "UAC",    "UAS"};/* Transport flag. */enum{    TSX_HAS_PENDING_TRANSPORT	= 1,    TSX_HAS_PENDING_RESCHED	= 2,    TSX_HAS_PENDING_SEND	= 4,    TSX_HAS_PENDING_DESTROY	= 8,    TSX_HAS_RESOLVED_SERVER	= 16,};/* Transaction lock. */typedef struct tsx_lock_data {    struct tsx_lock_data *prev;    pjsip_transaction    *tsx;    int			  is_alive;} tsx_lock_data;/* Timer timeout value constants */static const pj_time_val t1_timer_val = { PJSIP_T1_TIMEOUT/1000,                                           PJSIP_T1_TIMEOUT%1000 };static const pj_time_val t2_timer_val = { PJSIP_T2_TIMEOUT/1000,                                           PJSIP_T2_TIMEOUT%1000 };static const pj_time_val t4_timer_val = { PJSIP_T4_TIMEOUT/1000,                                           PJSIP_T4_TIMEOUT%1000 };static const pj_time_val td_timer_val = { PJSIP_TD_TIMEOUT/1000,                                           PJSIP_TD_TIMEOUT%1000 };static const pj_time_val timeout_timer_val = { (64*PJSIP_T1_TIMEOUT)/1000,					       (64*PJSIP_T1_TIMEOUT)%1000 };/* Internal timer IDs */enum Transaction_Timer_Id{    TSX_TIMER_RETRANSMISSION,    TSX_TIMER_TIMEOUT,};/* Prototypes. */static void	   lock_tsx(pjsip_transaction *tsx, struct tsx_lock_data *lck);static pj_status_t unlock_tsx( pjsip_transaction *tsx,                                struct tsx_lock_data *lck);static pj_status_t tsx_on_state_null(		pjsip_transaction *tsx, 				                pjsip_event *event);static pj_status_t tsx_on_state_calling(	pjsip_transaction *tsx, 				                pjsip_event *event);static pj_status_t tsx_on_state_trying(		pjsip_transaction *tsx, 				                pjsip_event *event);static pj_status_t tsx_on_state_proceeding_uas( pjsip_transaction *tsx, 					        pjsip_event *event);static pj_status_t tsx_on_state_proceeding_uac( pjsip_transaction *tsx,					        pjsip_event *event);static pj_status_t tsx_on_state_completed_uas(	pjsip_transaction *tsx, 					        pjsip_event *event);static pj_status_t tsx_on_state_completed_uac(	pjsip_transaction *tsx,					        pjsip_event *event);static pj_status_t tsx_on_state_confirmed(	pjsip_transaction *tsx, 					        pjsip_event *event);static pj_status_t tsx_on_state_terminated(	pjsip_transaction *tsx, 					        pjsip_event *event);static pj_status_t tsx_on_state_destroyed(	pjsip_transaction *tsx, 					        pjsip_event *event);static void        tsx_timer_callback( pj_timer_heap_t *theap, 			               pj_timer_entry *entry);static pj_status_t tsx_create( pjsip_module *tsx_user,			       pjsip_transaction **p_tsx);static pj_status_t tsx_destroy( pjsip_transaction *tsx );static void	   tsx_resched_retransmission( pjsip_transaction *tsx );static pj_status_t tsx_retransmit( pjsip_transaction *tsx, int resched);static int         tsx_send_msg( pjsip_transaction *tsx,                                  pjsip_tx_data *tdata);/* State handlers for UAC, indexed by state */static int  (*tsx_state_handler_uac[PJSIP_TSX_STATE_MAX])(pjsip_transaction *,							  pjsip_event *) = {    &tsx_on_state_null,    &tsx_on_state_calling,    NULL,    &tsx_on_state_proceeding_uac,    &tsx_on_state_completed_uac,    &tsx_on_state_confirmed,    &tsx_on_state_terminated,    &tsx_on_state_destroyed,};/* State handlers for UAS */static int  (*tsx_state_handler_uas[PJSIP_TSX_STATE_MAX])(pjsip_transaction *, 							  pjsip_event *) = {    &tsx_on_state_null,    NULL,    &tsx_on_state_trying,    &tsx_on_state_proceeding_uas,    &tsx_on_state_completed_uas,    &tsx_on_state_confirmed,    &tsx_on_state_terminated,    &tsx_on_state_destroyed,};/***************************************************************************** ** ** Utilities ** ***************************************************************************** *//* * Get transaction state name. */PJ_DEF(const char *) pjsip_tsx_state_str(pjsip_tsx_state_e state){    return state_str[state];}/* * Get the role name. */PJ_DEF(const char *) pjsip_role_name(pjsip_role_e role){    return role_name[role];}/* * Create transaction key for RFC2543 compliant messages, which don't have * unique branch parameter in the top most Via header. * * INVITE requests matches a transaction if the following attributes * match the original request: *	- Request-URI *	- To tag *	- From tag *	- Call-ID *	- CSeq *	- top Via header * * CANCEL matching is done similarly as INVITE, except: *	- CSeq method will differ *	- To tag is not matched. * * ACK matching is done similarly, except that: *	- method of the CSeq will differ, *	- To tag is matched to the response sent by the server transaction. * * The transaction key is constructed from the common components of above * components. Additional comparison is needed to fully match a transaction. */static pj_status_t create_tsx_key_2543( pj_pool_t *pool,			                pj_str_t *str,			                pjsip_role_e role,			                const pjsip_method *method,			                const pjsip_rx_data *rdata ){#define SEPARATOR   '$'    char *key, *p, *end;    int len;    pj_size_t len_required;    pjsip_uri *req_uri;    pj_str_t *host;    PJ_ASSERT_RETURN(pool && str && method && rdata, PJ_EINVAL);    PJ_ASSERT_RETURN(rdata->msg_info.msg, PJ_EINVAL);    PJ_ASSERT_RETURN(rdata->msg_info.via, PJSIP_EMISSINGHDR);    PJ_ASSERT_RETURN(rdata->msg_info.cseq, PJSIP_EMISSINGHDR);    PJ_ASSERT_RETURN(rdata->msg_info.from, PJSIP_EMISSINGHDR);    host = &rdata->msg_info.via->sent_by.host;    req_uri = (pjsip_uri*)rdata->msg_info.msg->line.req.uri;    /* Calculate length required. */    len_required = 9 +			    /* CSeq number */		   rdata->msg_info.from->tag.slen +   /* From tag. */		   rdata->msg_info.cid->id.slen +    /* Call-ID */		   host->slen +		    /* Via host. */		   9 +			    /* Via port. */		   16;			    /* Separator+Allowance. */    key = p = pj_pool_alloc(pool, len_required);    end = p + len_required;    /* Add role. */    *p++ = (char)(role==PJSIP_ROLE_UAC ? 'c' : 's');    *p++ = SEPARATOR;    /* Add method, except when method is INVITE or ACK. */    if (method->id != PJSIP_INVITE_METHOD && method->id != PJSIP_ACK_METHOD) {	pj_memcpy(p, method->name.ptr, method->name.slen);	p += method->name.slen;	*p++ = '$';    }    /* Add CSeq (only the number). */    len = pj_utoa(rdata->msg_info.cseq->cseq, p);    p += len;    *p++ = SEPARATOR;    /* Add From tag. */    len = rdata->msg_info.from->tag.slen;    pj_memcpy( p, rdata->msg_info.from->tag.ptr, len);    p += len;    *p++ = SEPARATOR;    /* Add Call-ID. */    len = rdata->msg_info.cid->id.slen;    pj_memcpy( p, rdata->msg_info.cid->id.ptr, len );    p += len;    *p++ = SEPARATOR;    /* Add top Via header.      * We don't really care whether the port contains the real port (because     * it can be omited if default port is used). Anyway this function is      * only used to match request retransmission, and we expect that the      * request retransmissions will contain the same port.     */    pj_memcpy(p, host->ptr, host->slen);    p += host->slen;    *p++ = ':';    len = pj_utoa(rdata->msg_info.via->sent_by.port, p);    p += len;    *p++ = SEPARATOR;        *p++ = '\0';    /* Done. */    str->ptr = key;    str->slen = p-key;    return PJ_SUCCESS;}/* * Create transaction key for RFC3161 compliant system. */static pj_status_t create_tsx_key_3261( pj_pool_t *pool,		                        pj_str_t *key,		                        pjsip_role_e role,		                        const pjsip_method *method,		                        const pj_str_t *branch){    char *p;    PJ_ASSERT_RETURN(pool && key && method && branch, PJ_EINVAL);    p = key->ptr = pj_pool_alloc(pool, branch->slen + method->name.slen + 4 );        /* Add role. */    *p++ = (char)(role==PJSIP_ROLE_UAC ? 'c' : 's');    *p++ = SEPARATOR;    /* Add method, except when method is INVITE or ACK. */    if (method->id != PJSIP_INVITE_METHOD && method->id != PJSIP_ACK_METHOD) {	pj_memcpy(p, method->name.ptr, method->name.slen);	p += method->name.slen;	*p++ = '$';    }    /* Add branch ID. */    pj_memcpy(p, branch->ptr, branch->slen);    p += branch->slen;    /* Set length */    key->slen = p - key->ptr;    return PJ_SUCCESS;}/* * Create key from the incoming data, to be used to search the transaction * in the transaction hash table. */PJ_DEF(pj_status_t) pjsip_tsx_create_key( pj_pool_t *pool, pj_str_t *key, 				          pjsip_role_e role, 				          const pjsip_method *method, 				          const pjsip_rx_data *rdata){    pj_str_t rfc3261_branch = {PJSIP_RFC3261_BRANCH_ID,                                PJSIP_RFC3261_BRANCH_LEN};    /* Get the branch parameter in the top-most Via.     * If branch parameter is started with "z9hG4bK", then the message was     * generated by agent compliant with RFC3261. Otherwise, it will be     * handled as RFC2543.     */    const pj_str_t *branch = &rdata->msg_info.via->branch_param;    if (pj_strncmp(branch,&rfc3261_branch,PJSIP_RFC3261_BRANCH_LEN)==0) {	/* Create transaction key. */	return create_tsx_key_3261(pool, key, role, method, branch);    } else {	/* Create the key for the message. This key will be matched up          * with the transaction key. For RFC2563 transactions, the          * transaction key was created by the same function, so it will          * match the message.	 */	return create_tsx_key_2543( pool, key, role, method, rdata );    }}/***************************************************************************** ** ** Transaction layer module ** ***************************************************************************** **//* * Create transaction layer module and registers it to the endpoint. */PJ_DEF(pj_status_t) pjsip_tsx_layer_init_module(pjsip_endpoint *endpt){    pj_pool_t *pool;    pj_status_t status;    PJ_ASSERT_RETURN(mod_tsx_layer.endpt==NULL, PJ_EINVALIDOP);    /* Initialize TLS ID for transaction lock. */    status = pj_thread_local_alloc(&pjsip_tsx_lock_tls_id);    if (status != PJ_SUCCESS)	return status;    pj_thread_local_set(pjsip_tsx_lock_tls_id, NULL);    /*     * Initialize transaction layer structure.     */    /* Create pool for the module. */    pool = pjsip_endpt_create_pool(endpt, "tsxlayer", 				   PJSIP_POOL_TSX_LAYER_LEN,				   PJSIP_POOL_TSX_LAYER_INC );    if (!pool)	return PJ_ENOMEM;        /* Initialize some attributes. */    mod_tsx_layer.pool = pool;    mod_tsx_layer.endpt = endpt;    /* Create hash table. */    mod_tsx_layer.htable = pj_hash_create( pool, PJSIP_MAX_TSX_COUNT );    if (!mod_tsx_layer.htable) {	pjsip_endpt_release_pool(endpt, pool);	return PJ_ENOMEM;    }    /* Create mutex. */    status = pj_mutex_create_recursive(pool, "tsxlayer", &mod_tsx_layer.mutex);    if (status != PJ_SUCCESS) {	pjsip_endpt_release_pool(endpt, pool);	return status;    }

⌨️ 快捷键说明

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