📄 pjsua_core.c
字号:
/*
* Create TCP transport.
*/
pjsua_transport_config config;
pjsip_host_port a_name;
pjsip_tpfactory *tcp;
pj_sockaddr_in local_addr;
/* Supply default config if it's not specified */
if (cfg == NULL) {
pjsua_transport_config_default(&config);
cfg = &config;
}
/* Init local address */
pj_sockaddr_in_init(&local_addr, 0, 0);
if (cfg->port)
local_addr.sin_port = pj_htons((pj_uint16_t)cfg->port);
if (cfg->bound_addr.slen) {
status = pj_sockaddr_in_set_str_addr(&local_addr,&cfg->bound_addr);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE,
"Unable to resolve transport bound address",
status);
goto on_return;
}
}
/* Init published name */
pj_bzero(&a_name, sizeof(pjsip_host_port));
if (cfg->public_addr.slen)
a_name.host = cfg->public_addr;
/* Create the TCP transport */
status = pjsip_tcp_transport_start2(pjsua_var.endpt, &local_addr,
&a_name, 1, &tcp);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Error creating SIP TCP listener",
status);
goto on_return;
}
/* Save the transport */
pjsua_var.tpdata[id].type = type;
pjsua_var.tpdata[id].local_name = tcp->addr_name;
pjsua_var.tpdata[id].data.factory = tcp;
#endif /* PJ_HAS_TCP */
#if defined(PJSIP_HAS_TLS_TRANSPORT) && PJSIP_HAS_TLS_TRANSPORT!=0
} else if (type == PJSIP_TRANSPORT_TLS) {
/*
* Create TLS transport.
*/
/*
* Create TCP transport.
*/
pjsua_transport_config config;
pjsip_host_port a_name;
pjsip_tpfactory *tls;
pj_sockaddr_in local_addr;
/* Supply default config if it's not specified */
if (cfg == NULL) {
pjsua_transport_config_default(&config);
config.port = 5061;
cfg = &config;
}
/* Init local address */
pj_sockaddr_in_init(&local_addr, 0, 0);
if (cfg->port)
local_addr.sin_port = pj_htons((pj_uint16_t)cfg->port);
if (cfg->bound_addr.slen) {
status = pj_sockaddr_in_set_str_addr(&local_addr,&cfg->bound_addr);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE,
"Unable to resolve transport bound address",
status);
goto on_return;
}
}
/* Init published name */
pj_bzero(&a_name, sizeof(pjsip_host_port));
if (cfg->public_addr.slen)
a_name.host = cfg->public_addr;
status = pjsip_tls_transport_start(pjsua_var.endpt,
&cfg->tls_setting,
&local_addr, &a_name, 1, &tls);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Error creating SIP TLS listener",
status);
goto on_return;
}
/* Save the transport */
pjsua_var.tpdata[id].type = type;
pjsua_var.tpdata[id].local_name = tls->addr_name;
pjsua_var.tpdata[id].data.factory = tls;
#endif
} else {
status = PJSIP_EUNSUPTRANSPORT;
pjsua_perror(THIS_FILE, "Error creating transport", status);
goto on_return;
}
/* Return the ID */
if (p_id) *p_id = id;
status = PJ_SUCCESS;
on_return:
PJSUA_UNLOCK();
return status;
}
/*
* Register transport that has been created by application.
*/
PJ_DEF(pj_status_t) pjsua_transport_register( pjsip_transport *tp,
pjsua_transport_id *p_id)
{
unsigned id;
PJSUA_LOCK();
/* Find empty transport slot */
for (id=0; id < PJ_ARRAY_SIZE(pjsua_var.tpdata); ++id) {
if (pjsua_var.tpdata[id].data.ptr == NULL)
break;
}
if (id == PJ_ARRAY_SIZE(pjsua_var.tpdata)) {
pjsua_perror(THIS_FILE, "Error creating transport", PJ_ETOOMANY);
PJSUA_UNLOCK();
return PJ_ETOOMANY;
}
/* Save the transport */
pjsua_var.tpdata[id].type = tp->key.type;
pjsua_var.tpdata[id].local_name = tp->local_name;
pjsua_var.tpdata[id].data.tp = tp;
/* Return the ID */
if (p_id) *p_id = id;
PJSUA_UNLOCK();
return PJ_SUCCESS;
}
/*
* Enumerate all transports currently created in the system.
*/
PJ_DEF(pj_status_t) pjsua_enum_transports( pjsua_transport_id id[],
unsigned *p_count )
{
unsigned i, count;
PJSUA_LOCK();
for (i=0, count=0; i<PJ_ARRAY_SIZE(pjsua_var.tpdata) && count<*p_count;
++i)
{
if (!pjsua_var.tpdata[i].data.ptr)
continue;
id[count++] = i;
}
*p_count = count;
PJSUA_UNLOCK();
return PJ_SUCCESS;
}
/*
* Get information about transports.
*/
PJ_DEF(pj_status_t) pjsua_transport_get_info( pjsua_transport_id id,
pjsua_transport_info *info)
{
pjsua_transport_data *t = &pjsua_var.tpdata[id];
pj_status_t status;
pj_bzero(info, sizeof(*info));
/* Make sure id is in range. */
PJ_ASSERT_RETURN(id>=0 && id<PJ_ARRAY_SIZE(pjsua_var.tpdata), PJ_EINVAL);
/* Make sure that transport exists */
PJ_ASSERT_RETURN(pjsua_var.tpdata[id].data.ptr != NULL, PJ_EINVAL);
PJSUA_LOCK();
if (pjsua_var.tpdata[id].type == PJSIP_TRANSPORT_UDP) {
pjsip_transport *tp = t->data.tp;
if (tp == NULL) {
PJSUA_UNLOCK();
return PJ_EINVALIDOP;
}
info->id = id;
info->type = tp->key.type;
info->type_name = pj_str(tp->type_name);
info->info = pj_str(tp->info);
info->flag = tp->flag;
info->addr_len = tp->addr_len;
info->local_addr = tp->local_addr;
info->local_name = tp->local_name;
info->usage_count = pj_atomic_get(tp->ref_cnt);
status = PJ_SUCCESS;
} else if (pjsua_var.tpdata[id].type == PJSIP_TRANSPORT_TCP) {
pjsip_tpfactory *factory = t->data.factory;
if (factory == NULL) {
PJSUA_UNLOCK();
return PJ_EINVALIDOP;
}
info->id = id;
info->type = t->type;
info->type_name = pj_str("TCP");
info->info = pj_str("TCP transport");
info->flag = factory->flag;
info->addr_len = sizeof(factory->local_addr);
info->local_addr = factory->local_addr;
info->local_name = factory->addr_name;
info->usage_count = 0;
status = PJ_SUCCESS;
} else {
pj_assert(!"Unsupported transport");
status = PJ_EINVALIDOP;
}
PJSUA_UNLOCK();
return status;
}
/*
* Disable a transport or re-enable it.
*/
PJ_DEF(pj_status_t) pjsua_transport_set_enable( pjsua_transport_id id,
pj_bool_t enabled)
{
/* Make sure id is in range. */
PJ_ASSERT_RETURN(id>=0 && id<PJ_ARRAY_SIZE(pjsua_var.tpdata), PJ_EINVAL);
/* Make sure that transport exists */
PJ_ASSERT_RETURN(pjsua_var.tpdata[id].data.ptr != NULL, PJ_EINVAL);
/* To be done!! */
PJ_TODO(pjsua_transport_set_enable);
PJ_UNUSED_ARG(enabled);
return PJ_EINVALIDOP;
}
/*
* Close the transport.
*/
PJ_DEF(pj_status_t) pjsua_transport_close( pjsua_transport_id id,
pj_bool_t force )
{
pj_status_t status;
/* Make sure id is in range. */
PJ_ASSERT_RETURN(id>=0 && id<PJ_ARRAY_SIZE(pjsua_var.tpdata), PJ_EINVAL);
/* Make sure that transport exists */
PJ_ASSERT_RETURN(pjsua_var.tpdata[id].data.ptr != NULL, PJ_EINVAL);
/* Note: destroy() may not work if there are objects still referencing
* the transport.
*/
if (force) {
switch (pjsua_var.tpdata[id].type) {
case PJSIP_TRANSPORT_UDP:
status = pjsip_transport_shutdown(pjsua_var.tpdata[id].data.tp);
if (status != PJ_SUCCESS)
return status;
status = pjsip_transport_destroy(pjsua_var.tpdata[id].data.tp);
if (status != PJ_SUCCESS)
return status;
break;
case PJSIP_TRANSPORT_TLS:
case PJSIP_TRANSPORT_TCP:
/* This will close the TCP listener, but existing TCP/TLS
* connections (if any) will still linger
*/
status = (*pjsua_var.tpdata[id].data.factory->destroy)
(pjsua_var.tpdata[id].data.factory);
if (status != PJ_SUCCESS)
return status;
break;
default:
return PJ_EINVAL;
}
} else {
/* If force is not specified, transports will be closed at their
* convenient time. However this will leak PJSUA-API transport
* descriptors as PJSUA-API wouldn't know when exactly the
* transport is closed thus it can't cleanup PJSUA transport
* descriptor.
*/
switch (pjsua_var.tpdata[id].type) {
case PJSIP_TRANSPORT_UDP:
return pjsip_transport_shutdown(pjsua_var.tpdata[id].data.tp);
case PJSIP_TRANSPORT_TLS:
case PJSIP_TRANSPORT_TCP:
return (*pjsua_var.tpdata[id].data.factory->destroy)
(pjsua_var.tpdata[id].data.factory);
default:
return PJ_EINVAL;
}
}
/* Cleanup pjsua data when force is applied */
if (force) {
pjsua_var.tpdata[id].type = PJSIP_TRANSPORT_UNSPECIFIED;
pjsua_var.tpdata[id].data.ptr = NULL;
}
return PJ_SUCCESS;
}
/*
* Add additional headers etc in msg_data specified by application
* when sending requests.
*/
void pjsua_process_msg_data(pjsip_tx_data *tdata,
const pjsua_msg_data *msg_data)
{
pj_bool_t allow_body;
const pjsip_hdr *hdr;
/* Always add User-Agent */
if (pjsua_var.ua_cfg.user_agent.slen &&
tdata->msg->type == PJSIP_REQUEST_MSG)
{
const pj_str_t STR_USER_AGENT = { "User-Agent", 10 };
pjsip_hdr *h;
h = (pjsip_hdr*)pjsip_generic_string_hdr_create(tdata->pool,
&STR_USER_AGENT,
&pjsua_var.ua_cfg.user_agent);
pjsip_msg_add_hdr(tdata->msg, h);
}
if (!msg_data)
return;
hdr = msg_data->hdr_list.next;
while (hdr && hdr != &msg_data->hdr_list) {
pjsip_hdr *new_hdr;
new_hdr = pjsip_hdr_clone(tdata->pool, hdr);
pjsip_msg_add_hdr(tdata->msg, new_hdr);
hdr = hdr->next;
}
allow_body = (tdata->msg->body == NULL);
if (allow_body && msg_data->content_type.slen && msg_data->msg_body.slen) {
pjsip_media_type ctype;
pjsip_msg_body *body;
pjsua_parse_media_type(tdata->pool, &msg_data->content_type, &ctype);
body = pjsip_msg_body_create(tdata->pool, &ctype.type, &ctype.subtype,
&msg_data->msg_body);
tdata->msg->body = body;
}
}
/*
* Add route_set to outgoing requests
*/
void pjsua_set_msg_route_set( pjsip_tx_data *tdata,
const pjsip_route_hdr *route_set )
{
const pjsip_route_hdr *r;
r = route_set->next;
while (r != route_set) {
pjsip_route_hdr *new_r;
new_r = pjsip_hdr_clone(tdata->pool, r);
pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)new_r);
r = r->next;
}
}
/*
* Simple version of MIME type parsing (it doesn't support parameters)
*/
void pjsua_parse_media_type( pj_pool_t *pool,
const pj_str_t *mime,
pjsip_media_type *media_type)
{
pj_str_t tmp;
char *pos;
pj_bzero(media_type, sizeof(*media_type));
pj_strdup_with_null(pool, &tmp, mime);
pos = pj_strchr(&tmp, '/');
if (pos) {
media_type->type.ptr = tmp.ptr;
media_type->type.slen = (pos-tmp.ptr);
media_type->subtype.ptr = pos+1;
media_type->subtype.slen = tmp.ptr+tmp.slen-pos-1;
} else {
media_type->type = tmp;
}
}
/*
* Internal function to init transport selector from transport id.
*/
void pjsua_init_tpselector(pjsua_transport_id tp_id,
pjsip_tpselector *sel)
{
pjsua_transport_data *tpdata;
unsigned flag;
pj_bzero(sel, sizeof(*sel));
if (tp_id == PJSUA_INVALID_ID)
return;
pj_assert(tp_id >= 0 && tp_id < PJ_ARRAY_SIZE(pjsua_var.tpdata));
tpdata = &pjsua_var.tpdata[tp_id];
flag = pjsip_transport_get_flag_from_type(tpdata->type);
if (flag & PJSIP_TRANSPORT_DATAGRAM) {
sel->type = PJSIP_TPSELECTOR_TRANSPORT;
sel->u.transport = tpdata->data.tp;
} else {
sel->type = PJSIP_TPSELECTOR_LISTENER;
sel->u.listener = tpdata->data.factory;
}
}
/*
* Verify that valid SIP url is given.
*/
PJ_DEF(pj_status_t) pjsua_verify_sip_url(const char *c_url)
{
pjsip_uri *p;
pj_pool_t *pool;
char *url;
int len = (c_url ? pj_ansi_strlen(c_url) : 0);
if (!len) return -1;
pool = pj_pool_create(&pjsua_var.cp.factory, "check%p", 1024, 0, NULL);
if (!pool) return -1;
url = pj_pool_alloc(pool, len+1);
pj_ansi_strcpy(url, c_url);
p = pjsip_parse_uri(pool, url, len, 0);
if (!p || pj_stricmp2(pjsip_uri_get_scheme(p), "sip") != 0)
p = NULL;
pj_pool_release(pool);
return p ? 0 : -1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -