2005-11-21 01:55:47 +00:00
|
|
|
/*
|
2011-05-05 06:14:19 +00:00
|
|
|
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
|
2008-06-20 22:44:47 +00:00
|
|
|
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
|
2005-11-21 01:55:47 +00:00
|
|
|
*
|
|
|
|
* 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>
|
2017-09-29 02:43:05 +00:00
|
|
|
#include <pj/math.h>
|
2005-11-21 01:55:47 +00:00
|
|
|
|
2007-08-16 10:11:44 +00:00
|
|
|
#define PJSIP_EX_NO_MEMORY pj_NO_MEMORY_EXCEPTION()
|
2006-01-07 18:44:25 +00:00
|
|
|
#define THIS_FILE "sip_endpoint.c"
|
2005-11-21 01:55:47 +00:00
|
|
|
|
|
|
|
#define MAX_METHODS 32
|
|
|
|
|
2012-03-30 07:10:13 +00:00
|
|
|
|
|
|
|
/* List of SIP endpoint exit callback. */
|
|
|
|
typedef struct exit_cb
|
|
|
|
{
|
|
|
|
PJ_DECL_LIST_MEMBER (struct exit_cb);
|
|
|
|
pjsip_endpt_exit_callback func;
|
|
|
|
} exit_cb;
|
|
|
|
|
|
|
|
|
2005-11-21 01:55:47 +00:00
|
|
|
/**
|
|
|
|
* 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;
|
|
|
|
|
2006-02-27 23:54:58 +00:00
|
|
|
/** Last ioqueue err */
|
|
|
|
pj_status_t ioq_last_err;
|
|
|
|
|
2005-11-21 01:55:47 +00:00
|
|
|
/** DNS Resolver. */
|
|
|
|
pjsip_resolver_t *resolver;
|
|
|
|
|
2005-12-30 23:50:15 +00:00
|
|
|
/** Modules lock. */
|
|
|
|
pj_rwmutex_t *mod_mutex;
|
2005-11-21 01:55:47 +00:00
|
|
|
|
|
|
|
/** Modules. */
|
|
|
|
pjsip_module *modules[PJSIP_MAX_MODULE];
|
|
|
|
|
2005-12-30 23:50:15 +00:00
|
|
|
/** Module list, sorted by priority. */
|
|
|
|
pjsip_module module_list;
|
|
|
|
|
2006-01-30 18:40:05 +00:00
|
|
|
/** Capability header list. */
|
|
|
|
pjsip_hdr cap_hdr;
|
|
|
|
|
2005-11-21 01:55:47 +00:00
|
|
|
/** Additional request headers. */
|
|
|
|
pjsip_hdr req_hdr;
|
2012-03-30 07:10:13 +00:00
|
|
|
|
|
|
|
/** List of exit callback. */
|
|
|
|
exit_cb exit_cb_list;
|
2005-11-21 01:55:47 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2006-07-03 14:18:17 +00:00
|
|
|
#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
|
|
|
|
|
|
|
|
|
2005-11-21 01:55:47 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Prototypes.
|
|
|
|
*/
|
2006-01-07 18:44:25 +00:00
|
|
|
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 );
|
2008-07-12 21:10:25 +00:00
|
|
|
static pj_status_t unload_module(pjsip_endpoint *endpt,
|
|
|
|
pjsip_module *mod);
|
2005-11-21 01:55:47 +00:00
|
|
|
|
2005-11-23 20:56:30 +00:00
|
|
|
/* Defined in sip_parser.c */
|
2005-11-22 23:51:50 +00:00
|
|
|
void init_sip_parser(void);
|
2006-12-01 11:14:37 +00:00
|
|
|
void deinit_sip_parser(void);
|
2005-11-21 01:55:47 +00:00
|
|
|
|
2005-11-23 20:56:30 +00:00
|
|
|
/* Defined in sip_tel_uri.c */
|
|
|
|
pj_status_t pjsip_tel_uri_subsys_init(void);
|
|
|
|
|
2006-02-09 00:13:40 +00:00
|
|
|
|
2005-11-21 01:55:47 +00:00
|
|
|
/*
|
|
|
|
* 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-01-08 23:57:07 +00:00
|
|
|
/* Compare module name, used for searching module based on name. */
|
2006-02-07 20:56:50 +00:00
|
|
|
static int cmp_mod_name(void *name, const void *mod)
|
2006-01-08 23:57:07 +00:00
|
|
|
{
|
2007-05-01 16:54:54 +00:00
|
|
|
return pj_stricmp((const pj_str_t*)name, &((pjsip_module*)mod)->name);
|
2006-01-08 23:57:07 +00:00
|
|
|
}
|
|
|
|
|
2005-11-21 01:55:47 +00:00
|
|
|
/*
|
2005-12-30 23:50:15 +00:00
|
|
|
* 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.
|
2005-11-21 01:55:47 +00:00
|
|
|
*/
|
2005-12-30 23:50:15 +00:00
|
|
|
PJ_DEF(pj_status_t) pjsip_endpt_register_module( pjsip_endpoint *endpt,
|
|
|
|
pjsip_module *mod )
|
2005-11-21 01:55:47 +00:00
|
|
|
{
|
2005-12-30 23:50:15 +00:00
|
|
|
pj_status_t status = PJ_SUCCESS;
|
|
|
|
pjsip_module *m;
|
2007-05-11 15:14:34 +00:00
|
|
|
unsigned i;
|
2005-11-21 01:55:47 +00:00
|
|
|
|
2005-12-30 23:50:15 +00:00
|
|
|
pj_rwmutex_lock_write(endpt->mod_mutex);
|
2005-11-21 01:55:47 +00:00
|
|
|
|
2005-12-30 23:50:15 +00:00
|
|
|
/* 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;});
|
2005-11-21 01:55:47 +00:00
|
|
|
|
2006-01-08 23:57:07 +00:00
|
|
|
/* 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; });
|
|
|
|
|
2005-12-30 23:50:15 +00:00
|
|
|
/* 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;
|
2005-11-21 01:55:47 +00:00
|
|
|
}
|
|
|
|
|
2005-12-30 23:50:15 +00:00
|
|
|
/* Assign the ID. */
|
|
|
|
mod->id = i;
|
2005-11-21 01:55:47 +00:00
|
|
|
|
2005-12-30 23:50:15 +00:00
|
|
|
/* Try to load the module. */
|
|
|
|
if (mod->load) {
|
|
|
|
status = (*mod->load)(endpt);
|
|
|
|
if (status != PJ_SUCCESS)
|
|
|
|
goto on_return;
|
2005-11-21 01:55:47 +00:00
|
|
|
}
|
|
|
|
|
2005-12-30 23:50:15 +00:00
|
|
|
/* Try to start the module. */
|
|
|
|
if (mod->start) {
|
|
|
|
status = (*mod->start)();
|
|
|
|
if (status != PJ_SUCCESS)
|
|
|
|
goto on_return;
|
2005-11-21 01:55:47 +00:00
|
|
|
}
|
|
|
|
|
2005-12-30 23:50:15 +00:00
|
|
|
/* 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;
|
2005-11-21 01:55:47 +00:00
|
|
|
}
|
2005-12-30 23:50:15 +00:00
|
|
|
pj_list_insert_before(m, mod);
|
2005-11-21 01:55:47 +00:00
|
|
|
|
|
|
|
/* Done. */
|
2005-12-30 23:50:15 +00:00
|
|
|
|
2006-02-19 01:38:06 +00:00
|
|
|
PJ_LOG(4,(THIS_FILE, "Module \"%.*s\" registered",
|
|
|
|
(int)mod->name.slen, mod->name.ptr));
|
|
|
|
|
2005-12-30 23:50:15 +00:00
|
|
|
on_return:
|
|
|
|
pj_rwmutex_unlock_write(endpt->mod_mutex);
|
|
|
|
return status;
|
2005-11-21 01:55:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2005-12-30 23:50:15 +00:00
|
|
|
* Unregister a module from the endpoint.
|
|
|
|
* The endpoint will then call the stop and unload function in the module to
|
|
|
|
* properly shutdown the module.
|
2005-11-21 01:55:47 +00:00
|
|
|
*/
|
2005-12-30 23:50:15 +00:00
|
|
|
PJ_DEF(pj_status_t) pjsip_endpt_unregister_module( pjsip_endpoint *endpt,
|
|
|
|
pjsip_module *mod )
|
2005-11-21 01:55:47 +00:00
|
|
|
{
|
2005-12-30 23:50:15 +00:00
|
|
|
pj_status_t status;
|
2005-11-21 01:55:47 +00:00
|
|
|
|
2005-12-30 23:50:15 +00:00
|
|
|
pj_rwmutex_lock_write(endpt->mod_mutex);
|
2005-11-21 01:55:47 +00:00
|
|
|
|
2005-12-30 23:50:15 +00:00
|
|
|
/* 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;} );
|
2005-11-21 01:55:47 +00:00
|
|
|
|
2005-12-30 23:50:15 +00:00
|
|
|
/* Make sure the module exists in the array. */
|
2007-05-11 15:14:34 +00:00
|
|
|
PJ_ASSERT_ON_FAIL( mod->id>=0 &&
|
|
|
|
mod->id<(int)PJ_ARRAY_SIZE(endpt->modules) &&
|
2005-12-30 23:50:15 +00:00
|
|
|
endpt->modules[mod->id] == mod,
|
|
|
|
{status = PJ_ENOTFOUND; goto on_return;});
|
2005-11-21 01:55:47 +00:00
|
|
|
|
2005-12-30 23:50:15 +00:00
|
|
|
/* Try to stop the module. */
|
|
|
|
if (mod->stop) {
|
|
|
|
status = (*mod->stop)();
|
|
|
|
if (status != PJ_SUCCESS) goto on_return;
|
|
|
|
}
|
2005-11-21 01:55:47 +00:00
|
|
|
|
2008-07-12 21:10:25 +00:00
|
|
|
/* Unload module */
|
|
|
|
status = unload_module(endpt, mod);
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
static pj_status_t unload_module(pjsip_endpoint *endpt,
|
|
|
|
pjsip_module *mod)
|
|
|
|
{
|
|
|
|
pj_status_t status;
|
|
|
|
|
2005-12-30 23:50:15 +00:00
|
|
|
/* Try to unload the module. */
|
|
|
|
if (mod->unload) {
|
|
|
|
status = (*mod->unload)();
|
2008-07-12 21:10:25 +00:00
|
|
|
if (status != PJ_SUCCESS)
|
|
|
|
return status;
|
2005-12-30 23:50:15 +00:00
|
|
|
}
|
2005-11-21 01:55:47 +00:00
|
|
|
|
2006-02-19 01:38:06 +00:00
|
|
|
/* Module MUST NOT set module ID to -1. */
|
|
|
|
pj_assert(mod->id >= 0);
|
|
|
|
|
2005-12-30 23:50:15 +00:00
|
|
|
/* Remove module from array. */
|
|
|
|
endpt->modules[mod->id] = NULL;
|
2005-11-21 01:55:47 +00:00
|
|
|
|
2005-12-30 23:50:15 +00:00
|
|
|
/* Remove module from list. */
|
|
|
|
pj_list_erase(mod);
|
2005-11-21 01:55:47 +00:00
|
|
|
|
2006-01-07 18:44:25 +00:00
|
|
|
/* Set module Id to -1. */
|
|
|
|
mod->id = -1;
|
|
|
|
|
2005-12-30 23:50:15 +00:00
|
|
|
/* Done. */
|
|
|
|
status = PJ_SUCCESS;
|
2005-11-21 01:55:47 +00:00
|
|
|
|
2006-02-19 01:38:06 +00:00
|
|
|
PJ_LOG(4,(THIS_FILE, "Module \"%.*s\" unregistered",
|
|
|
|
(int)mod->name.slen, mod->name.ptr));
|
|
|
|
|
2005-12-30 23:50:15 +00:00
|
|
|
return status;
|
2005-11-21 01:55:47 +00:00
|
|
|
}
|
|
|
|
|
2006-01-30 18:40:05 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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) {
|
2023-03-14 01:56:18 +00:00
|
|
|
if ((int)hdr->type == htype)
|
2006-01-30 18:40:05 +00:00
|
|
|
return hdr;
|
|
|
|
hdr = hdr->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-11-11 16:16:04 +00:00
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
2005-11-21 01:55:47 +00:00
|
|
|
/*
|
2006-01-30 18:40:05 +00:00
|
|
|
* Add or register new capabilities as indicated by the tags to the
|
|
|
|
* appropriate header fields in the endpoint.
|
2005-11-21 01:55:47 +00:00
|
|
|
*/
|
2006-01-30 18:40:05 +00:00
|
|
|
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[])
|
2005-11-21 01:55:47 +00:00
|
|
|
{
|
2006-01-30 18:40:05 +00:00
|
|
|
pjsip_generic_array_hdr *hdr;
|
|
|
|
unsigned i;
|
|
|
|
|
2006-08-15 20:26:34 +00:00
|
|
|
PJ_UNUSED_ARG(mod);
|
|
|
|
|
2006-01-30 18:40:05 +00:00
|
|
|
/* Check arguments. */
|
2006-08-15 20:26:34 +00:00
|
|
|
PJ_ASSERT_RETURN(endpt!=NULL && count>0 && tags, PJ_EINVAL);
|
2016-07-26 02:58:44 +00:00
|
|
|
PJ_ASSERT_RETURN(count <= PJSIP_GENERIC_ARRAY_MAX_COUNT, PJ_ETOOMANY);
|
2006-01-30 18:40:05 +00:00
|
|
|
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;
|
|
|
|
}
|
2022-11-22 09:26:54 +00:00
|
|
|
|
2023-04-06 02:26:10 +00:00
|
|
|
if (hdr == NULL) {
|
|
|
|
return PJ_ENOMEM;
|
2006-02-07 12:34:11 +00:00
|
|
|
}
|
2023-04-06 02:26:10 +00:00
|
|
|
pj_list_push_back(&endpt->cap_hdr, hdr);
|
2006-01-30 18:40:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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;
|
2005-11-21 01:55:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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;
|
2006-01-30 18:40:05 +00:00
|
|
|
pjsip_max_fwd_hdr *mf_hdr;
|
2005-11-21 01:55:47 +00:00
|
|
|
pj_lock_t *lock = NULL;
|
|
|
|
|
2006-02-09 00:13:40 +00:00
|
|
|
|
2011-03-16 07:34:16 +00:00
|
|
|
status = pj_register_strerror(PJSIP_ERRNO_START, PJ_ERRNO_SPACE_SIZE,
|
|
|
|
&pjsip_strerror);
|
|
|
|
pj_assert(status == PJ_SUCCESS);
|
2006-02-09 00:13:40 +00:00
|
|
|
|
2006-01-07 18:44:25 +00:00
|
|
|
PJ_LOG(5, (THIS_FILE, "Creating endpoint instance..."));
|
2005-11-21 01:55:47 +00:00
|
|
|
|
|
|
|
*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. */
|
2007-05-01 16:54:54 +00:00
|
|
|
endpt = PJ_POOL_ZALLOC_T(pool, pjsip_endpoint);
|
2005-11-21 01:55:47 +00:00
|
|
|
endpt->pool = pool;
|
|
|
|
endpt->pf = pf;
|
|
|
|
|
2005-12-30 23:50:15 +00:00
|
|
|
/* Init modules list. */
|
|
|
|
pj_list_init(&endpt->module_list);
|
|
|
|
|
2012-03-30 07:10:13 +00:00
|
|
|
/* Initialize exit callback list. */
|
|
|
|
pj_list_init(&endpt->exit_cb_list);
|
|
|
|
|
2005-12-30 23:50:15 +00:00
|
|
|
/* 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;
|
|
|
|
|
2005-11-22 23:51:50 +00:00
|
|
|
/* Init parser. */
|
|
|
|
init_sip_parser();
|
|
|
|
|
2005-11-23 20:56:30 +00:00
|
|
|
/* Init tel: uri */
|
|
|
|
pjsip_tel_uri_subsys_init();
|
|
|
|
|
2005-11-21 01:55:47 +00:00
|
|
|
/* 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,
|
2006-01-07 18:44:25 +00:00
|
|
|
&endpt_on_rx_msg,
|
|
|
|
&endpt_on_tx_msg,
|
2005-11-21 01:55:47 +00:00
|
|
|
&endpt->transport_mgr);
|
|
|
|
if (status != PJ_SUCCESS) {
|
|
|
|
goto on_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create asynchronous DNS resolver. */
|
2006-10-08 12:39:34 +00:00
|
|
|
status = pjsip_resolver_create(endpt->pool, &endpt->resolver);
|
|
|
|
if (status != PJ_SUCCESS) {
|
2019-05-09 08:18:18 +00:00
|
|
|
PJ_PERROR(4, (THIS_FILE, status,
|
|
|
|
"Error creating resolver instance"));
|
2005-11-21 01:55:47 +00:00
|
|
|
goto on_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initialize request headers. */
|
|
|
|
pj_list_init(&endpt->req_hdr);
|
|
|
|
|
|
|
|
/* Add "Max-Forwards" for request header. */
|
2006-01-30 18:40:05 +00:00
|
|
|
mf_hdr = pjsip_max_fwd_hdr_create(endpt->pool,
|
|
|
|
PJSIP_MAX_FORWARDS_VALUE);
|
2005-11-21 01:55:47 +00:00
|
|
|
pj_list_insert_before( &endpt->req_hdr, mf_hdr);
|
|
|
|
|
2006-01-30 18:40:05 +00:00
|
|
|
/* Initialize capability header list. */
|
|
|
|
pj_list_init(&endpt->cap_hdr);
|
|
|
|
|
2006-02-07 18:48:01 +00:00
|
|
|
|
2005-11-21 01:55:47 +00:00
|
|
|
/* Done. */
|
|
|
|
*p_endpt = endpt;
|
|
|
|
return status;
|
|
|
|
|
|
|
|
on_error:
|
|
|
|
if (endpt->transport_mgr) {
|
|
|
|
pjsip_tpmgr_destroy(endpt->transport_mgr);
|
|
|
|
endpt->transport_mgr = NULL;
|
|
|
|
}
|
2006-11-21 08:37:17 +00:00
|
|
|
if (endpt->ioqueue) {
|
|
|
|
pj_ioqueue_destroy(endpt->ioqueue);
|
|
|
|
endpt->ioqueue = NULL;
|
|
|
|
}
|
2006-11-21 18:41:47 +00:00
|
|
|
if (endpt->timer_heap) {
|
|
|
|
pj_timer_heap_destroy(endpt->timer_heap);
|
|
|
|
endpt->timer_heap = NULL;
|
|
|
|
}
|
2005-11-21 01:55:47 +00:00
|
|
|
if (endpt->mutex) {
|
|
|
|
pj_mutex_destroy(endpt->mutex);
|
|
|
|
endpt->mutex = NULL;
|
|
|
|
}
|
2013-05-30 08:32:07 +00:00
|
|
|
deinit_sip_parser();
|
2005-12-30 23:50:15 +00:00
|
|
|
if (endpt->mod_mutex) {
|
|
|
|
pj_rwmutex_destroy(endpt->mod_mutex);
|
|
|
|
endpt->mod_mutex = NULL;
|
2005-11-21 01:55:47 +00:00
|
|
|
}
|
|
|
|
pj_pool_release( endpt->pool );
|
|
|
|
|
2019-05-09 08:18:18 +00:00
|
|
|
PJ_PERROR(4, (THIS_FILE, status, "Error creating endpoint"));
|
2005-11-21 01:55:47 +00:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Destroy endpoint.
|
|
|
|
*/
|
|
|
|
PJ_DEF(void) pjsip_endpt_destroy(pjsip_endpoint *endpt)
|
|
|
|
{
|
2006-01-07 18:44:25 +00:00
|
|
|
pjsip_module *mod;
|
2012-03-30 07:10:13 +00:00
|
|
|
exit_cb *ecb;
|
2006-01-07 18:44:25 +00:00
|
|
|
|
2019-05-09 08:18:18 +00:00
|
|
|
PJ_LOG(5, (THIS_FILE, "Destroying endpoint instance.."));
|
2006-01-07 18:44:25 +00:00
|
|
|
|
2008-07-12 21:10:25 +00:00
|
|
|
/* Phase 1: stop all modules */
|
|
|
|
mod = endpt->module_list.prev;
|
|
|
|
while (mod != &endpt->module_list) {
|
|
|
|
pjsip_module *prev = mod->prev;
|
|
|
|
if (mod->stop) {
|
|
|
|
(*mod->stop)();
|
|
|
|
}
|
|
|
|
mod = prev;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Phase 2: unload modules. */
|
2006-07-18 00:10:53 +00:00
|
|
|
mod = endpt->module_list.prev;
|
|
|
|
while (mod != &endpt->module_list) {
|
|
|
|
pjsip_module *prev = mod->prev;
|
2008-07-12 21:10:25 +00:00
|
|
|
unload_module(endpt, mod);
|
2006-07-18 00:10:53 +00:00
|
|
|
mod = prev;
|
2006-01-07 18:44:25 +00:00
|
|
|
}
|
2005-11-21 01:55:47 +00:00
|
|
|
|
2007-05-30 15:20:56 +00:00
|
|
|
/* Destroy resolver */
|
|
|
|
pjsip_resolver_destroy(endpt->resolver);
|
|
|
|
|
2005-11-21 01:55:47 +00:00
|
|
|
/* Shutdown and destroy all transports. */
|
|
|
|
pjsip_tpmgr_destroy(endpt->transport_mgr);
|
|
|
|
|
2006-11-21 08:37:17 +00:00
|
|
|
/* Destroy ioqueue */
|
|
|
|
pj_ioqueue_destroy(endpt->ioqueue);
|
|
|
|
|
2006-11-21 18:41:47 +00:00
|
|
|
/* Destroy timer heap */
|
2012-06-05 10:41:17 +00:00
|
|
|
#if PJ_TIMER_DEBUG
|
|
|
|
pj_timer_heap_dump(endpt->timer_heap);
|
|
|
|
#endif
|
2006-11-21 18:41:47 +00:00
|
|
|
pj_timer_heap_destroy(endpt->timer_heap);
|
|
|
|
|
2012-03-30 07:10:13 +00:00
|
|
|
/* Call all registered exit callbacks */
|
|
|
|
ecb = endpt->exit_cb_list.next;
|
|
|
|
while (ecb != &endpt->exit_cb_list) {
|
|
|
|
(*ecb->func)(endpt);
|
|
|
|
ecb = ecb->next;
|
|
|
|
}
|
|
|
|
|
2005-11-21 01:55:47 +00:00
|
|
|
/* Delete endpoint mutex. */
|
|
|
|
pj_mutex_destroy(endpt->mutex);
|
|
|
|
|
2006-12-01 11:14:37 +00:00
|
|
|
/* Deinit parser */
|
|
|
|
deinit_sip_parser();
|
|
|
|
|
2006-11-21 12:39:31 +00:00
|
|
|
/* Delete module's mutex */
|
|
|
|
pj_rwmutex_destroy(endpt->mod_mutex);
|
|
|
|
|
2005-11-21 01:55:47 +00:00
|
|
|
/* Finally destroy pool. */
|
|
|
|
pj_pool_release(endpt->pool);
|
2006-01-07 18:44:25 +00:00
|
|
|
|
|
|
|
PJ_LOG(4, (THIS_FILE, "Endpoint %p destroyed", endpt));
|
2005-11-21 01:55:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get endpoint name.
|
|
|
|
*/
|
|
|
|
PJ_DEF(const pj_str_t*) pjsip_endpt_name(const pjsip_endpoint *endpt)
|
|
|
|
{
|
|
|
|
return &endpt->name;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create new pool.
|
|
|
|
*/
|
|
|
|
PJ_DEF(pj_pool_t*) pjsip_endpt_create_pool( pjsip_endpoint *endpt,
|
|
|
|
const char *pool_name,
|
|
|
|
pj_size_t initial,
|
|
|
|
pj_size_t increment )
|
|
|
|
{
|
|
|
|
pj_pool_t *pool;
|
|
|
|
|
|
|
|
/* Lock endpoint mutex. */
|
2006-06-28 16:14:17 +00:00
|
|
|
/* No need to lock mutex. Factory is thread safe.
|
2005-11-21 01:55:47 +00:00
|
|
|
pj_mutex_lock(endpt->mutex);
|
2006-06-28 16:14:17 +00:00
|
|
|
*/
|
2005-11-21 01:55:47 +00:00
|
|
|
|
|
|
|
/* Create pool */
|
|
|
|
pool = pj_pool_create( endpt->pf, pool_name,
|
|
|
|
initial, increment, &pool_callback);
|
|
|
|
|
|
|
|
/* Unlock mutex. */
|
2006-06-28 16:14:17 +00:00
|
|
|
/* No need to lock mutex. Factory is thread safe.
|
2005-11-21 01:55:47 +00:00
|
|
|
pj_mutex_unlock(endpt->mutex);
|
2006-06-28 16:14:17 +00:00
|
|
|
*/
|
2005-11-21 01:55:47 +00:00
|
|
|
|
2006-01-07 18:44:25 +00:00
|
|
|
if (!pool) {
|
2005-11-21 01:55:47 +00:00
|
|
|
PJ_LOG(4, (THIS_FILE, "Unable to create pool %s!", pool_name));
|
|
|
|
}
|
|
|
|
|
|
|
|
return pool;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Return back pool to endpoint's pool manager to be either destroyed or
|
|
|
|
* recycled.
|
|
|
|
*/
|
2006-01-05 23:35:46 +00:00
|
|
|
PJ_DEF(void) pjsip_endpt_release_pool( pjsip_endpoint *endpt, pj_pool_t *pool )
|
2005-11-21 01:55:47 +00:00
|
|
|
{
|
2006-01-07 18:44:25 +00:00
|
|
|
PJ_LOG(6, (THIS_FILE, "Releasing pool %s", pj_pool_getobjname(pool)));
|
2005-11-21 01:55:47 +00:00
|
|
|
|
2006-07-03 14:18:17 +00:00
|
|
|
/* Don't need to acquire mutex since pool factory is thread safe
|
|
|
|
pj_mutex_lock(endpt->mutex);
|
|
|
|
*/
|
2005-11-21 01:55:47 +00:00
|
|
|
pj_pool_release( pool );
|
2006-07-03 14:18:17 +00:00
|
|
|
|
2006-07-18 00:10:53 +00:00
|
|
|
PJ_UNUSED_ARG(endpt);
|
2006-07-03 14:18:17 +00:00
|
|
|
/*
|
2005-11-21 01:55:47 +00:00
|
|
|
pj_mutex_unlock(endpt->mutex);
|
2006-07-03 14:18:17 +00:00
|
|
|
*/
|
2005-11-21 01:55:47 +00:00
|
|
|
}
|
|
|
|
|
2006-06-01 11:41:38 +00:00
|
|
|
|
|
|
|
PJ_DEF(pj_status_t) pjsip_endpt_handle_events2(pjsip_endpoint *endpt,
|
|
|
|
const pj_time_val *max_timeout,
|
|
|
|
unsigned *p_count)
|
2005-11-21 01:55:47 +00:00
|
|
|
{
|
2017-09-29 02:43:05 +00:00
|
|
|
enum { MAX_TIMEOUT_ON_ERR = 10 };
|
2005-11-21 01:55:47 +00:00
|
|
|
/* timeout is 'out' var. This just to make compiler happy. */
|
|
|
|
pj_time_val timeout = { 0, 0};
|
2006-07-10 21:30:34 +00:00
|
|
|
unsigned count = 0, net_event_count = 0;
|
2006-06-01 11:41:38 +00:00
|
|
|
int c;
|
2005-11-21 01:55:47 +00:00
|
|
|
|
2006-01-07 18:44:25 +00:00
|
|
|
PJ_LOG(6, (THIS_FILE, "pjsip_endpt_handle_events()"));
|
2005-11-21 01:55:47 +00:00
|
|
|
|
|
|
|
/* Poll the timer. The timer heap has its own mutex for better
|
|
|
|
* granularity, so we don't need to lock end endpoint.
|
|
|
|
*/
|
|
|
|
timeout.sec = timeout.msec = 0;
|
2006-06-01 11:41:38 +00:00
|
|
|
c = pj_timer_heap_poll( endpt->timer_heap, &timeout );
|
|
|
|
if (c > 0)
|
|
|
|
count += c;
|
2005-11-21 01:55:47 +00:00
|
|
|
|
2006-03-01 19:29:10 +00:00
|
|
|
/* timer_heap_poll should never ever returns negative value, or otherwise
|
|
|
|
* ioqueue_poll() will block forever!
|
|
|
|
*/
|
|
|
|
pj_assert(timeout.sec >= 0 && timeout.msec >= 0);
|
2007-02-28 15:36:19 +00:00
|
|
|
if (timeout.msec >= 1000) timeout.msec = 999;
|
2006-03-01 19:29:10 +00:00
|
|
|
|
2005-11-21 01:55:47 +00:00
|
|
|
/* If caller specifies maximum time to wait, then compare the value with
|
|
|
|
* the timeout to wait from timer, and use the minimum value.
|
|
|
|
*/
|
|
|
|
if (max_timeout && PJ_TIME_VAL_GT(timeout, *max_timeout)) {
|
|
|
|
timeout = *max_timeout;
|
|
|
|
}
|
|
|
|
|
2006-07-10 21:30:34 +00:00
|
|
|
/* Poll ioqueue.
|
|
|
|
* Repeat polling the ioqueue while we have immediate events, because
|
|
|
|
* timer heap may process more than one events, so if we only process
|
|
|
|
* one network events at a time (such as when IOCP backend is used),
|
|
|
|
* the ioqueue may have trouble keeping up with the request rate.
|
|
|
|
*
|
|
|
|
* For example, for each send() request, one network event will be
|
|
|
|
* reported by ioqueue for the send() completion. If we don't poll
|
|
|
|
* the ioqueue often enough, the send() completion will not be
|
|
|
|
* reported in timely manner.
|
|
|
|
*/
|
|
|
|
do {
|
|
|
|
c = pj_ioqueue_poll( endpt->ioqueue, &timeout);
|
|
|
|
if (c < 0) {
|
2008-08-19 16:18:02 +00:00
|
|
|
pj_status_t err = pj_get_netos_error();
|
2017-09-29 02:43:05 +00:00
|
|
|
#if PJSIP_HANDLE_EVENTS_HAS_SLEEP_ON_ERR
|
|
|
|
unsigned msec = PJ_TIME_VAL_MSEC(timeout);
|
|
|
|
pj_thread_sleep(PJ_MIN(msec, MAX_TIMEOUT_ON_ERR));
|
|
|
|
#endif
|
|
|
|
|
2006-07-10 21:30:34 +00:00
|
|
|
if (p_count)
|
|
|
|
*p_count = count;
|
2008-08-19 16:18:02 +00:00
|
|
|
return err;
|
2006-07-10 21:30:34 +00:00
|
|
|
} else if (c == 0) {
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
net_event_count += c;
|
|
|
|
timeout.sec = timeout.msec = 0;
|
|
|
|
}
|
2006-07-11 09:53:27 +00:00
|
|
|
} while (c > 0 && net_event_count < PJSIP_MAX_NET_EVENTS);
|
2006-07-10 21:30:34 +00:00
|
|
|
|
|
|
|
count += net_event_count;
|
|
|
|
if (p_count)
|
|
|
|
*p_count = count;
|
|
|
|
|
|
|
|
return PJ_SUCCESS;
|
2005-11-21 01:55:47 +00:00
|
|
|
}
|
|
|
|
|
2006-06-01 11:41:38 +00:00
|
|
|
/*
|
|
|
|
* Handle events.
|
|
|
|
*/
|
|
|
|
PJ_DEF(pj_status_t) pjsip_endpt_handle_events(pjsip_endpoint *endpt,
|
|
|
|
const pj_time_val *max_timeout)
|
|
|
|
{
|
|
|
|
return pjsip_endpt_handle_events2(endpt, max_timeout, NULL);
|
|
|
|
}
|
|
|
|
|
2005-11-21 01:55:47 +00:00
|
|
|
/*
|
|
|
|
* Schedule timer.
|
|
|
|
*/
|
2012-06-05 10:41:17 +00:00
|
|
|
#if PJ_TIMER_DEBUG
|
|
|
|
PJ_DEF(pj_status_t) pjsip_endpt_schedule_timer_dbg(pjsip_endpoint *endpt,
|
|
|
|
pj_timer_entry *entry,
|
|
|
|
const pj_time_val *delay,
|
|
|
|
const char *src_file,
|
|
|
|
int src_line)
|
|
|
|
{
|
2023-11-16 07:30:03 +00:00
|
|
|
PJ_LOG(6, (THIS_FILE, "pjsip_endpt_schedule_timer(entry=%p, delay=%lu.%lu)",
|
2023-12-27 02:32:32 +00:00
|
|
|
entry, (unsigned long)delay->sec,
|
|
|
|
(unsigned long)delay->msec));
|
2012-06-05 10:41:17 +00:00
|
|
|
return pj_timer_heap_schedule_dbg(endpt->timer_heap, entry, delay,
|
|
|
|
src_file, src_line);
|
|
|
|
}
|
|
|
|
#else
|
2005-11-21 01:55:47 +00:00
|
|
|
PJ_DEF(pj_status_t) pjsip_endpt_schedule_timer( pjsip_endpoint *endpt,
|
|
|
|
pj_timer_entry *entry,
|
|
|
|
const pj_time_val *delay )
|
|
|
|
{
|
2023-12-27 02:32:32 +00:00
|
|
|
PJ_LOG(6, (THIS_FILE, "pjsip_endpt_schedule_timer(entry=%p, delay=%lu.%lu)",
|
|
|
|
entry, (unsigned long)delay->sec,
|
|
|
|
(unsigned long)delay->msec));
|
2005-11-21 01:55:47 +00:00
|
|
|
return pj_timer_heap_schedule( endpt->timer_heap, entry, delay );
|
|
|
|
}
|
2012-06-05 10:41:17 +00:00
|
|
|
#endif
|
2005-11-21 01:55:47 +00:00
|
|
|
|
2019-04-23 08:42:45 +00:00
|
|
|
/*
|
|
|
|
* Schedule timer with group lock.
|
|
|
|
*/
|
|
|
|
#if PJ_TIMER_DEBUG
|
|
|
|
PJ_DEF(pj_status_t) pjsip_endpt_schedule_timer_w_grp_lock_dbg(
|
|
|
|
pjsip_endpoint *endpt,
|
|
|
|
pj_timer_entry *entry,
|
|
|
|
const pj_time_val *delay,
|
|
|
|
int id_val,
|
|
|
|
pj_grp_lock_t *grp_lock,
|
|
|
|
const char *src_file,
|
|
|
|
int src_line)
|
|
|
|
{
|
|
|
|
PJ_LOG(6, (THIS_FILE, "pjsip_endpt_schedule_timer_w_grp_lock"
|
2023-12-27 02:32:32 +00:00
|
|
|
"(entry=%p, delay=%lu.%lu, grp_lock=%p)",
|
|
|
|
entry, (unsigned long)delay->sec,
|
|
|
|
(unsigned long)delay->msec, grp_lock));
|
2019-04-23 08:42:45 +00:00
|
|
|
return pj_timer_heap_schedule_w_grp_lock_dbg(endpt->timer_heap, entry,
|
|
|
|
delay, id_val, grp_lock,
|
|
|
|
src_file, src_line);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
PJ_DEF(pj_status_t) pjsip_endpt_schedule_timer_w_grp_lock(
|
|
|
|
pjsip_endpoint *endpt,
|
|
|
|
pj_timer_entry *entry,
|
|
|
|
const pj_time_val *delay,
|
|
|
|
int id_val,
|
|
|
|
pj_grp_lock_t *grp_lock )
|
|
|
|
{
|
|
|
|
PJ_LOG(6, (THIS_FILE, "pjsip_endpt_schedule_timer_w_grp_lock"
|
2023-12-27 02:32:32 +00:00
|
|
|
"(entry=%p, delay=%lu.%lu, grp_lock=%p)",
|
|
|
|
entry, (unsigned long)delay->sec,
|
|
|
|
(unsigned long)delay->msec, grp_lock));
|
2019-04-23 08:42:45 +00:00
|
|
|
return pj_timer_heap_schedule_w_grp_lock( endpt->timer_heap, entry,
|
|
|
|
delay, id_val, grp_lock );
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2005-11-21 01:55:47 +00:00
|
|
|
/*
|
|
|
|
* Cancel the previously registered timer.
|
|
|
|
*/
|
|
|
|
PJ_DEF(void) pjsip_endpt_cancel_timer( pjsip_endpoint *endpt,
|
|
|
|
pj_timer_entry *entry )
|
|
|
|
{
|
2006-01-07 18:44:25 +00:00
|
|
|
PJ_LOG(6, (THIS_FILE, "pjsip_endpt_cancel_timer(entry=%p)", entry));
|
2005-11-21 01:55:47 +00:00
|
|
|
pj_timer_heap_cancel( endpt->timer_heap, entry );
|
|
|
|
}
|
|
|
|
|
2007-03-23 16:34:20 +00:00
|
|
|
/*
|
|
|
|
* Get the timer heap instance of the SIP endpoint.
|
|
|
|
*/
|
|
|
|
PJ_DEF(pj_timer_heap_t*) pjsip_endpt_get_timer_heap(pjsip_endpoint *endpt)
|
|
|
|
{
|
|
|
|
return endpt->timer_heap;
|
|
|
|
}
|
|
|
|
|
2012-10-04 06:11:58 +00:00
|
|
|
/* Init with default */
|
|
|
|
PJ_DEF(void) pjsip_process_rdata_param_default(pjsip_process_rdata_param *p)
|
|
|
|
{
|
|
|
|
pj_bzero(p, sizeof(*p));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Distribute rdata */
|
|
|
|
PJ_DEF(pj_status_t) pjsip_endpt_process_rx_data( pjsip_endpoint *endpt,
|
|
|
|
pjsip_rx_data *rdata,
|
|
|
|
pjsip_process_rdata_param *p,
|
|
|
|
pj_bool_t *p_handled)
|
|
|
|
{
|
|
|
|
pjsip_msg *msg;
|
|
|
|
pjsip_process_rdata_param def_prm;
|
|
|
|
pjsip_module *mod;
|
|
|
|
pj_bool_t handled = PJ_FALSE;
|
|
|
|
unsigned i;
|
|
|
|
pj_status_t status;
|
|
|
|
|
|
|
|
PJ_ASSERT_RETURN(endpt && rdata, PJ_EINVAL);
|
|
|
|
|
|
|
|
if (p==NULL) {
|
|
|
|
p = &def_prm;
|
|
|
|
pjsip_process_rdata_param_default(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
msg = rdata->msg_info.msg;
|
|
|
|
|
|
|
|
if (p_handled)
|
|
|
|
*p_handled = PJ_FALSE;
|
|
|
|
|
|
|
|
if (!p->silent) {
|
|
|
|
PJ_LOG(5, (THIS_FILE, "Distributing rdata to modules: %s",
|
|
|
|
pjsip_rx_data_get_info(rdata)));
|
|
|
|
pj_log_push_indent();
|
|
|
|
}
|
|
|
|
|
|
|
|
LOCK_MODULE_ACCESS(endpt);
|
|
|
|
|
|
|
|
/* Find start module */
|
|
|
|
if (p->start_mod) {
|
2012-11-01 03:45:40 +00:00
|
|
|
mod = (pjsip_module*)
|
|
|
|
pj_list_find_node(&endpt->module_list, p->start_mod);
|
2012-10-04 06:11:58 +00:00
|
|
|
if (!mod) {
|
|
|
|
status = PJ_ENOTFOUND;
|
|
|
|
goto on_return;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
mod = endpt->module_list.next;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Start after the specified index */
|
|
|
|
for (i=0; i < p->idx_after_start && mod != &endpt->module_list; ++i) {
|
|
|
|
mod = mod->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Start with the specified priority */
|
2013-03-04 04:34:38 +00:00
|
|
|
while (mod != &endpt->module_list && mod->priority < (int)p->start_prio) {
|
2012-10-04 06:11:58 +00:00
|
|
|
mod = mod->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mod == &endpt->module_list) {
|
|
|
|
status = PJ_ENOTFOUND;
|
|
|
|
goto on_return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Distribute */
|
|
|
|
if (msg->type == PJSIP_REQUEST_MSG) {
|
|
|
|
do {
|
|
|
|
if (mod->on_rx_request)
|
|
|
|
handled = (*mod->on_rx_request)(rdata);
|
|
|
|
if (handled)
|
|
|
|
break;
|
|
|
|
mod = mod->next;
|
|
|
|
} while (mod != &endpt->module_list);
|
|
|
|
} else {
|
|
|
|
do {
|
|
|
|
if (mod->on_rx_response)
|
|
|
|
handled = (*mod->on_rx_response)(rdata);
|
|
|
|
if (handled)
|
|
|
|
break;
|
|
|
|
mod = mod->next;
|
|
|
|
} while (mod != &endpt->module_list);
|
|
|
|
}
|
|
|
|
|
|
|
|
status = PJ_SUCCESS;
|
|
|
|
|
|
|
|
on_return:
|
|
|
|
if (p_handled)
|
|
|
|
*p_handled = handled;
|
|
|
|
|
|
|
|
UNLOCK_MODULE_ACCESS(endpt);
|
|
|
|
if (!p->silent) {
|
|
|
|
pj_log_pop_indent();
|
|
|
|
}
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2005-11-21 01:55:47 +00:00
|
|
|
/*
|
|
|
|
* This is the callback that is called by the transport manager when it
|
|
|
|
* receives a message from the network.
|
|
|
|
*/
|
2006-01-07 18:44:25 +00:00
|
|
|
static void endpt_on_rx_msg( pjsip_endpoint *endpt,
|
2013-06-19 06:47:43 +00:00
|
|
|
pj_status_t status,
|
|
|
|
pjsip_rx_data *rdata )
|
2005-11-21 01:55:47 +00:00
|
|
|
{
|
2013-03-29 02:19:27 +00:00
|
|
|
pjsip_msg *msg = rdata->msg_info.msg;
|
2012-10-04 06:11:58 +00:00
|
|
|
pjsip_process_rdata_param proc_prm;
|
|
|
|
pj_bool_t handled = PJ_FALSE;
|
2005-11-21 01:55:47 +00:00
|
|
|
|
2013-12-13 11:44:51 +00:00
|
|
|
PJ_UNUSED_ARG(msg);
|
|
|
|
|
2005-11-21 01:55:47 +00:00
|
|
|
if (status != PJ_SUCCESS) {
|
2006-06-06 17:04:30 +00:00
|
|
|
char info[30];
|
|
|
|
char errmsg[PJ_ERR_MSG_SIZE];
|
2022-11-22 09:26:54 +00:00
|
|
|
|
2006-06-06 17:04:30 +00:00
|
|
|
info[0] = '\0';
|
2022-11-22 09:26:54 +00:00
|
|
|
|
2006-06-06 17:04:30 +00:00
|
|
|
if (status == PJSIP_EMISSINGHDR) {
|
|
|
|
pj_str_t p;
|
2022-11-22 09:26:54 +00:00
|
|
|
|
2006-06-06 17:04:30 +00:00
|
|
|
p.ptr = info; p.slen = 0;
|
2022-11-22 09:26:54 +00:00
|
|
|
|
2006-06-06 17:04:30 +00:00
|
|
|
if (rdata->msg_info.cid == NULL || rdata->msg_info.cid->id.slen)
|
|
|
|
pj_strcpy2(&p, "Call-ID");
|
|
|
|
if (rdata->msg_info.from == NULL)
|
|
|
|
pj_strcpy2(&p, " From");
|
|
|
|
if (rdata->msg_info.to == NULL)
|
|
|
|
pj_strcpy2(&p, " To");
|
|
|
|
if (rdata->msg_info.via == NULL)
|
|
|
|
pj_strcpy2(&p, " Via");
|
|
|
|
if (rdata->msg_info.cseq == NULL)
|
|
|
|
pj_strcpy2(&p, " CSeq");
|
2022-11-22 09:26:54 +00:00
|
|
|
|
2006-06-06 17:04:30 +00:00
|
|
|
p.ptr[p.slen] = '\0';
|
|
|
|
}
|
2022-11-22 09:26:54 +00:00
|
|
|
|
2006-06-06 17:04:30 +00:00
|
|
|
pj_strerror(status, errmsg, sizeof(errmsg));
|
2022-11-22 09:26:54 +00:00
|
|
|
|
2006-06-06 17:04:30 +00:00
|
|
|
PJ_LOG(1, (THIS_FILE,
|
|
|
|
"Error processing packet from %s:%d: %s %s [code %d]:\n"
|
2006-07-09 10:11:43 +00:00
|
|
|
"%.*s\n"
|
2006-06-06 17:04:30 +00:00
|
|
|
"-- end of packet.",
|
|
|
|
rdata->pkt_info.src_name,
|
|
|
|
rdata->pkt_info.src_port,
|
|
|
|
errmsg,
|
|
|
|
info,
|
|
|
|
status,
|
2006-07-09 10:11:43 +00:00
|
|
|
(int)rdata->msg_info.len,
|
2006-06-06 17:04:30 +00:00
|
|
|
rdata->msg_info.msg_buf));
|
2005-11-21 01:55:47 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-01-07 18:44:25 +00:00
|
|
|
PJ_LOG(5, (THIS_FILE, "Processing incoming message: %s",
|
|
|
|
pjsip_rx_data_get_info(rdata)));
|
2011-09-18 14:59:56 +00:00
|
|
|
pj_log_push_indent();
|
2006-01-07 18:44:25 +00:00
|
|
|
|
2007-07-10 01:46:08 +00:00
|
|
|
#if defined(PJSIP_CHECK_VIA_SENT_BY) && PJSIP_CHECK_VIA_SENT_BY != 0
|
2005-11-21 01:55:47 +00:00
|
|
|
/* For response, check that the value in Via sent-by match the transport.
|
|
|
|
* If not matched, silently drop the response.
|
|
|
|
* Ref: RFC3261 Section 18.1.2 Receiving Response
|
|
|
|
*/
|
|
|
|
if (msg->type == PJSIP_RESPONSE_MSG) {
|
2005-12-30 23:50:15 +00:00
|
|
|
const pj_str_t *local_addr;
|
2005-11-21 01:55:47 +00:00
|
|
|
int port = rdata->msg_info.via->sent_by.port;
|
|
|
|
pj_bool_t mismatch = PJ_FALSE;
|
|
|
|
if (port == 0) {
|
2007-05-01 16:54:54 +00:00
|
|
|
pjsip_transport_type_e type;
|
2007-05-29 11:51:45 +00:00
|
|
|
type = (pjsip_transport_type_e)rdata->tp_info.transport->key.type;
|
2005-11-21 01:55:47 +00:00
|
|
|
port = pjsip_transport_get_default_port_for_type(type);
|
|
|
|
}
|
2005-12-30 23:50:15 +00:00
|
|
|
local_addr = &rdata->tp_info.transport->local_name.host;
|
2022-11-22 09:26:54 +00:00
|
|
|
|
2006-02-26 21:22:35 +00:00
|
|
|
if (pj_strcmp(&rdata->msg_info.via->sent_by.host, local_addr) != 0) {
|
2022-11-22 09:26:54 +00:00
|
|
|
|
2006-02-26 21:22:35 +00:00
|
|
|
/* The RFC says that we should drop response when sent-by
|
|
|
|
* address mismatch. But it could happen (e.g. with SER) when
|
|
|
|
* endpoint with private IP is sending request to public
|
|
|
|
* server.
|
2022-11-22 09:26:54 +00:00
|
|
|
|
2005-11-21 01:55:47 +00:00
|
|
|
mismatch = PJ_TRUE;
|
2022-11-22 09:26:54 +00:00
|
|
|
|
2006-02-26 21:22:35 +00:00
|
|
|
*/
|
2022-11-22 09:26:54 +00:00
|
|
|
|
2006-02-26 21:22:35 +00:00
|
|
|
} else if (port != rdata->tp_info.transport->local_name.port) {
|
2005-11-21 01:55:47 +00:00
|
|
|
/* Port or address mismatch, we should discard response */
|
|
|
|
/* But we saw one implementation (we don't want to name it to
|
|
|
|
* protect the innocence) which put wrong sent-by port although
|
|
|
|
* the "rport" parameter is correct.
|
|
|
|
* So we discard the response only if the port doesn't match
|
|
|
|
* both the port in sent-by and rport. We try to be lenient here!
|
|
|
|
*/
|
2005-12-30 23:50:15 +00:00
|
|
|
if (rdata->msg_info.via->rport_param !=
|
|
|
|
rdata->tp_info.transport->local_name.port)
|
2005-11-21 01:55:47 +00:00
|
|
|
mismatch = PJ_TRUE;
|
|
|
|
else {
|
2006-01-07 18:44:25 +00:00
|
|
|
PJ_LOG(4,(THIS_FILE, "Message %s from %s has mismatch port in "
|
2005-12-30 23:50:15 +00:00
|
|
|
"sent-by but the rport parameter is "
|
|
|
|
"correct",
|
2006-01-07 18:44:25 +00:00
|
|
|
pjsip_rx_data_get_info(rdata),
|
|
|
|
rdata->pkt_info.src_name));
|
2005-11-21 01:55:47 +00:00
|
|
|
}
|
|
|
|
}
|
2022-11-22 09:26:54 +00:00
|
|
|
|
2005-11-21 01:55:47 +00:00
|
|
|
if (mismatch) {
|
2005-12-30 23:50:15 +00:00
|
|
|
PJ_TODO(ENDPT_REPORT_WHEN_DROPPING_MESSAGE);
|
2006-01-07 18:44:25 +00:00
|
|
|
PJ_LOG(4,(THIS_FILE, "Dropping response %s from %s:%d because "
|
|
|
|
"sent-by is mismatch",
|
|
|
|
pjsip_rx_data_get_info(rdata),
|
2005-12-30 23:50:15 +00:00
|
|
|
rdata->pkt_info.src_name,
|
|
|
|
rdata->pkt_info.src_port));
|
2011-09-18 14:59:56 +00:00
|
|
|
pj_log_pop_indent();
|
2005-11-21 01:55:47 +00:00
|
|
|
return;
|
|
|
|
}
|
2005-12-30 23:50:15 +00:00
|
|
|
}
|
2007-07-10 01:46:08 +00:00
|
|
|
#endif
|
2005-11-21 01:55:47 +00:00
|
|
|
|
2012-10-04 06:11:58 +00:00
|
|
|
pjsip_process_rdata_param_default(&proc_prm);
|
|
|
|
proc_prm.silent = PJ_TRUE;
|
2005-11-21 01:55:47 +00:00
|
|
|
|
2012-10-04 06:11:58 +00:00
|
|
|
pjsip_endpt_process_rx_data(endpt, rdata, &proc_prm, &handled);
|
2005-11-21 01:55:47 +00:00
|
|
|
|
2012-10-04 06:11:58 +00:00
|
|
|
/* No module is able to handle the message */
|
|
|
|
if (!handled) {
|
|
|
|
PJ_LOG(4,(THIS_FILE, "%s from %s:%d was dropped/unhandled by"
|
|
|
|
" any modules",
|
|
|
|
pjsip_rx_data_get_info(rdata),
|
|
|
|
rdata->pkt_info.src_name,
|
|
|
|
rdata->pkt_info.src_port));
|
2006-01-07 18:44:25 +00:00
|
|
|
}
|
|
|
|
|
2006-02-07 12:34:11 +00:00
|
|
|
/* Must clear mod_data before returning rdata to transport, since
|
|
|
|
* rdata may be reused.
|
|
|
|
*/
|
2006-07-03 15:19:31 +00:00
|
|
|
pj_bzero(&rdata->endpt_info, sizeof(rdata->endpt_info));
|
2011-09-18 14:59:56 +00:00
|
|
|
|
|
|
|
pj_log_pop_indent();
|
2006-01-07 18:44:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This callback is called by transport manager before message is sent.
|
|
|
|
* Modules may inspect the message before it's actually sent.
|
|
|
|
*/
|
|
|
|
static pj_status_t endpt_on_tx_msg( pjsip_endpoint *endpt,
|
|
|
|
pjsip_tx_data *tdata )
|
|
|
|
{
|
|
|
|
pj_status_t status = PJ_SUCCESS;
|
|
|
|
pjsip_module *mod;
|
|
|
|
|
|
|
|
/* Distribute to modules, starting from modules with LOWEST priority */
|
2006-07-03 14:18:17 +00:00
|
|
|
LOCK_MODULE_ACCESS(endpt);
|
2006-01-07 18:44:25 +00:00
|
|
|
|
|
|
|
mod = endpt->module_list.prev;
|
|
|
|
if (tdata->msg->type == PJSIP_REQUEST_MSG) {
|
|
|
|
while (mod != &endpt->module_list) {
|
|
|
|
if (mod->on_tx_request)
|
|
|
|
status = (*mod->on_tx_request)(tdata);
|
|
|
|
if (status != PJ_SUCCESS)
|
|
|
|
break;
|
|
|
|
mod = mod->prev;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
while (mod != &endpt->module_list) {
|
|
|
|
if (mod->on_tx_response)
|
|
|
|
status = (*mod->on_tx_response)(tdata);
|
|
|
|
if (status != PJ_SUCCESS)
|
|
|
|
break;
|
|
|
|
mod = mod->prev;
|
2005-11-21 01:55:47 +00:00
|
|
|
}
|
|
|
|
}
|
2005-12-30 23:50:15 +00:00
|
|
|
|
2006-07-03 14:18:17 +00:00
|
|
|
UNLOCK_MODULE_ACCESS(endpt);
|
2006-01-07 18:44:25 +00:00
|
|
|
|
|
|
|
return status;
|
2005-11-21 01:55:47 +00:00
|
|
|
}
|
|
|
|
|
2006-01-07 18:44:25 +00:00
|
|
|
|
2005-11-21 01:55:47 +00:00
|
|
|
/*
|
|
|
|
* Create transmit data buffer.
|
|
|
|
*/
|
|
|
|
PJ_DEF(pj_status_t) pjsip_endpt_create_tdata( pjsip_endpoint *endpt,
|
|
|
|
pjsip_tx_data **p_tdata)
|
|
|
|
{
|
|
|
|
return pjsip_tx_data_create(endpt->transport_mgr, p_tdata);
|
|
|
|
}
|
|
|
|
|
2006-10-08 12:39:34 +00:00
|
|
|
/*
|
|
|
|
* Create the DNS resolver instance.
|
|
|
|
*/
|
|
|
|
PJ_DEF(pj_status_t) pjsip_endpt_create_resolver(pjsip_endpoint *endpt,
|
|
|
|
pj_dns_resolver **p_resv)
|
|
|
|
{
|
|
|
|
#if PJSIP_HAS_RESOLVER
|
|
|
|
PJ_ASSERT_RETURN(endpt && p_resv, PJ_EINVAL);
|
|
|
|
return pj_dns_resolver_create( endpt->pf, NULL, 0, endpt->timer_heap,
|
|
|
|
endpt->ioqueue, p_resv);
|
|
|
|
#else
|
|
|
|
PJ_UNUSED_ARG(endpt);
|
|
|
|
PJ_UNUSED_ARG(p_resv);
|
|
|
|
pj_assert(!"Resolver is disabled (PJSIP_HAS_RESOLVER==0)");
|
|
|
|
return PJ_EINVALIDOP;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set DNS resolver to be used by the SIP resolver.
|
|
|
|
*/
|
|
|
|
PJ_DEF(pj_status_t) pjsip_endpt_set_resolver( pjsip_endpoint *endpt,
|
|
|
|
pj_dns_resolver *resv)
|
|
|
|
{
|
|
|
|
return pjsip_resolver_set_resolver(endpt->resolver, resv);
|
|
|
|
}
|
|
|
|
|
2015-04-08 10:10:44 +00:00
|
|
|
/*
|
|
|
|
* Set DNS external resolver implementation to be used by the SIP resolver.
|
|
|
|
*/
|
|
|
|
PJ_DEF(pj_status_t) pjsip_endpt_set_ext_resolver(pjsip_endpoint *endpt,
|
|
|
|
pjsip_ext_resolver *ext_res)
|
|
|
|
{
|
|
|
|
return pjsip_resolver_set_ext_resolver(endpt->resolver, ext_res);
|
|
|
|
}
|
|
|
|
|
2006-10-08 12:39:34 +00:00
|
|
|
/*
|
|
|
|
* Get the DNS resolver being used by the SIP resolver.
|
|
|
|
*/
|
|
|
|
PJ_DEF(pj_dns_resolver*) pjsip_endpt_get_resolver(pjsip_endpoint *endpt)
|
|
|
|
{
|
|
|
|
PJ_ASSERT_RETURN(endpt, NULL);
|
|
|
|
return pjsip_resolver_get_resolver(endpt->resolver);
|
|
|
|
}
|
|
|
|
|
2005-11-21 01:55:47 +00:00
|
|
|
/*
|
|
|
|
* Resolve
|
|
|
|
*/
|
|
|
|
PJ_DEF(void) pjsip_endpt_resolve( pjsip_endpoint *endpt,
|
|
|
|
pj_pool_t *pool,
|
2005-12-26 12:52:19 +00:00
|
|
|
pjsip_host_info *target,
|
2005-11-21 01:55:47 +00:00
|
|
|
void *token,
|
|
|
|
pjsip_resolver_callback *cb)
|
|
|
|
{
|
|
|
|
pjsip_resolve( endpt->resolver, pool, target, token, cb);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get transport manager.
|
|
|
|
*/
|
|
|
|
PJ_DEF(pjsip_tpmgr*) pjsip_endpt_get_tpmgr(pjsip_endpoint *endpt)
|
|
|
|
{
|
|
|
|
return endpt->transport_mgr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get ioqueue instance.
|
|
|
|
*/
|
|
|
|
PJ_DEF(pj_ioqueue_t*) pjsip_endpt_get_ioqueue(pjsip_endpoint *endpt)
|
|
|
|
{
|
|
|
|
return endpt->ioqueue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find/create transport.
|
|
|
|
*/
|
2005-12-30 23:50:15 +00:00
|
|
|
PJ_DEF(pj_status_t) pjsip_endpt_acquire_transport(pjsip_endpoint *endpt,
|
2005-11-21 01:55:47 +00:00
|
|
|
pjsip_transport_type_e type,
|
2005-12-30 23:50:15 +00:00
|
|
|
const pj_sockaddr_t *remote,
|
2005-12-26 12:52:19 +00:00
|
|
|
int addr_len,
|
2007-01-12 06:37:35 +00:00
|
|
|
const pjsip_tpselector *sel,
|
2005-12-30 23:50:15 +00:00
|
|
|
pjsip_transport **transport)
|
2005-11-21 01:55:47 +00:00
|
|
|
{
|
2005-12-30 23:50:15 +00:00
|
|
|
return pjsip_tpmgr_acquire_transport(endpt->transport_mgr, type,
|
2007-01-12 06:37:35 +00:00
|
|
|
remote, addr_len, sel, transport);
|
2005-11-21 01:55:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-02-24 05:43:34 +00:00
|
|
|
/*
|
|
|
|
* Find/create transport.
|
|
|
|
*/
|
|
|
|
PJ_DEF(pj_status_t) pjsip_endpt_acquire_transport2(pjsip_endpoint *endpt,
|
|
|
|
pjsip_transport_type_e type,
|
|
|
|
const pj_sockaddr_t *remote,
|
|
|
|
int addr_len,
|
|
|
|
const pjsip_tpselector *sel,
|
|
|
|
pjsip_tx_data *tdata,
|
|
|
|
pjsip_transport **transport)
|
|
|
|
{
|
|
|
|
return pjsip_tpmgr_acquire_transport2(endpt->transport_mgr, type, remote,
|
|
|
|
addr_len, sel, tdata, transport);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-11-21 01:55:47 +00:00
|
|
|
/*
|
|
|
|
* Report error.
|
|
|
|
*/
|
|
|
|
PJ_DEF(void) pjsip_endpt_log_error( pjsip_endpoint *endpt,
|
|
|
|
const char *sender,
|
|
|
|
pj_status_t error_code,
|
|
|
|
const char *format,
|
|
|
|
... )
|
|
|
|
{
|
2005-11-23 11:25:17 +00:00
|
|
|
#if PJ_LOG_MAX_LEVEL > 0
|
2005-11-21 01:55:47 +00:00
|
|
|
char newformat[256];
|
2013-06-19 06:47:43 +00:00
|
|
|
pj_size_t len;
|
2005-11-21 01:55:47 +00:00
|
|
|
va_list marker;
|
|
|
|
|
|
|
|
va_start(marker, format);
|
|
|
|
|
|
|
|
PJ_UNUSED_ARG(endpt);
|
|
|
|
|
2006-02-14 21:15:30 +00:00
|
|
|
len = pj_ansi_strlen(format);
|
2007-05-11 15:14:34 +00:00
|
|
|
if (len < (int)sizeof(newformat)-30) {
|
2005-11-21 01:55:47 +00:00
|
|
|
pj_str_t errstr;
|
|
|
|
|
2023-03-24 04:11:20 +00:00
|
|
|
pj_ansi_strxcpy(newformat, format, sizeof(newformat));
|
2006-03-10 12:57:12 +00:00
|
|
|
pj_ansi_snprintf(newformat+len, sizeof(newformat)-len-1,
|
|
|
|
": [err %d] ", error_code);
|
2006-02-14 21:15:30 +00:00
|
|
|
len += pj_ansi_strlen(newformat+len);
|
2005-11-21 01:55:47 +00:00
|
|
|
|
2006-03-10 12:57:12 +00:00
|
|
|
errstr = pj_strerror( error_code, newformat+len,
|
|
|
|
sizeof(newformat)-len-1);
|
2005-11-21 01:55:47 +00:00
|
|
|
|
|
|
|
len += errstr.slen;
|
|
|
|
newformat[len] = '\0';
|
|
|
|
|
|
|
|
pj_log(sender, 1, newformat, marker);
|
|
|
|
} else {
|
|
|
|
pj_log(sender, 1, format, marker);
|
|
|
|
}
|
|
|
|
|
|
|
|
va_end(marker);
|
2005-11-23 11:25:17 +00:00
|
|
|
#else
|
|
|
|
PJ_UNUSED_ARG(format);
|
|
|
|
PJ_UNUSED_ARG(error_code);
|
|
|
|
PJ_UNUSED_ARG(sender);
|
|
|
|
PJ_UNUSED_ARG(endpt);
|
|
|
|
#endif
|
2005-11-21 01:55:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Dump endpoint.
|
|
|
|
*/
|
|
|
|
PJ_DEF(void) pjsip_endpt_dump( pjsip_endpoint *endpt, pj_bool_t detail )
|
|
|
|
{
|
|
|
|
#if PJ_LOG_MAX_LEVEL >= 3
|
|
|
|
PJ_LOG(5, (THIS_FILE, "pjsip_endpt_dump()"));
|
|
|
|
|
|
|
|
/* Lock mutex. */
|
|
|
|
pj_mutex_lock(endpt->mutex);
|
|
|
|
|
|
|
|
PJ_LOG(3, (THIS_FILE, "Dumping endpoint %p:", endpt));
|
|
|
|
|
|
|
|
/* Dumping pool factory. */
|
2006-03-30 16:46:36 +00:00
|
|
|
pj_pool_factory_dump(endpt->pf, detail);
|
2005-11-21 01:55:47 +00:00
|
|
|
|
|
|
|
/* Pool health. */
|
2023-03-22 01:45:23 +00:00
|
|
|
PJ_LOG(3, (THIS_FILE," Endpoint pool capacity=%lu, used_size=%lu",
|
2023-12-27 02:32:32 +00:00
|
|
|
(unsigned long)pj_pool_get_capacity(endpt->pool),
|
|
|
|
(unsigned long)pj_pool_get_used_size(endpt->pool)));
|
2005-11-21 01:55:47 +00:00
|
|
|
|
2006-10-08 12:39:34 +00:00
|
|
|
/* Resolver */
|
|
|
|
#if PJSIP_HAS_RESOLVER
|
|
|
|
if (pjsip_endpt_get_resolver(endpt)) {
|
|
|
|
pj_dns_resolver_dump(pjsip_endpt_get_resolver(endpt), detail);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2005-11-21 01:55:47 +00:00
|
|
|
/* Transports.
|
|
|
|
*/
|
|
|
|
pjsip_tpmgr_dump_transports( endpt->transport_mgr );
|
|
|
|
|
|
|
|
/* Timer. */
|
2012-06-05 10:41:17 +00:00
|
|
|
#if PJ_TIMER_DEBUG
|
|
|
|
pj_timer_heap_dump(endpt->timer_heap);
|
|
|
|
#else
|
2023-03-23 01:30:44 +00:00
|
|
|
PJ_LOG(3,(THIS_FILE, " Timer heap has %lu entries",
|
2023-12-27 02:32:32 +00:00
|
|
|
(unsigned long)pj_timer_heap_count(endpt->timer_heap)));
|
2012-06-05 10:41:17 +00:00
|
|
|
#endif
|
2005-11-21 01:55:47 +00:00
|
|
|
|
|
|
|
/* Unlock mutex. */
|
|
|
|
pj_mutex_unlock(endpt->mutex);
|
|
|
|
#else
|
2005-11-23 11:25:17 +00:00
|
|
|
PJ_UNUSED_ARG(endpt);
|
|
|
|
PJ_UNUSED_ARG(detail);
|
2005-11-21 01:55:47 +00:00
|
|
|
PJ_LOG(3,(THIS_FILE, "pjsip_end_dump: can't dump because it's disabled."));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2012-03-30 07:10:13 +00:00
|
|
|
|
|
|
|
PJ_DEF(pj_status_t) pjsip_endpt_atexit( pjsip_endpoint *endpt,
|
|
|
|
pjsip_endpt_exit_callback func)
|
|
|
|
{
|
|
|
|
exit_cb *new_cb;
|
|
|
|
|
|
|
|
PJ_ASSERT_RETURN(endpt && func, PJ_EINVAL);
|
|
|
|
|
|
|
|
new_cb = PJ_POOL_ZALLOC_T(endpt->pool, exit_cb);
|
|
|
|
new_cb->func = func;
|
|
|
|
|
|
|
|
pj_mutex_lock(endpt->mutex);
|
|
|
|
pj_list_push_back(&endpt->exit_cb_list, new_cb);
|
|
|
|
pj_mutex_unlock(endpt->mutex);
|
|
|
|
|
|
|
|
return PJ_SUCCESS;
|
|
|
|
}
|