📄 sip_dialog.c
字号:
PJSIP_URI_SCHEME_IS_SIPS(rdata->msg_info.msg->line.req.uri);
/* Call-ID */
dlg->call_id = pjsip_hdr_clone(dlg->pool, rdata->msg_info.cid);
/* Route set.
* RFC 3261 Section 12.1.1:
* The route set MUST be set to the list of URIs in the Record-Route
* header field from the request, taken in order and preserving all URI
* parameters. If no Record-Route header field is present in the request,
* the route set MUST be set to the empty set.
*/
pj_list_init(&dlg->route_set);
rr = rdata->msg_info.record_route;
while (rr != NULL) {
pjsip_route_hdr *route;
/* Clone the Record-Route, change the type to Route header. */
route = pjsip_hdr_clone(dlg->pool, rr);
pjsip_routing_hdr_set_route(route);
/* Add to route set. */
pj_list_push_back(&dlg->route_set, route);
/* Find next Record-Route header. */
rr = rr->next;
if (rr == (void*)&rdata->msg_info.msg->hdr)
break;
rr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_RECORD_ROUTE, rr);
}
/* Init client authentication session. */
status = pjsip_auth_clt_init(&dlg->auth_sess, dlg->endpt,
dlg->pool, 0);
if (status != PJ_SUCCESS)
goto on_error;
/* Create UAS transaction for this request. */
status = pjsip_tsx_create_uas(dlg->ua, rdata, &tsx);
if (status != PJ_SUCCESS)
goto on_error;
/* Associate this dialog to the transaction. */
tsx->mod_data[dlg->ua->id] = dlg;
/* Increment tsx counter */
++dlg->tsx_count;
/* Calculate hash value of remote tag. */
dlg->remote.tag_hval = pj_hash_calc(0, dlg->remote.info->tag.ptr,
dlg->remote.info->tag.slen);
/* Register this dialog to user agent. */
status = pjsip_ua_register_dlg( ua, dlg );
if (status != PJ_SUCCESS)
goto on_error;
/* Put this dialog in rdata's mod_data */
rdata->endpt_info.mod_data[ua->id] = dlg;
PJ_TODO(DIALOG_APP_TIMER);
/* Feed the first request to the transaction. */
pjsip_tsx_recv_msg(tsx, rdata);
/* Done. */
*p_dlg = dlg;
PJ_LOG(5,(dlg->obj_name, "UAS dialog created"));
return PJ_SUCCESS;
on_error:
if (tsx) {
pjsip_tsx_terminate(tsx, 500);
--dlg->tsx_count;
}
destroy_dialog(dlg);
return status;
}
/*
* Bind dialog to a specific transport/listener.
*/
PJ_DEF(pj_status_t) pjsip_dlg_set_transport( pjsip_dialog *dlg,
const pjsip_tpselector *sel)
{
/* Validate */
PJ_ASSERT_RETURN(dlg && sel, PJ_EINVAL);
/* Start locking the dialog. */
pjsip_dlg_inc_lock(dlg);
/* Decrement reference counter of previous transport selector */
pjsip_tpselector_dec_ref(&dlg->tp_sel);
/* Copy transport selector structure .*/
pj_memcpy(&dlg->tp_sel, sel, sizeof(*sel));
/* Increment reference counter */
pjsip_tpselector_add_ref(&dlg->tp_sel);
/* Unlock dialog. */
pjsip_dlg_dec_lock(dlg);
return PJ_SUCCESS;
}
/*
* Create forked dialog from a response.
*/
PJ_DEF(pj_status_t) pjsip_dlg_fork( const pjsip_dialog *first_dlg,
const pjsip_rx_data *rdata,
pjsip_dialog **new_dlg )
{
pjsip_dialog *dlg;
const pjsip_route_hdr *r;
pj_status_t status;
/* Check arguments. */
PJ_ASSERT_RETURN(first_dlg && rdata && new_dlg, PJ_EINVAL);
/* rdata must be response message. */
PJ_ASSERT_RETURN(rdata->msg_info.msg->type == PJSIP_RESPONSE_MSG,
PJSIP_ENOTRESPONSEMSG);
/* Status code MUST be 1xx (but not 100), or 2xx */
status = rdata->msg_info.msg->line.status.code;
PJ_ASSERT_RETURN( (status/100==1 && status!=100) ||
(status/100==2), PJ_EBUG);
/* To tag must present in the response. */
PJ_ASSERT_RETURN(rdata->msg_info.to->tag.slen != 0, PJSIP_EMISSINGTAG);
/* Create the dialog. */
status = create_dialog((pjsip_user_agent*)first_dlg->ua, &dlg);
if (status != PJ_SUCCESS)
return status;
/* Clone remote target. */
dlg->target = pjsip_uri_clone(dlg->pool, first_dlg->target);
/* Clone local info. */
dlg->local.info = pjsip_hdr_clone(dlg->pool, first_dlg->local.info);
/* Clone local tag. */
pj_strdup(dlg->pool, &dlg->local.info->tag, &first_dlg->local.info->tag);
dlg->local.tag_hval = first_dlg->local.tag_hval;
/* Clone local CSeq. */
dlg->local.first_cseq = first_dlg->local.first_cseq;
dlg->local.cseq = first_dlg->local.cseq;
/* Clone local Contact. */
dlg->local.contact = pjsip_hdr_clone(dlg->pool, first_dlg->local.contact);
/* Clone remote info. */
dlg->remote.info = pjsip_hdr_clone(dlg->pool, first_dlg->remote.info);
/* Set remote tag from the response. */
pj_strdup(dlg->pool, &dlg->remote.info->tag, &rdata->msg_info.to->tag);
/* Initialize remote's CSeq to -1. */
dlg->remote.cseq = dlg->remote.first_cseq = -1;
/* Initial role is UAC. */
dlg->role = PJSIP_ROLE_UAC;
/* Dialog state depends on the response. */
status = rdata->msg_info.msg->line.status.code/100;
if (status == 1 || status == 2)
dlg->state = PJSIP_DIALOG_STATE_ESTABLISHED;
else {
pj_assert(!"Invalid status code");
dlg->state = PJSIP_DIALOG_STATE_NULL;
}
/* Secure? */
dlg->secure = PJSIP_URI_SCHEME_IS_SIPS(dlg->target);
/* Clone Call-ID header. */
dlg->call_id = pjsip_hdr_clone(dlg->pool, first_dlg->call_id);
/* Duplicate Route-Set. */
pj_list_init(&dlg->route_set);
r = first_dlg->route_set.next;
while (r != &first_dlg->route_set) {
pjsip_route_hdr *h;
h = pjsip_hdr_clone(dlg->pool, r);
pj_list_push_back(&dlg->route_set, h);
r = r->next;
}
/* Clone client authentication session. */
status = pjsip_auth_clt_clone(dlg->pool, &dlg->auth_sess,
&first_dlg->auth_sess);
if (status != PJ_SUCCESS)
goto on_error;
/* Register this dialog to user agent. */
status = pjsip_ua_register_dlg(dlg->ua, dlg );
if (status != PJ_SUCCESS)
goto on_error;
/* Done! */
*new_dlg = dlg;
PJ_LOG(5,(dlg->obj_name, "Forked dialog created"));
return PJ_SUCCESS;
on_error:
destroy_dialog(dlg);
return status;
}
/*
* Destroy dialog.
*/
static pj_status_t unregister_and_destroy_dialog( pjsip_dialog *dlg )
{
pj_status_t status;
/* Lock must have been held. */
/* Check dialog state. */
/* Number of sessions must be zero. */
PJ_ASSERT_RETURN(dlg->sess_count==0, PJ_EINVALIDOP);
/* MUST not have pending transactions. */
PJ_ASSERT_RETURN(dlg->tsx_count==0, PJ_EINVALIDOP);
/* Unregister from user agent. */
status = pjsip_ua_unregister_dlg(dlg->ua, dlg);
if (status != PJ_SUCCESS) {
pj_assert(!"Unexpected failed unregistration!");
return status;
}
/* Log */
PJ_LOG(5,(dlg->obj_name, "Dialog destroyed"));
/* Destroy this dialog. */
destroy_dialog(dlg);
return PJ_SUCCESS;
}
/*
* Forcefully terminate dialog.
*/
PJ_DEF(pj_status_t) pjsip_dlg_terminate( pjsip_dialog *dlg )
{
/* Number of sessions must be zero. */
PJ_ASSERT_RETURN(dlg->sess_count==0, PJ_EINVALIDOP);
/* MUST not have pending transactions. */
PJ_ASSERT_RETURN(dlg->tsx_count==0, PJ_EINVALIDOP);
return unregister_and_destroy_dialog(dlg);
}
/*
* Set route_set
*/
PJ_DEF(pj_status_t) pjsip_dlg_set_route_set( pjsip_dialog *dlg,
const pjsip_route_hdr *route_set )
{
pjsip_route_hdr *r;
PJ_ASSERT_RETURN(dlg, PJ_EINVAL);
pjsip_dlg_inc_lock(dlg);
/* Clear route set. */
pj_list_init(&dlg->route_set);
if (!route_set) {
pjsip_dlg_dec_lock(dlg);
return PJ_SUCCESS;
}
r = route_set->next;
while (r != route_set) {
pjsip_route_hdr *new_r;
new_r = pjsip_hdr_clone(dlg->pool, r);
pj_list_push_back(&dlg->route_set, new_r);
r = r->next;
}
pjsip_dlg_dec_lock(dlg);
return PJ_SUCCESS;
}
/*
* Increment session counter.
*/
PJ_DEF(pj_status_t) pjsip_dlg_inc_session( pjsip_dialog *dlg,
pjsip_module *mod )
{
PJ_ASSERT_RETURN(dlg && mod, PJ_EINVAL);
pjsip_dlg_inc_lock(dlg);
++dlg->sess_count;
pjsip_dlg_dec_lock(dlg);
PJ_LOG(5,(dlg->obj_name, "Session count inc to %d by %.*s",
dlg->sess_count, (int)mod->name.slen, mod->name.ptr));
return PJ_SUCCESS;
}
/*
* Lock dialog and increment session counter temporarily
* to prevent it from being deleted. In addition, it must lock
* the user agent's dialog table first, to prevent deadlock.
*/
PJ_DEF(void) pjsip_dlg_inc_lock(pjsip_dialog *dlg)
{
PJ_LOG(6,(dlg->obj_name, "Entering pjsip_dlg_inc_lock(), sess_count=%d",
dlg->sess_count));
pj_mutex_lock(dlg->mutex_);
dlg->sess_count++;
PJ_LOG(6,(dlg->obj_name, "Leaving pjsip_dlg_inc_lock(), sess_count=%d",
dlg->sess_count));
}
/* Try to acquire dialog's mutex, but bail out if mutex can not be
* acquired immediately.
*/
PJ_DEF(pj_status_t) pjsip_dlg_try_inc_lock(pjsip_dialog *dlg)
{
pj_status_t status;
PJ_LOG(6,(dlg->obj_name,"Entering pjsip_dlg_try_inc_lock(), sess_count=%d",
dlg->sess_count));
status = pj_mutex_trylock(dlg->mutex_);
if (status != PJ_SUCCESS) {
PJ_LOG(6,(dlg->obj_name, "pjsip_dlg_try_inc_lock() failed"));
return status;
}
dlg->sess_count++;
PJ_LOG(6,(dlg->obj_name, "Leaving pjsip_dlg_try_inc_lock(), sess_count=%d",
dlg->sess_count));
return PJ_SUCCESS;
}
/*
* Unlock dialog and decrement session counter.
* It may delete the dialog!
*/
PJ_DEF(void) pjsip_dlg_dec_lock(pjsip_dialog *dlg)
{
PJ_LOG(6,(dlg->obj_name, "Entering pjsip_dlg_dec_lock(), sess_count=%d",
dlg->sess_count));
pj_assert(dlg->sess_count > 0);
--dlg->sess_count;
if (dlg->sess_count==0 && dlg->tsx_count==0) {
pj_mutex_unlock(dlg->mutex_);
pj_mutex_lock(dlg->mutex_);
unregister_and_destroy_dialog(dlg);
} else {
pj_mutex_unlock(dlg->mutex_);
}
PJ_LOG(6,(THIS_FILE, "Leaving pjsip_dlg_dec_lock() (dlg=%p)", dlg));
}
/*
* Decrement session counter.
*/
PJ_DEF(pj_status_t) pjsip_dlg_dec_session( pjsip_dialog *dlg,
pjsip_module *mod)
{
PJ_ASSERT_RETURN(dlg, PJ_EINVAL);
PJ_LOG(5,(dlg->obj_name, "Session count dec to %d by %.*s",
dlg->sess_count-1, (int)mod->name.slen, mod->name.ptr));
pjsip_dlg_inc_lock(dlg);
--dlg->sess_count;
pjsip_dlg_dec_lock(dlg);
return PJ_SUCCESS;
}
/*
* Add usage.
*/
PJ_DEF(pj_status_t) pjsip_dlg_add_usage( pjsip_dialog *dlg,
pjsip_module *mod,
void *mod_data )
{
unsigned index;
PJ_ASSERT_RETURN(dlg && mod, PJ_EINVAL);
PJ_ASSERT_RETURN(mod->id >= 0 && mod->id < PJSIP_MAX_MODULE,
PJ_EINVAL);
PJ_ASSERT_RETURN(dlg->usage_cnt < PJSIP_MAX_MODULE, PJ_EBUG);
PJ_LOG(5,(dlg->obj_name,
"Module %.*s added as dialog usage, data=%p",
(int)mod->name.slen, mod->name.ptr, mod_data));
pjsip_dlg_inc_lock(dlg);
/* Usages are sorted on priority, lowest number first.
* Find position to put the new module, also makes sure that
* this module has not been registered before.
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -