📄 sip_endpoint.c
字号:
pjsip_module *prev = mod->prev;
pjsip_endpt_unregister_module(endpt, mod);
mod = prev;
}
/* Shutdown and destroy all transports. */
pjsip_tpmgr_destroy(endpt->transport_mgr);
/* Destroy ioqueue */
pj_ioqueue_destroy(endpt->ioqueue);
/* Destroy timer heap */
pj_timer_heap_destroy(endpt->timer_heap);
/* Delete endpoint mutex. */
pj_mutex_destroy(endpt->mutex);
/* Deinit parser */
deinit_sip_parser();
/* Delete module's mutex */
pj_rwmutex_destroy(endpt->mod_mutex);
/* Finally destroy pool. */
pj_pool_release(endpt->pool);
PJ_LOG(4, (THIS_FILE, "Endpoint %p destroyed", endpt));
}
/*
* 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. */
/* No need to lock mutex. Factory is thread safe.
pj_mutex_lock(endpt->mutex);
*/
/* Create pool */
pool = pj_pool_create( endpt->pf, pool_name,
initial, increment, &pool_callback);
/* Unlock mutex. */
/* No need to lock mutex. Factory is thread safe.
pj_mutex_unlock(endpt->mutex);
*/
if (!pool) {
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.
*/
PJ_DEF(void) pjsip_endpt_release_pool( pjsip_endpoint *endpt, pj_pool_t *pool )
{
PJ_LOG(6, (THIS_FILE, "Releasing pool %s", pj_pool_getobjname(pool)));
/* Don't need to acquire mutex since pool factory is thread safe
pj_mutex_lock(endpt->mutex);
*/
pj_pool_release( pool );
PJ_UNUSED_ARG(endpt);
/*
pj_mutex_unlock(endpt->mutex);
*/
}
PJ_DEF(pj_status_t) pjsip_endpt_handle_events2(pjsip_endpoint *endpt,
const pj_time_val *max_timeout,
unsigned *p_count)
{
/* timeout is 'out' var. This just to make compiler happy. */
pj_time_val timeout = { 0, 0};
unsigned count = 0, net_event_count = 0;
int c;
PJ_LOG(6, (THIS_FILE, "pjsip_endpt_handle_events()"));
/* 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;
c = pj_timer_heap_poll( endpt->timer_heap, &timeout );
if (c > 0)
count += c;
/* timer_heap_poll should never ever returns negative value, or otherwise
* ioqueue_poll() will block forever!
*/
pj_assert(timeout.sec >= 0 && timeout.msec >= 0);
if (timeout.msec >= 1000) timeout.msec = 999;
/* 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;
}
/* 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) {
pj_thread_sleep(PJ_TIME_VAL_MSEC(timeout));
if (p_count)
*p_count = count;
return pj_get_netos_error();
} else if (c == 0) {
break;
} else {
net_event_count += c;
timeout.sec = timeout.msec = 0;
}
} while (c > 0 && net_event_count < PJSIP_MAX_NET_EVENTS);
count += net_event_count;
if (p_count)
*p_count = count;
return PJ_SUCCESS;
}
/*
* 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);
}
/*
* Schedule timer.
*/
PJ_DEF(pj_status_t) pjsip_endpt_schedule_timer( pjsip_endpoint *endpt,
pj_timer_entry *entry,
const pj_time_val *delay )
{
PJ_LOG(6, (THIS_FILE, "pjsip_endpt_schedule_timer(entry=%p, delay=%u.%u)",
entry, delay->sec, delay->msec));
return pj_timer_heap_schedule( endpt->timer_heap, entry, delay );
}
/*
* Cancel the previously registered timer.
*/
PJ_DEF(void) pjsip_endpt_cancel_timer( pjsip_endpoint *endpt,
pj_timer_entry *entry )
{
PJ_LOG(6, (THIS_FILE, "pjsip_endpt_cancel_timer(entry=%p)", entry));
pj_timer_heap_cancel( endpt->timer_heap, entry );
}
/*
* This is the callback that is called by the transport manager when it
* receives a message from the network.
*/
static void endpt_on_rx_msg( pjsip_endpoint *endpt,
pj_status_t status,
pjsip_rx_data *rdata )
{
pjsip_msg *msg = rdata->msg_info.msg;
if (status != PJ_SUCCESS) {
char info[30];
char errmsg[PJ_ERR_MSG_SIZE];
info[0] = '\0';
if (status == PJSIP_EMISSINGHDR) {
pj_str_t p;
p.ptr = info; p.slen = 0;
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");
p.ptr[p.slen] = '\0';
}
pj_strerror(status, errmsg, sizeof(errmsg));
PJ_LOG(1, (THIS_FILE,
"Error processing packet from %s:%d: %s %s [code %d]:\n"
"%.*s\n"
"-- end of packet.",
rdata->pkt_info.src_name,
rdata->pkt_info.src_port,
errmsg,
info,
status,
(int)rdata->msg_info.len,
rdata->msg_info.msg_buf));
return;
}
PJ_LOG(5, (THIS_FILE, "Processing incoming message: %s",
pjsip_rx_data_get_info(rdata)));
/* 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) {
const pj_str_t *local_addr;
int port = rdata->msg_info.via->sent_by.port;
pj_bool_t mismatch = PJ_FALSE;
if (port == 0) {
int type;
type = rdata->tp_info.transport->key.type;
port = pjsip_transport_get_default_port_for_type(type);
}
local_addr = &rdata->tp_info.transport->local_name.host;
if (pj_strcmp(&rdata->msg_info.via->sent_by.host, local_addr) != 0) {
/* 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.
mismatch = PJ_TRUE;
*/
} else if (port != rdata->tp_info.transport->local_name.port) {
/* 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!
*/
if (rdata->msg_info.via->rport_param !=
rdata->tp_info.transport->local_name.port)
mismatch = PJ_TRUE;
else {
PJ_LOG(4,(THIS_FILE, "Message %s from %s has mismatch port in "
"sent-by but the rport parameter is "
"correct",
pjsip_rx_data_get_info(rdata),
rdata->pkt_info.src_name));
}
}
if (mismatch) {
PJ_TODO(ENDPT_REPORT_WHEN_DROPPING_MESSAGE);
PJ_LOG(4,(THIS_FILE, "Dropping response %s from %s:%d because "
"sent-by is mismatch",
pjsip_rx_data_get_info(rdata),
rdata->pkt_info.src_name,
rdata->pkt_info.src_port));
return;
}
}
/* Distribute to modules, starting from modules with highest priority */
LOCK_MODULE_ACCESS(endpt);
if (msg->type == PJSIP_REQUEST_MSG) {
pjsip_module *mod;
pj_bool_t handled = PJ_FALSE;
mod = endpt->module_list.next;
while (mod != &endpt->module_list) {
if (mod->on_rx_request)
handled = (*mod->on_rx_request)(rdata);
if (handled)
break;
mod = mod->next;
}
/* No module is able to handle the request. */
if (!handled) {
PJ_TODO(ENDPT_RESPOND_UNHANDLED_REQUEST);
PJ_LOG(4,(THIS_FILE, "Message %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));
}
} else {
pjsip_module *mod;
pj_bool_t handled = PJ_FALSE;
mod = endpt->module_list.next;
while (mod != &endpt->module_list) {
if (mod->on_rx_response)
handled = (*mod->on_rx_response)(rdata);
if (handled)
break;
mod = mod->next;
}
if (!handled) {
PJ_LOG(4,(THIS_FILE, "Message %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));
}
}
UNLOCK_MODULE_ACCESS(endpt);
/* Must clear mod_data before returning rdata to transport, since
* rdata may be reused.
*/
pj_bzero(&rdata->endpt_info, sizeof(rdata->endpt_info));
}
/*
* 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 */
LOCK_MODULE_ACCESS(endpt);
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;
}
}
UNLOCK_MODULE_ACCESS(endpt);
return status;
}
/*
* 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);
}
/*
* 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);
}
/*
* 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);
}
/*
* Resolve
*/
PJ_DEF(void) pjsip_endpt_resolve( pjsip_endpoint *endpt,
pj_pool_t *pool,
pjsip_host_info *target,
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.
*/
PJ_DEF(pj_status_t) pjsip_endpt_acquire_transport(pjsip_endpoint *endpt,
pjsip_transport_type_e type,
const pj_sockaddr_t *remote,
int addr_len,
const pjsip_tpselector *sel,
pjsip_transport **transport)
{
return pjsip_tpmgr_acquire_transport(endpt->transport_mgr, type,
remote, addr_len, sel, transport);
}
/*
* Report error.
*/
PJ_DEF(void) pjsip_endpt_log_error( pjsip_endpoint *endpt,
const char *sender,
pj_status_t error_code,
const char *format,
... )
{
#if PJ_LOG_MAX_LEVEL > 0
char newformat[256];
int len;
va_list marker;
va_start(marker, format);
PJ_UNUSED_ARG(endpt);
len = pj_ansi_strlen(format);
if (len < sizeof(newformat)-30) {
pj_str_t errstr;
pj_ansi_strcpy(newformat, format);
pj_ansi_snprintf(newformat+len, sizeof(newformat)-len-1,
": [err %d] ", error_code);
len += pj_ansi_strlen(newformat+len);
errstr = pj_strerror( error_code, newformat+len,
sizeof(newformat)-len-1);
len += errstr.slen;
newformat[len] = '\0';
pj_log(sender, 1, newformat, marker);
} else {
pj_log(sender, 1, format, marker);
}
va_end(marker);
#else
PJ_UNUSED_ARG(format);
PJ_UNUSED_ARG(error_code);
PJ_UNUSED_ARG(sender);
PJ_UNUSED_ARG(endpt);
#endif
}
/*
* 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. */
pj_pool_factory_dump(endpt->pf, detail);
/* Pool health. */
PJ_LOG(3, (THIS_FILE," Endpoint pool capacity=%u, used_size=%u",
pj_pool_get_capacity(endpt->pool),
pj_pool_get_used_size(endpt->pool)));
/* Resolver */
#if PJSIP_HAS_RESOLVER
if (pjsip_endpt_get_resolver(endpt)) {
pj_dns_resolver_dump(pjsip_endpt_get_resolver(endpt), detail);
}
#endif
/* Transports.
*/
pjsip_tpmgr_dump_transports( endpt->transport_mgr );
/* Timer. */
PJ_LOG(3,(THIS_FILE, " Timer heap has %u entries",
pj_timer_heap_count(endpt->timer_heap)));
/* Unlock mutex. */
pj_mutex_unlock(endpt->mutex);
#else
PJ_UNUSED_ARG(endpt);
PJ_UNUSED_ARG(detail);
PJ_LOG(3,(THIS_FILE, "pjsip_end_dump: can't dump because it's disabled."));
#endif
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -