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

📄 sip_endpoint.c

📁 基于sip协议的网络电话源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $Id: sip_endpoint.c 1018 2007-02-28 15:38:01Z 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_endpoint.h>#include <pjsip/sip_transaction.h>#include <pjsip/sip_private.h>#include <pjsip/sip_event.h>#include <pjsip/sip_resolve.h>#include <pjsip/sip_module.h>#include <pjsip/sip_util.h>#include <pjsip/sip_errno.h>#include <pj/except.h>#include <pj/log.h>#include <pj/string.h>#include <pj/os.h>#include <pj/pool.h>#include <pj/hash.h>#include <pj/assert.h>#include <pj/errno.h>#include <pj/lock.h>#define PJSIP_EX_NO_MEMORY  PJ_NO_MEMORY_EXCEPTION#define THIS_FILE	    "sip_endpoint.c"#define MAX_METHODS   32/** * The SIP endpoint. */struct pjsip_endpoint{    /** Pool to allocate memory for the endpoint. */    pj_pool_t		*pool;    /** Mutex for the pool, hash table, and event list/queue. */    pj_mutex_t		*mutex;    /** Pool factory. */    pj_pool_factory	*pf;    /** Name. */    pj_str_t		 name;    /** Timer heap. */    pj_timer_heap_t	*timer_heap;    /** Transport manager. */    pjsip_tpmgr		*transport_mgr;    /** Ioqueue. */    pj_ioqueue_t	*ioqueue;    /** Last ioqueue err */    pj_status_t		 ioq_last_err;    /** DNS Resolver. */    pjsip_resolver_t	*resolver;    /** Modules lock. */    pj_rwmutex_t	*mod_mutex;    /** Modules. */    pjsip_module        *modules[PJSIP_MAX_MODULE];    /** Module list, sorted by priority. */    pjsip_module	 module_list;    /** Capability header list. */    pjsip_hdr		 cap_hdr;    /** Additional request headers. */    pjsip_hdr		 req_hdr;};#if defined(PJSIP_SAFE_MODULE) && PJSIP_SAFE_MODULE!=0#   define LOCK_MODULE_ACCESS(ept)	pj_rwmutex_lock_read(ept->mod_mutex)#   define UNLOCK_MODULE_ACCESS(ept)	pj_rwmutex_unlock_read(ept->mod_mutex)#else#   define LOCK_MODULE_ACCESS(endpt)#   define UNLOCK_MODULE_ACCESS(endpt)#endif/* * Prototypes. */static void endpt_on_rx_msg( pjsip_endpoint*, 			     pj_status_t, pjsip_rx_data*);static pj_status_t endpt_on_tx_msg( pjsip_endpoint *endpt,				    pjsip_tx_data *tdata );/* Defined in sip_parser.c */void init_sip_parser(void);void deinit_sip_parser(void);/* Defined in sip_tel_uri.c */pj_status_t pjsip_tel_uri_subsys_init(void);/* Specifies whether error subsystem has been registered to pjlib. */static int error_subsys_initialized;/** * Defined in sip_errno.c * * Get error message for the specified error code. This can only get * PJSIP specific error message. To get all types of error message, * use pj_strerror() instead. * * @param status    The error code. * @param buffer    The buffer where to put the error message. * @param bufsize   Size of the buffer. * * @return	    The error message as NULL terminated string, *                  wrapped with pj_str_t. */PJ_DECL(pj_str_t) pjsip_strerror( pj_status_t status, char *buffer,				  pj_size_t bufsize);/* * This is the global handler for memory allocation failure, for pools that * are created by the endpoint (by default, all pools ARE allocated by  * endpoint). The error is handled by throwing exception, and hopefully, * the exception will be handled by the application (or this library). */static void pool_callback( pj_pool_t *pool, pj_size_t size ){    PJ_UNUSED_ARG(pool);    PJ_UNUSED_ARG(size);    PJ_THROW(PJSIP_EX_NO_MEMORY);}/* Compare module name, used for searching module based on name. */static int cmp_mod_name(void *name, const void *mod){    return pj_stricmp(name, &((pjsip_module*)mod)->name);}/* * Register new module to the endpoint. * The endpoint will then call the load and start function in the module to  * properly initialize the module, and assign a unique module ID for the  * module. */PJ_DEF(pj_status_t) pjsip_endpt_register_module( pjsip_endpoint *endpt,						 pjsip_module *mod ){    pj_status_t status = PJ_SUCCESS;    pjsip_module *m;    int i;    pj_rwmutex_lock_write(endpt->mod_mutex);    /* Make sure that this module has not been registered. */    PJ_ASSERT_ON_FAIL(	pj_list_find_node(&endpt->module_list, mod) == NULL,			{status = PJ_EEXISTS; goto on_return;});    /* Make sure that no module with the same name has been registered. */    PJ_ASSERT_ON_FAIL(	pj_list_search(&endpt->module_list, &mod->name, 				       &cmp_mod_name)==NULL,			{status = PJ_EEXISTS; goto on_return; });    /* Find unused ID for this module. */    for (i=0; i<PJ_ARRAY_SIZE(endpt->modules); ++i) {	if (endpt->modules[i] == NULL)	    break;    }    if (i == PJ_ARRAY_SIZE(endpt->modules)) {	pj_assert(!"Too many modules registered!");	status = PJ_ETOOMANY;	goto on_return;    }    /* Assign the ID. */    mod->id = i;    /* Try to load the module. */    if (mod->load) {	status = (*mod->load)(endpt);	if (status != PJ_SUCCESS)	    goto on_return;    }    /* Try to start the module. */    if (mod->start) {	status = (*mod->start)();	if (status != PJ_SUCCESS)	    goto on_return;    }    /* Save the module. */    endpt->modules[i] = mod;    /* Put in the module list, sorted by priority. */    m = endpt->module_list.next;    while (m != &endpt->module_list) {	if (m->priority > mod->priority)	    break;	m = m->next;    }    pj_list_insert_before(m, mod);    /* Done. */    PJ_LOG(4,(THIS_FILE, "Module \"%.*s\" registered", 	      (int)mod->name.slen, mod->name.ptr));on_return:    pj_rwmutex_unlock_write(endpt->mod_mutex);    return status;}/* * Unregister a module from the endpoint. * The endpoint will then call the stop and unload function in the module to  * properly shutdown the module. */PJ_DEF(pj_status_t) pjsip_endpt_unregister_module( pjsip_endpoint *endpt,						   pjsip_module *mod ){    pj_status_t status;    pj_rwmutex_lock_write(endpt->mod_mutex);    /* Make sure the module exists in the list. */    PJ_ASSERT_ON_FAIL(	pj_list_find_node(&endpt->module_list, mod) == mod,			{status = PJ_ENOTFOUND;goto on_return;} );    /* Make sure the module exists in the array. */    PJ_ASSERT_ON_FAIL(	mod->id>=0 && mod->id<PJ_ARRAY_SIZE(endpt->modules) &&			endpt->modules[mod->id] == mod,			{status = PJ_ENOTFOUND; goto on_return;});    /* Try to stop the module. */    if (mod->stop) {	status = (*mod->stop)();	if (status != PJ_SUCCESS) goto on_return;    }    /* Try to unload the module. */    if (mod->unload) {	status = (*mod->unload)();	if (status != PJ_SUCCESS) goto on_return;    }    /* Module MUST NOT set module ID to -1. */    pj_assert(mod->id >= 0);    /* Remove module from array. */    endpt->modules[mod->id] = NULL;    /* Remove module from list. */    pj_list_erase(mod);    /* Set module Id to -1. */    mod->id = -1;    /* Done. */    status = PJ_SUCCESS;    PJ_LOG(4,(THIS_FILE, "Module \"%.*s\" unregistered", 	      (int)mod->name.slen, mod->name.ptr));on_return:    pj_rwmutex_unlock_write(endpt->mod_mutex);    if (status != PJ_SUCCESS) {	char errmsg[PJ_ERR_MSG_SIZE];	pj_strerror(status, errmsg, sizeof(errmsg));	PJ_LOG(3,(THIS_FILE, "Module \"%.*s\" can not be unregistered: %s",		  (int)mod->name.slen, mod->name.ptr, errmsg));    }    return status;}/* * Get the value of the specified capability header field. */PJ_DEF(const pjsip_hdr*) pjsip_endpt_get_capability( pjsip_endpoint *endpt,						     int htype,						     const pj_str_t *hname){    pjsip_hdr *hdr = endpt->cap_hdr.next;    /* Check arguments. */    PJ_ASSERT_RETURN(endpt != NULL, NULL);    PJ_ASSERT_RETURN(htype != PJSIP_H_OTHER || hname, NULL);    if (htype != PJSIP_H_OTHER) {	while (hdr != &endpt->cap_hdr) {	    if (hdr->type == htype)		return hdr;	    hdr = hdr->next;	}    }    return NULL;}/* * Check if the specified capability is supported. */PJ_DEF(pj_bool_t) pjsip_endpt_has_capability( pjsip_endpoint *endpt,					      int htype,					      const pj_str_t *hname,					      const pj_str_t *token){    const pjsip_generic_array_hdr *hdr;    unsigned i;    hdr = (const pjsip_generic_array_hdr*) 	   pjsip_endpt_get_capability(endpt, htype, hname);    if (!hdr)	return PJ_FALSE;    PJ_ASSERT_RETURN(token != NULL, PJ_FALSE);    for (i=0; i<hdr->count; ++i) {	if (!pj_stricmp(&hdr->values[i], token))	    return PJ_TRUE;    }    return PJ_FALSE;}/* * Add or register new capabilities as indicated by the tags to the * appropriate header fields in the endpoint. */PJ_DEF(pj_status_t) pjsip_endpt_add_capability( pjsip_endpoint *endpt,						pjsip_module *mod,						int htype,						const pj_str_t *hname,						unsigned count,						const pj_str_t tags[]){    pjsip_generic_array_hdr *hdr;    unsigned i;    PJ_UNUSED_ARG(mod);    /* Check arguments. */    PJ_ASSERT_RETURN(endpt!=NULL && count>0 && tags, PJ_EINVAL);    PJ_ASSERT_RETURN(htype==PJSIP_H_ACCEPT || 		     htype==PJSIP_H_ALLOW ||		     htype==PJSIP_H_SUPPORTED,		     PJ_EINVAL);    /* Find the header. */    hdr = (pjsip_generic_array_hdr*) pjsip_endpt_get_capability(endpt, 								htype, hname);    /* Create the header when it's not present */    if (hdr == NULL) {	switch (htype) {	case PJSIP_H_ACCEPT:	    hdr = pjsip_accept_hdr_create(endpt->pool);	    break;	case PJSIP_H_ALLOW:	    hdr = pjsip_allow_hdr_create(endpt->pool);	    break;	case PJSIP_H_SUPPORTED:	    hdr = pjsip_supported_hdr_create(endpt->pool);	    break;	default:	    return PJ_EINVAL;	}	if (hdr) {	    pj_list_push_back(&endpt->cap_hdr, hdr);	}    }    /* Add the tags to the header. */    for (i=0; i<count; ++i) {	pj_strdup(endpt->pool, &hdr->values[hdr->count], &tags[i]);	++hdr->count;    }    /* Done. */    return PJ_SUCCESS;}/* * Get additional headers to be put in outgoing request message. */PJ_DEF(const pjsip_hdr*) pjsip_endpt_get_request_headers(pjsip_endpoint *endpt){    return &endpt->req_hdr;}/* * Initialize endpoint. */PJ_DEF(pj_status_t) pjsip_endpt_create(pj_pool_factory *pf,				       const char *name,                                       pjsip_endpoint **p_endpt){    pj_status_t status;    pj_pool_t *pool;    pjsip_endpoint *endpt;    pjsip_max_fwd_hdr *mf_hdr;    pj_lock_t *lock = NULL;    if (!error_subsys_initialized) {	pj_register_strerror(PJSIP_ERRNO_START, PJ_ERRNO_SPACE_SIZE,			     &pjsip_strerror);	error_subsys_initialized = 1;    }    PJ_LOG(5, (THIS_FILE, "Creating endpoint instance..."));    *p_endpt = NULL;    /* Create pool */    pool = pj_pool_create(pf, "pept%p", 			  PJSIP_POOL_LEN_ENDPT, PJSIP_POOL_INC_ENDPT,			  &pool_callback);    if (!pool)	return PJ_ENOMEM;    /* Create endpoint. */    endpt = pj_pool_zalloc(pool, sizeof(*endpt));    endpt->pool = pool;    endpt->pf = pf;    /* Init modules list. */    pj_list_init(&endpt->module_list);    /* Create R/W mutex for module manipulation. */    status = pj_rwmutex_create(endpt->pool, "ept%p", &endpt->mod_mutex);    if (status != PJ_SUCCESS)	goto on_error;    /* Init parser. */    init_sip_parser();    /* Init tel: uri */    pjsip_tel_uri_subsys_init();    /* Get name. */    if (name != NULL) {	pj_str_t temp;	pj_strdup_with_null(endpt->pool, &endpt->name, pj_cstr(&temp, name));    } else {	pj_strdup_with_null(endpt->pool, &endpt->name, pj_gethostname());    }    /* Create mutex for the events, etc. */    status = pj_mutex_create_recursive( endpt->pool, "ept%p", &endpt->mutex );    if (status != PJ_SUCCESS) {	goto on_error;    }    /* Create timer heap to manage all timers within this endpoint. */    status = pj_timer_heap_create( endpt->pool, PJSIP_MAX_TIMER_COUNT,                                    &endpt->timer_heap);    if (status != PJ_SUCCESS) {	goto on_error;    }    /* Set recursive lock for the timer heap. */    status = pj_lock_create_recursive_mutex( endpt->pool, "edpt%p", &lock);    if (status != PJ_SUCCESS) {	goto on_error;    }    pj_timer_heap_set_lock(endpt->timer_heap, lock, PJ_TRUE);    /* Set maximum timed out entries to process in a single poll. */    pj_timer_heap_set_max_timed_out_per_poll(endpt->timer_heap, 					     PJSIP_MAX_TIMED_OUT_ENTRIES);    /* Create ioqueue. */    status = pj_ioqueue_create( endpt->pool, PJSIP_MAX_TRANSPORTS, &endpt->ioqueue);    if (status != PJ_SUCCESS) {	goto on_error;    }    /* Create transport manager. */    status = pjsip_tpmgr_create( endpt->pool, endpt,			         &endpt_on_rx_msg,				 &endpt_on_tx_msg,				 &endpt->transport_mgr);    if (status != PJ_SUCCESS) {	goto on_error;    }    /* Create asynchronous DNS resolver. */    status = pjsip_resolver_create(endpt->pool, &endpt->resolver);    if (status != PJ_SUCCESS) {	PJ_LOG(4, (THIS_FILE, "Error creating resolver instance"));	goto on_error;    }    /* Initialize request headers. */    pj_list_init(&endpt->req_hdr);    /* Add "Max-Forwards" for request header. */    mf_hdr = pjsip_max_fwd_hdr_create(endpt->pool,				      PJSIP_MAX_FORWARDS_VALUE);    pj_list_insert_before( &endpt->req_hdr, mf_hdr);    /* Initialize capability header list. */    pj_list_init(&endpt->cap_hdr);    /* Done. */    *p_endpt = endpt;    return status;on_error:    if (endpt->transport_mgr) {	pjsip_tpmgr_destroy(endpt->transport_mgr);	endpt->transport_mgr = NULL;    }    if (endpt->ioqueue) {	pj_ioqueue_destroy(endpt->ioqueue);	endpt->ioqueue = NULL;    }    if (endpt->timer_heap) {	pj_timer_heap_destroy(endpt->timer_heap);	endpt->timer_heap = NULL;    }    if (endpt->mutex) {	pj_mutex_destroy(endpt->mutex);	endpt->mutex = NULL;    }    if (endpt->mod_mutex) {	pj_rwmutex_destroy(endpt->mod_mutex);	endpt->mod_mutex = NULL;    }    pj_pool_release( endpt->pool );    PJ_LOG(4, (THIS_FILE, "Error creating endpoint"));    return status;}/* * Destroy endpoint. */PJ_DEF(void) pjsip_endpt_destroy(pjsip_endpoint *endpt){    pjsip_module *mod;    PJ_LOG(5, (THIS_FILE, "Destroying endpoing instance.."));    /* Unregister modules. */    mod = endpt->module_list.prev;    while (mod != &endpt->module_list) {

⌨️ 快捷键说明

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