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

📄 sip_transport.c

📁 一个开源SIP协议栈
💻 C
📖 第 1 页 / 共 3 页
字号:
/* $Id: sip_transport.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 <pjsip/sip_transport.h>
#include <pjsip/sip_endpoint.h>
#include <pjsip/sip_parser.h>
#include <pjsip/sip_msg.h>
#include <pjsip/sip_private.h>
#include <pjsip/sip_errno.h>
#include <pjsip/sip_module.h>
#include <pj/except.h>
#include <pj/os.h>
#include <pj/log.h>
#include <pj/ioqueue.h>
#include <pj/hash.h>
#include <pj/string.h>
#include <pj/pool.h>
#include <pj/assert.h>
#include <pj/lock.h>


#define THIS_FILE    "sip_transport.c"

#if 0
#   define TRACE_(x)	PJ_LOG(5,x)
#else
#   define TRACE_(x)
#endif

/* Prototype. */
static pj_status_t mod_on_tx_msg(pjsip_tx_data *tdata);

/* This module has sole purpose to print transmit data to contigous buffer
 * before actually transmitted to the wire. 
 */
static pjsip_module mod_msg_print = 
{
    NULL, NULL,				/* prev and next		    */
    { "mod-msg-print", 13},		/* Name.			    */
    -1,					/* Id				    */
    PJSIP_MOD_PRIORITY_TRANSPORT_LAYER,	/* Priority			    */
    NULL,				/* load()			    */
    NULL,				/* start()			    */
    NULL,				/* stop()			    */
    NULL,				/* unload()			    */
    NULL,				/* on_rx_request()		    */
    NULL,				/* on_rx_response()		    */
    &mod_on_tx_msg,			/* on_tx_request()		    */
    &mod_on_tx_msg,			/* on_tx_response()		    */
    NULL,				/* on_tsx_state()		    */
};

/*
 * Transport manager.
 */
struct pjsip_tpmgr 
{
    pj_hash_table_t *table;
    pj_lock_t	    *lock;
    pjsip_endpoint  *endpt;
    pjsip_tpfactory  factory_list;
#if defined(PJ_DEBUG) && PJ_DEBUG!=0
    pj_atomic_t	    *tdata_counter;
#endif
    void           (*on_rx_msg)(pjsip_endpoint*, pj_status_t, pjsip_rx_data*);
    pj_status_t	   (*on_tx_msg)(pjsip_endpoint*, pjsip_tx_data*);
};

/* Key for looking up hash table */
struct transport_key
{
    pjsip_transport_type_e  type;
    pj_sockaddr		    addr;
};

/*****************************************************************************
 *
 * GENERAL TRANSPORT (NAMES, TYPES, ETC.)
 *
 *****************************************************************************/

/*
 * Transport names.
 */
struct
{
    pjsip_transport_type_e type;
    pj_uint16_t		   port;
    pj_str_t		   name;
    unsigned		   flag;
    char		   name_buf[16];
} transport_names[16] = 
{
    { PJSIP_TRANSPORT_UNSPECIFIED, 0, {"Unspecified", 11}, 0},
    { PJSIP_TRANSPORT_UDP, 5060, {"UDP", 3}, PJSIP_TRANSPORT_DATAGRAM},
    { PJSIP_TRANSPORT_TCP, 5060, {"TCP", 3}, PJSIP_TRANSPORT_RELIABLE},
    { PJSIP_TRANSPORT_TLS, 5061, {"TLS", 3}, PJSIP_TRANSPORT_RELIABLE | PJSIP_TRANSPORT_SECURE},
    { PJSIP_TRANSPORT_SCTP, 5060, {"SCTP", 4}, PJSIP_TRANSPORT_RELIABLE},
    { PJSIP_TRANSPORT_LOOP, 15060, {"LOOP", 4}, PJSIP_TRANSPORT_RELIABLE}, 
    { PJSIP_TRANSPORT_LOOP_DGRAM, 15060, {"LOOP-DGRAM", 10}, PJSIP_TRANSPORT_DATAGRAM},
};


/*
 * Register new transport type to PJSIP.
 */
PJ_DECL(pj_status_t) pjsip_transport_register_type(unsigned tp_flag,
						   const char *tp_name,
						   int def_port,
						   int *p_tp_type)
{
    unsigned i;

    PJ_ASSERT_RETURN(tp_flag && tp_name && def_port, PJ_EINVAL);
    PJ_ASSERT_RETURN(pj_ansi_strlen(tp_name) < 
			PJ_ARRAY_SIZE(transport_names[0].name_buf), 
		     PJ_ENAMETOOLONG);

    for (i=1; i<PJ_ARRAY_SIZE(transport_names); ++i) {
	if (transport_names[i].type == 0)
	    break;
    }

    if (i == PJ_ARRAY_SIZE(transport_names))
	return PJ_ETOOMANY;

    transport_names[i].type = (pjsip_transport_type_e)i;
    transport_names[i].port = (pj_uint16_t)def_port;
    pj_ansi_strcpy(transport_names[i].name_buf, tp_name);
    transport_names[i].name = pj_str(transport_names[i].name_buf);
    transport_names[i].flag = tp_flag;

    if (p_tp_type)
	*p_tp_type = i;

    return PJ_SUCCESS;
}


/*
 * Get transport type from name.
 */
PJ_DEF(pjsip_transport_type_e) 
pjsip_transport_get_type_from_name(const pj_str_t *name)
{
    unsigned i;

    /* Sanity check. 
     * Check that transport_names[] are indexed on transport type. 
     */
    PJ_ASSERT_RETURN(transport_names[PJSIP_TRANSPORT_UDP].type ==
		     PJSIP_TRANSPORT_UDP, PJSIP_TRANSPORT_UNSPECIFIED);

    if (name->slen == 0)
	return PJSIP_TRANSPORT_UNSPECIFIED;

    /* Get transport type from name. */
    for (i=0; i<PJ_ARRAY_SIZE(transport_names); ++i) {
	if (pj_stricmp(name, &transport_names[i].name) == 0) {
	    return transport_names[i].type;
	}
    }

    pj_assert(!"Invalid transport name");
    return PJSIP_TRANSPORT_UNSPECIFIED;
}


/*
 * Get the transport type for the specified flags.
 */
PJ_DEF(pjsip_transport_type_e) 
pjsip_transport_get_type_from_flag(unsigned flag)
{
    unsigned i;

    /* Sanity check. 
     * Check that transport_names[] are indexed on transport type. 
     */
    PJ_ASSERT_RETURN(transport_names[PJSIP_TRANSPORT_UDP].type ==
		     PJSIP_TRANSPORT_UDP, PJSIP_TRANSPORT_UNSPECIFIED);

    /* Get the transport type for the specified flags. */
    for (i=0; i<PJ_ARRAY_SIZE(transport_names); ++i) {
	if (transport_names[i].flag == flag) {
	    return transport_names[i].type;
	}
    }

    pj_assert(!"Invalid transport type");
    return PJSIP_TRANSPORT_UNSPECIFIED;
}

PJ_DEF(unsigned)
pjsip_transport_get_flag_from_type( pjsip_transport_type_e type )
{
    /* Sanity check. 
     * Check that transport_names[] are indexed on transport type. 
     */
    PJ_ASSERT_RETURN(transport_names[PJSIP_TRANSPORT_UDP].type ==
		     PJSIP_TRANSPORT_UDP, 0);

    /* Check that argument is valid. */
    PJ_ASSERT_RETURN(type < PJ_ARRAY_SIZE(transport_names), 0);

    /* Return transport flag. */
    return transport_names[type].flag;
}

/*
 * Get the default SIP port number for the specified type.
 */
PJ_DEF(int) 
pjsip_transport_get_default_port_for_type(pjsip_transport_type_e type)
{
    /* Sanity check. 
     * Check that transport_names[] are indexed on transport type. 
     */
    PJ_ASSERT_RETURN(transport_names[PJSIP_TRANSPORT_UDP].type ==
		     PJSIP_TRANSPORT_UDP, 0);

    /* Check that argument is valid. */
    PJ_ASSERT_RETURN(type < PJ_ARRAY_SIZE(transport_names), 5060);

    /* Return the port. */
    return transport_names[type].port;
}

/*
 * Get transport name.
 */
PJ_DEF(const char*) pjsip_transport_get_type_name(pjsip_transport_type_e type)
{
    /* Sanity check. 
     * Check that transport_names[] are indexed on transport type. 
     */
    PJ_ASSERT_RETURN(transport_names[PJSIP_TRANSPORT_UDP].type ==
		     PJSIP_TRANSPORT_UDP, "Unknown");

    /* Check that argument is valid. */
    PJ_ASSERT_RETURN(type < PJ_ARRAY_SIZE(transport_names), "Unknown");

    /* Return the port. */
    return transport_names[type].name.ptr;
}


/*****************************************************************************
 *
 * TRANSPORT SELECTOR
 *
 *****************************************************************************/

/*
 * Add transport/listener reference in the selector.
 */
PJ_DEF(void) pjsip_tpselector_add_ref(pjsip_tpselector *sel)
{
    if (sel->type == PJSIP_TPSELECTOR_TRANSPORT && sel->u.transport != NULL)
	pjsip_transport_add_ref(sel->u.transport);
    else if (sel->type == PJSIP_TPSELECTOR_LISTENER && sel->u.listener != NULL)
	; /* Hmm.. looks like we don't have reference counter for listener */
}


/*
 * Decrement transport/listener reference in the selector.
 */
PJ_DEF(void) pjsip_tpselector_dec_ref(pjsip_tpselector *sel)
{
    if (sel->type == PJSIP_TPSELECTOR_TRANSPORT && sel->u.transport != NULL)
	pjsip_transport_dec_ref(sel->u.transport);
    else if (sel->type == PJSIP_TPSELECTOR_LISTENER && sel->u.listener != NULL)
	; /* Hmm.. looks like we don't have reference counter for listener */
}


/*****************************************************************************
 *
 * TRANSMIT DATA BUFFER MANIPULATION.
 *
 *****************************************************************************/

/*
 * Create new transmit buffer.
 */
PJ_DEF(pj_status_t) pjsip_tx_data_create( pjsip_tpmgr *mgr,
					  pjsip_tx_data **p_tdata )
{
    pj_pool_t *pool;
    pjsip_tx_data *tdata;
    pj_status_t status;

    PJ_ASSERT_RETURN(mgr && p_tdata, PJ_EINVAL);

    pool = pjsip_endpt_create_pool( mgr->endpt, "tdta%p",
				    PJSIP_POOL_LEN_TDATA,
				    PJSIP_POOL_INC_TDATA );
    if (!pool)
	return PJ_ENOMEM;

    tdata = pj_pool_zalloc(pool, sizeof(pjsip_tx_data));
    tdata->pool = pool;
    tdata->mgr = mgr;
    pj_ansi_snprintf(tdata->obj_name, PJ_MAX_OBJ_NAME, "tdta%p", tdata);

    status = pj_atomic_create(tdata->pool, 0, &tdata->ref_cnt);
    if (status != PJ_SUCCESS) {
	pjsip_endpt_release_pool( mgr->endpt, tdata->pool );
	return status;
    }
    
    //status = pj_lock_create_simple_mutex(pool, "tdta%p", &tdata->lock);
    status = pj_lock_create_null_mutex(pool, "tdta%p", &tdata->lock);
    if (status != PJ_SUCCESS) {
	pjsip_endpt_release_pool( mgr->endpt, tdata->pool );
	return status;
    }

    pj_ioqueue_op_key_init(&tdata->op_key.key, sizeof(tdata->op_key));

#if defined(PJ_DEBUG) && PJ_DEBUG!=0
    pj_atomic_inc( tdata->mgr->tdata_counter );
#endif

    *p_tdata = tdata;
    return PJ_SUCCESS;
}


/*
 * Add reference to tx buffer.
 */
PJ_DEF(void) pjsip_tx_data_add_ref( pjsip_tx_data *tdata )
{
    pj_atomic_inc(tdata->ref_cnt);
}

/*
 * Decrease transport data reference, destroy it when the reference count
 * reaches zero.
 */
PJ_DEF(pj_status_t) pjsip_tx_data_dec_ref( pjsip_tx_data *tdata )
{
    pj_assert( pj_atomic_get(tdata->ref_cnt) > 0);
    if (pj_atomic_dec_and_get(tdata->ref_cnt) <= 0) {
	PJ_LOG(5,(tdata->obj_name, "Destroying txdata %s",
		  pjsip_tx_data_get_info(tdata)));
	pjsip_tpselector_dec_ref(&tdata->tp_sel);
#if defined(PJ_DEBUG) && PJ_DEBUG!=0
	pj_atomic_dec( tdata->mgr->tdata_counter );
#endif
	pj_atomic_destroy( tdata->ref_cnt );
	pj_lock_destroy( tdata->lock );
	pjsip_endpt_release_pool( tdata->mgr->endpt, tdata->pool );
	return PJSIP_EBUFDESTROYED;
    } else {
	return PJ_SUCCESS;
    }
}

/*
 * Invalidate the content of the print buffer to force the message to be
 * re-printed when sent.
 */
PJ_DEF(void) pjsip_tx_data_invalidate_msg( pjsip_tx_data *tdata )
{
    tdata->buf.cur = tdata->buf.start;
    tdata->info = NULL;
}

PJ_DEF(pj_bool_t) pjsip_tx_data_is_valid( pjsip_tx_data *tdata )
{
    return tdata->buf.cur != tdata->buf.start;
}

static char *get_msg_info(pj_pool_t *pool, const char *obj_name,
			  const pjsip_msg *msg)
{
    char info_buf[128], *info;
    const pjsip_cseq_hdr *cseq;
    int len;

    cseq = pjsip_msg_find_hdr(msg, PJSIP_H_CSEQ, NULL);
    PJ_ASSERT_RETURN(cseq != NULL, "INVALID MSG");

    if (msg->type == PJSIP_REQUEST_MSG) {
	len = pj_ansi_snprintf(info_buf, sizeof(info_buf), 
			       "Request msg %.*s/cseq=%d (%s)",
			       (int)msg->line.req.method.name.slen,
			       msg->line.req.method.name.ptr,
			       cseq->cseq, obj_name);
    } else {
	len = pj_ansi_snprintf(info_buf, sizeof(info_buf),
			       "Response msg %d/%.*s/cseq=%d (%s)",
			       msg->line.status.code,
			       (int)cseq->method.name.slen,
			       cseq->method.name.ptr,
			       cseq->cseq, obj_name);
    }

    if (len < 1 || len >= sizeof(info_buf)) {
	return (char*)obj_name;
    }

    info = pj_pool_alloc(pool, len+1);
    pj_memcpy(info, info_buf, len+1);

    return info;
}

PJ_DEF(char*) pjsip_tx_data_get_info( pjsip_tx_data *tdata )
{

    if (tdata==NULL || tdata->msg==NULL)
	return "NULL";

    if (tdata->info)
	return tdata->info;

    pj_lock_acquire(tdata->lock);
    tdata->info = get_msg_info(tdata->pool, tdata->obj_name, tdata->msg);
    pj_lock_release(tdata->lock);

    return tdata->info;
}

PJ_DEF(pj_status_t) pjsip_tx_data_set_transport(pjsip_tx_data *tdata,
						const pjsip_tpselector *sel)
{
    PJ_ASSERT_RETURN(tdata && sel, PJ_EINVAL);

    pj_lock_acquire(tdata->lock);

    pjsip_tpselector_dec_ref(&tdata->tp_sel);

    pj_memcpy(&tdata->tp_sel, sel, sizeof(*sel));
    pjsip_tpselector_add_ref(&tdata->tp_sel);

    pj_lock_release(tdata->lock);

    return PJ_SUCCESS;
}


PJ_DEF(char*) pjsip_rx_data_get_info(pjsip_rx_data *rdata)
{
    char obj_name[PJ_MAX_OBJ_NAME];

    PJ_ASSERT_RETURN(rdata->msg_info.msg, "INVALID MSG");

    if (rdata->msg_info.info)
	return rdata->msg_info.info;

    pj_ansi_strcpy(obj_name, "rdata");
    pj_ansi_snprintf(obj_name+5, sizeof(obj_name)-5, "%p", rdata);

    rdata->msg_info.info = get_msg_info(rdata->tp_info.pool, obj_name,
					rdata->msg_info.msg);
    return rdata->msg_info.info;
}

/*****************************************************************************
 *
 * TRANSPORT KEY
 *
 *****************************************************************************/


/*****************************************************************************
 *
 * TRANSPORT
 *
 *****************************************************************************/

static void transport_send_callback(pjsip_transport *transport,
				    void *token,

⌨️ 快捷键说明

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