📄 sip_dialog.c
字号:
for (index=0; index<dlg->usage_cnt; ++index) {
if (dlg->usage[index] == mod) {
/* Module may be registered more than once in the same dialog.
* For example, when call transfer fails, application may retry
* call transfer on the same dialog.
* So return PJ_SUCCESS here.
*/
PJ_LOG(4,(dlg->obj_name,
"Module %.*s already registered as dialog usage, "
"updating the data %p",
(int)mod->name.slen, mod->name.ptr, mod_data));
dlg->mod_data[mod->id] = mod_data;
pjsip_dlg_dec_lock(dlg);
return PJ_SUCCESS;
//pj_assert(!"This module is already registered");
//pjsip_dlg_dec_lock(dlg);
//return PJSIP_ETYPEEXISTS;
}
if (dlg->usage[index]->priority > mod->priority)
break;
}
/* index holds position to put the module.
* Insert module at this index.
*/
pj_array_insert(dlg->usage, sizeof(dlg->usage[0]), dlg->usage_cnt,
index, &mod);
/* Set module data. */
dlg->mod_data[mod->id] = mod_data;
/* Increment count. */
++dlg->usage_cnt;
pjsip_dlg_dec_lock(dlg);
return PJ_SUCCESS;
}
/*
* Attach module specific data to the dialog. Application can also set
* the value directly by accessing dlg->mod_data[module_id].
*/
PJ_DEF(pj_status_t) pjsip_dlg_set_mod_data( pjsip_dialog *dlg,
int mod_id,
void *data )
{
PJ_ASSERT_RETURN(dlg, PJ_EINVAL);
PJ_ASSERT_RETURN(mod_id >= 0 && mod_id < PJSIP_MAX_MODULE,
PJ_EINVAL);
dlg->mod_data[mod_id] = data;
return PJ_SUCCESS;
}
/**
* Get module specific data previously attached to the dialog. Application
* can also get value directly by accessing dlg->mod_data[module_id].
*/
PJ_DEF(void*) pjsip_dlg_get_mod_data( pjsip_dialog *dlg,
int mod_id)
{
PJ_ASSERT_RETURN(dlg, NULL);
PJ_ASSERT_RETURN(mod_id >= 0 && mod_id < PJSIP_MAX_MODULE,
NULL);
return dlg->mod_data[mod_id];
}
/*
* Create a new request within dialog (i.e. after the dialog session has been
* established). The construction of such requests follows the rule in
* RFC3261 section 12.2.1.
*/
static pj_status_t dlg_create_request_throw( pjsip_dialog *dlg,
const pjsip_method *method,
int cseq,
pjsip_tx_data **p_tdata )
{
pjsip_tx_data *tdata;
pjsip_contact_hdr *contact;
pjsip_route_hdr *route, *end_list;
pj_status_t status;
/* Contact Header field.
* Contact can only be present in requests that establish dialog (in the
* core SIP spec, only INVITE).
*/
if (pjsip_method_creates_dialog(method))
contact = dlg->local.contact;
else
contact = NULL;
/*
* Create the request by cloning from the headers in the
* dialog.
*/
status = pjsip_endpt_create_request_from_hdr(dlg->endpt,
method,
dlg->target,
dlg->local.info,
dlg->remote.info,
contact,
dlg->call_id,
cseq,
NULL,
&tdata);
if (status != PJ_SUCCESS)
return status;
/* Just copy dialog route-set to Route header.
* The transaction will do the processing as specified in Section 12.2.1
* of RFC 3261 in function tsx_process_route() in sip_transaction.c.
*/
route = dlg->route_set.next;
end_list = &dlg->route_set;
for (; route != end_list; route = route->next ) {
pjsip_route_hdr *r;
r = pjsip_hdr_shallow_clone( tdata->pool, route );
pjsip_routing_hdr_set_route(r);
pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)r);
}
/* Copy authorization headers, if request is not ACK or CANCEL. */
if (method->id != PJSIP_ACK_METHOD && method->id != PJSIP_CANCEL_METHOD) {
status = pjsip_auth_clt_init_req( &dlg->auth_sess, tdata );
if (status != PJ_SUCCESS)
return status;
}
/* Done. */
*p_tdata = tdata;
return PJ_SUCCESS;
}
/*
* Create outgoing request.
*/
PJ_DEF(pj_status_t) pjsip_dlg_create_request( pjsip_dialog *dlg,
const pjsip_method *method,
int cseq,
pjsip_tx_data **p_tdata)
{
pj_status_t status;
pjsip_tx_data *tdata = NULL;
PJ_USE_EXCEPTION;
PJ_ASSERT_RETURN(dlg && method && p_tdata, PJ_EINVAL);
/* Lock dialog. */
pjsip_dlg_inc_lock(dlg);
/* Use outgoing CSeq and increment it by one. */
if (cseq <= 0)
cseq = dlg->local.cseq + 1;
/* Keep compiler happy */
status = PJ_EBUG;
/* Create the request. */
PJ_TRY {
status = dlg_create_request_throw(dlg, method, cseq, &tdata);
}
PJ_CATCH_ANY {
status = PJ_ENOMEM;
}
PJ_END;
/* Failed! Delete transmit data. */
if (status != PJ_SUCCESS && tdata) {
pjsip_tx_data_dec_ref( tdata );
tdata = NULL;
}
/* Unlock dialog. */
pjsip_dlg_dec_lock(dlg);
*p_tdata = tdata;
return status;
}
/*
* Send request statefully, and update dialog'c CSeq.
*/
PJ_DEF(pj_status_t) pjsip_dlg_send_request( pjsip_dialog *dlg,
pjsip_tx_data *tdata,
int mod_data_id,
void *mod_data)
{
pjsip_transaction *tsx;
pjsip_msg *msg = tdata->msg;
pj_status_t status;
/* Check arguments. */
PJ_ASSERT_RETURN(dlg && tdata && tdata->msg, PJ_EINVAL);
PJ_ASSERT_RETURN(tdata->msg->type == PJSIP_REQUEST_MSG,
PJSIP_ENOTREQUESTMSG);
PJ_LOG(5,(dlg->obj_name, "Sending %s",
pjsip_tx_data_get_info(tdata)));
/* Lock and increment session */
pjsip_dlg_inc_lock(dlg);
/* Update dialog's CSeq and message's CSeq if request is not
* ACK nor CANCEL.
*/
if (msg->line.req.method.id != PJSIP_CANCEL_METHOD &&
msg->line.req.method.id != PJSIP_ACK_METHOD)
{
pjsip_cseq_hdr *ch;
ch = PJSIP_MSG_CSEQ_HDR(msg);
PJ_ASSERT_RETURN(ch!=NULL, PJ_EBUG);
ch->cseq = dlg->local.cseq++;
/* Force the whole message to be re-printed. */
pjsip_tx_data_invalidate_msg( tdata );
}
/* Create a new transaction if method is not ACK.
* The transaction user is the user agent module.
*/
if (msg->line.req.method.id != PJSIP_ACK_METHOD) {
int tsx_count;
status = pjsip_tsx_create_uac(dlg->ua, tdata, &tsx);
if (status != PJ_SUCCESS)
goto on_error;
/* Set transport selector */
status = pjsip_tsx_set_transport(tsx, &dlg->tp_sel);
pj_assert(status == PJ_SUCCESS);
/* Attach this dialog to the transaction, so that user agent
* will dispatch events to this dialog.
*/
tsx->mod_data[dlg->ua->id] = dlg;
/* Copy optional caller's mod_data, if present */
if (mod_data_id >= 0 && mod_data_id < PJSIP_MAX_MODULE)
tsx->mod_data[mod_data_id] = mod_data;
/* Increment transaction counter. */
tsx_count = ++dlg->tsx_count;
/* Send the message. */
status = pjsip_tsx_send_msg(tsx, tdata);
if (status != PJ_SUCCESS) {
if (dlg->tsx_count == tsx_count)
pjsip_tsx_terminate(tsx, tsx->status_code);
goto on_error;
}
} else {
/* Set transport selector */
pjsip_tx_data_set_transport(tdata, &dlg->tp_sel);
/* Send request */
status = pjsip_endpt_send_request_stateless(dlg->endpt, tdata,
NULL, NULL);
if (status != PJ_SUCCESS)
goto on_error;
}
/* Unlock dialog, may destroy dialog. */
pjsip_dlg_dec_lock(dlg);
return PJ_SUCCESS;
on_error:
/* Unlock dialog, may destroy dialog. */
pjsip_dlg_dec_lock(dlg);
/* Whatever happen delete the message. */
pjsip_tx_data_dec_ref( tdata );
return status;
}
/* Add standard headers for certain types of response */
static void dlg_beautify_response(pjsip_dialog *dlg,
pj_bool_t add_headers,
int st_code,
pjsip_tx_data *tdata)
{
pjsip_cseq_hdr *cseq;
int st_class;
const pjsip_hdr *c_hdr;
pjsip_hdr *hdr;
cseq = PJSIP_MSG_CSEQ_HDR(tdata->msg);
pj_assert(cseq != NULL);
st_class = st_code / 100;
/* Contact, Allow, Supported header. */
if (add_headers && pjsip_method_creates_dialog(&cseq->method)) {
/* Add Contact header for 1xx, 2xx, 3xx and 485 response. */
if (st_class==2 || st_class==3 || (st_class==1 && st_code != 100) ||
st_code==485)
{
pj_str_t hcontact = { "Contact", 7 };
/* Add contact header only if one is not present. */
if (pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, NULL) == 0 &&
pjsip_msg_find_hdr_by_name(tdata->msg, &hcontact, NULL) == 0)
{
hdr = pjsip_hdr_clone(tdata->pool, dlg->local.contact);
pjsip_msg_add_hdr(tdata->msg, hdr);
}
}
/* Add Allow header in 2xx and 405 response. */
if ((st_class==2 || st_code==405) &&
pjsip_msg_find_hdr(tdata->msg, PJSIP_H_ALLOW, NULL)==NULL)
{
c_hdr = pjsip_endpt_get_capability(dlg->endpt,
PJSIP_H_ALLOW, NULL);
if (c_hdr) {
hdr = pjsip_hdr_clone(tdata->pool, c_hdr);
pjsip_msg_add_hdr(tdata->msg, hdr);
}
}
/* Add Supported header in 2xx response. */
if (st_class==2 &&
pjsip_msg_find_hdr(tdata->msg, PJSIP_H_SUPPORTED, NULL)==NULL)
{
c_hdr = pjsip_endpt_get_capability(dlg->endpt,
PJSIP_H_SUPPORTED, NULL);
if (c_hdr) {
hdr = pjsip_hdr_clone(tdata->pool, c_hdr);
pjsip_msg_add_hdr(tdata->msg, hdr);
}
}
}
/* Add To tag in all responses except 100 */
if (st_code != 100) {
pjsip_to_hdr *to;
to = PJSIP_MSG_TO_HDR(tdata->msg);
pj_assert(to != NULL);
to->tag = dlg->local.info->tag;
if (dlg->state == PJSIP_DIALOG_STATE_NULL)
dlg->state = PJSIP_DIALOG_STATE_ESTABLISHED;
}
}
/*
* Create response.
*/
PJ_DEF(pj_status_t) pjsip_dlg_create_response( pjsip_dialog *dlg,
pjsip_rx_data *rdata,
int st_code,
const pj_str_t *st_text,
pjsip_tx_data **p_tdata)
{
pj_status_t status;
pjsip_tx_data *tdata;
/* Create generic response.
* This will initialize response's Via, To, From, Call-ID, CSeq
* and Record-Route headers from the request.
*/
status = pjsip_endpt_create_response(dlg->endpt,
rdata, st_code, st_text, &tdata);
if (status != PJ_SUCCESS)
return status;
/* Lock the dialog. */
pjsip_dlg_inc_lock(dlg);
dlg_beautify_response(dlg, PJ_FALSE, st_code, tdata);
/* Unlock the dialog. */
pjsip_dlg_dec_lock(dlg);
/* Done. */
*p_tdata = tdata;
return PJ_SUCCESS;
}
/*
* Modify response.
*/
PJ_DEF(pj_status_t) pjsip_dlg_modify_response( pjsip_dialog *dlg,
pjsip_tx_data *tdata,
int st_code,
const pj_str_t *st_text)
{
pjsip_hdr *hdr;
PJ_ASSERT_RETURN(dlg && tdata && tdata->msg, PJ_EINVAL);
PJ_ASSERT_RETURN(tdata->msg->type == PJSIP_RESPONSE_MSG,
PJSIP_ENOTRESPONSEMSG);
PJ_ASSERT_RETURN(st_code >= 100 && st_code <= 699, PJ_EINVAL);
/* Lock and increment session */
pjsip_dlg_inc_lock(dlg);
/* Replace status code and reason */
tdata->msg->line.status.code = st_code;
if (st_text) {
pj_strdup(tdata->pool, &tdata->msg->line.status.reason, st_text);
} else {
tdata->msg->line.status.reason = *pjsip_get_status_text(st_code);
}
/* Remove existing Contact header (without this, when dialog sent
* 180 and then 302, the Contact in 302 will not get updated).
*/
hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, NULL);
if (hdr)
pj_list_erase(hdr);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -