📄 sip_endpoint.c
字号:
/* $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 + -