📄 sip_inv.c
字号:
case PJSIP_TSX_STATE_TERMINATED:
/* INVITE transaction can be terminated either because UAC
* transaction received 2xx response or because of transport
* error.
*/
if (tsx->status_code/100 == 2) {
/* This must be receipt of 2xx response */
/* Set state to CONNECTING */
inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
inv_check_sdp_in_incoming_msg(inv, tsx,
e->body.tsx_state.src.rdata);
/* Send ACK */
pj_assert(e->body.tsx_state.type == PJSIP_EVENT_RX_MSG);
inv_send_ack(inv, e->body.tsx_state.src.rdata);
inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, e);
} else {
inv_set_cause(inv, tsx->status_code, &tsx->status_text);
inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
}
break;
default:
break;
}
} else if (inv->role == PJSIP_ROLE_UAC &&
tsx->role == PJSIP_ROLE_UAC &&
tsx->method.id == PJSIP_CANCEL_METHOD)
{
/*
* Handle case when outgoing CANCEL is answered with 481 (Call/
* Transaction Does Not Exist), 408, or when it's timed out. In these
* cases, disconnect session (i.e. dialog usage only).
*/
if (tsx->status_code == PJSIP_SC_CALL_TSX_DOES_NOT_EXIST ||
tsx->status_code == PJSIP_SC_REQUEST_TIMEOUT ||
tsx->status_code == PJSIP_SC_TSX_TIMEOUT ||
tsx->status_code == PJSIP_SC_TSX_TRANSPORT_ERROR)
{
inv_set_cause(inv, tsx->status_code, &tsx->status_text);
inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
}
}
}
/*
* State INCOMING is after we received the request, but before
* responses with tag are sent.
*/
static void inv_on_state_incoming( pjsip_inv_session *inv, pjsip_event *e)
{
pjsip_transaction *tsx = e->body.tsx_state.tsx;
pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
PJ_ASSERT_ON_FAIL(tsx && dlg, return);
if (tsx == inv->invite_tsx) {
/*
* Handle the INVITE state transition.
*/
switch (tsx->state) {
case PJSIP_TSX_STATE_TRYING:
inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e);
break;
case PJSIP_TSX_STATE_PROCEEDING:
/*
* Transaction sent provisional response.
*/
if (tsx->status_code > 100)
inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
break;
case PJSIP_TSX_STATE_COMPLETED:
/*
* Transaction sent final response.
*/
if (tsx->status_code/100 == 2) {
inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
} else {
inv_set_cause(inv, tsx->status_code, &tsx->status_text);
inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
}
break;
case PJSIP_TSX_STATE_TERMINATED:
/*
* This happens on transport error (e.g. failed to send
* response)
*/
inv_set_cause(inv, tsx->status_code, &tsx->status_text);
inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
break;
default:
pj_assert(!"Unexpected INVITE state");
break;
}
} else if (tsx->method.id == PJSIP_CANCEL_METHOD &&
tsx->role == PJSIP_ROLE_UAS &&
tsx->state < PJSIP_TSX_STATE_COMPLETED &&
e->body.tsx_state.type == PJSIP_EVENT_RX_MSG )
{
/*
* Handle incoming CANCEL request.
*/
inv_respond_incoming_cancel(inv, tsx, e->body.tsx_state.src.rdata);
}
}
/*
* State EARLY is for both UAS and UAC, after response with To tag
* is sent/received.
*/
static void inv_on_state_early( pjsip_inv_session *inv, pjsip_event *e)
{
pjsip_transaction *tsx = e->body.tsx_state.tsx;
pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
PJ_ASSERT_ON_FAIL(tsx && dlg, return);
if (tsx == inv->invite_tsx) {
/*
* Handle the INVITE state progress.
*/
switch (tsx->state) {
case PJSIP_TSX_STATE_PROCEEDING:
/* Send/received another provisional response. */
inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
inv_check_sdp_in_incoming_msg(inv, tsx,
e->body.tsx_state.src.rdata);
}
break;
case PJSIP_TSX_STATE_COMPLETED:
if (tsx->status_code/100 == 2) {
inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
inv_check_sdp_in_incoming_msg(inv, tsx,
e->body.tsx_state.src.rdata);
}
} else {
inv_set_cause(inv, tsx->status_code, &tsx->status_text);
inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
}
break;
case PJSIP_TSX_STATE_CONFIRMED:
/* For some reason can go here */
case PJSIP_TSX_STATE_TERMINATED:
/* INVITE transaction can be terminated either because UAC
* transaction received 2xx response or because of transport
* error.
*/
if (tsx->status_code/100 == 2) {
/* This must be receipt of 2xx response */
/* Set state to CONNECTING */
inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
inv_check_sdp_in_incoming_msg(inv, tsx,
e->body.tsx_state.src.rdata);
}
/* if UAC, send ACK and move state to confirmed. */
if (tsx->role == PJSIP_ROLE_UAC) {
pj_assert(e->body.tsx_state.type == PJSIP_EVENT_RX_MSG);
inv_send_ack(inv, e->body.tsx_state.src.rdata);
inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, e);
}
} else {
inv_set_cause(inv, tsx->status_code, &tsx->status_text);
inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
}
break;
default:
pj_assert(!"Unexpected INVITE tsx state");
}
} else if (inv->role == PJSIP_ROLE_UAS &&
tsx->role == PJSIP_ROLE_UAS &&
tsx->method.id == PJSIP_CANCEL_METHOD &&
tsx->state < PJSIP_TSX_STATE_COMPLETED &&
e->body.tsx_state.type == PJSIP_EVENT_RX_MSG )
{
/*
* Handle incoming CANCEL request.
*/
inv_respond_incoming_cancel(inv, tsx, e->body.tsx_state.src.rdata);
} else if (inv->role == PJSIP_ROLE_UAC &&
tsx->role == PJSIP_ROLE_UAC &&
tsx->method.id == PJSIP_CANCEL_METHOD)
{
/*
* Handle case when outgoing CANCEL is answered with 481 (Call/
* Transaction Does Not Exist), 408, or when it's timed out. In these
* cases, disconnect session (i.e. dialog usage only).
*/
if (tsx->status_code == PJSIP_SC_CALL_TSX_DOES_NOT_EXIST ||
tsx->status_code == PJSIP_SC_REQUEST_TIMEOUT ||
tsx->status_code == PJSIP_SC_TSX_TIMEOUT ||
tsx->status_code == PJSIP_SC_TSX_TRANSPORT_ERROR)
{
inv_set_cause(inv, tsx->status_code, &tsx->status_text);
inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
}
}
}
/*
* State CONNECTING is after 2xx response to INVITE is sent/received.
*/
static void inv_on_state_connecting( pjsip_inv_session *inv, pjsip_event *e)
{
pjsip_transaction *tsx = e->body.tsx_state.tsx;
pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
PJ_ASSERT_ON_FAIL(tsx && dlg, return);
if (tsx == inv->invite_tsx) {
/*
* Handle INVITE state progression.
*/
switch (tsx->state) {
case PJSIP_TSX_STATE_CONFIRMED:
if (tsx->status_code/100 == 2)
inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, e);
break;
case PJSIP_TSX_STATE_TERMINATED:
/* INVITE transaction can be terminated either because UAC
* transaction received 2xx response or because of transport
* error.
*/
if (tsx->status_code/100 != 2) {
inv_set_cause(inv, tsx->status_code, &tsx->status_text);
inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
}
break;
case PJSIP_TSX_STATE_DESTROYED:
/* Do nothing. */
break;
default:
pj_assert(!"Unexpected state");
}
} else if (tsx->role == PJSIP_ROLE_UAS &&
tsx->method.id == PJSIP_BYE_METHOD &&
tsx->status_code < 200 &&
e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
{
/*
* Handle incoming BYE.
*/
inv_respond_incoming_bye( inv, tsx, e->body.tsx_state.src.rdata, e );
} else if (tsx->method.id == PJSIP_BYE_METHOD &&
tsx->role == PJSIP_ROLE_UAC &&
(tsx->state == PJSIP_TSX_STATE_COMPLETED ||
tsx->state == PJSIP_TSX_STATE_TERMINATED))
{
/*
* Outgoing BYE
*/
inv_handle_bye_response( inv, tsx, e->body.tsx_state.src.rdata, e);
}
else if (tsx->method.id == PJSIP_CANCEL_METHOD &&
tsx->role == PJSIP_ROLE_UAS &&
tsx->status_code < 200 &&
e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
{
/*
* Handle strandled incoming CANCEL.
*/
pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
pjsip_tx_data *tdata;
pj_status_t status;
status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
if (status != PJ_SUCCESS) return;
status = pjsip_dlg_send_response(dlg, tsx, tdata);
if (status != PJ_SUCCESS) return;
}
}
/*
* State CONFIRMED is after ACK is sent/received.
*/
static void inv_on_state_confirmed( pjsip_inv_session *inv, pjsip_event *e)
{
pjsip_transaction *tsx = e->body.tsx_state.tsx;
pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
PJ_ASSERT_ON_FAIL(tsx && dlg, return);
if (tsx->method.id == PJSIP_BYE_METHOD &&
tsx->role == PJSIP_ROLE_UAC &&
(tsx->state == PJSIP_TSX_STATE_COMPLETED ||
tsx->state == PJSIP_TSX_STATE_TERMINATED))
{
/*
* Outgoing BYE
*/
inv_handle_bye_response( inv, tsx, e->body.tsx_state.src.rdata, e);
}
else if (tsx->method.id == PJSIP_BYE_METHOD &&
tsx->role == PJSIP_ROLE_UAS &&
tsx->status_code < 200 &&
e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
{
/*
* Handle incoming BYE.
*/
inv_respond_incoming_bye( inv, tsx, e->body.tsx_state.src.rdata, e );
}
else if (tsx->method.id == PJSIP_CANCEL_METHOD &&
tsx->role == PJSIP_ROLE_UAS &&
tsx->status_code < 200 &&
e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
{
/*
* Handle strandled incoming CANCEL.
*/
pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
pjsip_tx_data *tdata;
pj_status_t status;
status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
if (status != PJ_SUCCESS) return;
status = pjsip_dlg_send_response(dlg, tsx, tdata);
if (status != PJ_SUCCESS) return;
}
else if (tsx->method.id == PJSIP_INVITE_METHOD &&
tsx->role == PJSIP_ROLE_UAS)
{
/*
* Handle incoming re-INVITE
*/
if (tsx->state == PJSIP_TSX_STATE_TRYING) {
pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
pjsip_tx_data *tdata;
pj_status_t status;
/* Check if we have INVITE pending. */
if (inv->invite_tsx && inv->invite_tsx!=tsx) {
pj_str_t reason;
reason = pj_str("Another INVITE transaction in progress");
/* Can not receive re-INVITE while another one is pending. */
status = pjsip_dlg_create_response( inv->dlg, rdata, 500,
&reason, &tdata);
if (status != PJ_SUCCESS)
return;
status = pjsip_dlg_send_response( inv->dlg, tsx, tdata);
return;
}
/* Save the invite transaction. */
inv->invite_tsx = tsx;
/* Process SDP in incoming message. */
status = inv_check_sdp_in_incoming_msg(inv, tsx, rdata);
if (status != PJ_SUCCESS) {
/* Not Acceptable */
const pjsip_hdr *accept;
status = pjsip_dlg_create_response(inv->dlg, rdata,
488, NULL, &tdata);
if (status != PJ_SUCCESS)
return;
accept = pjsip_endpt_get_capability(dlg->endpt, PJSIP_H_ACCEPT,
NULL);
if (accept) {
pjsip_msg_add_hdr(tdata->msg,
pjsip_hdr_clone(tdata->pool, accept));
}
status = pjsip_dlg_send_response(dlg, tsx, tdata);
return;
}
/* Create 2xx ANSWER */
status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
if (status != PJ_SUCCESS)
return;
/* Process SDP in the answer */
status = process_answer(inv, 200, tdata, NULL);
if (status != PJ_SUCCESS) {
/*
* SDP negotiation has failed.
*/
pj_status_t rc;
pj_str_t reason;
/* Delete the 2xx answer */
pjsip_tx_data_dec_ref(tdata);
/* Create 500 response */
reason = pj_str("SDP negotiation failed");
rc = pjsip_dlg_create_response(dlg, rdata, 500, &reason,
&tdata);
if (rc == PJ_SUCCESS) {
pjsip_warning_hdr *w;
const pj_str_t *endpt_name;
endpt_name = pjsip_endpt_name(dlg->endpt);
w = pjsip_warning_hdr_create_from_status(tdata->pool,
endpt_name,
status);
if (w)
pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)w);
pjsip_inv_send_msg(inv, tdata);
}
return;
}
/* Send 2xx regardless of the status of negotiation */
status = pjsip_inv_send_msg(inv, tdata);
}
}
else if (tsx->method.id == PJSIP_INVITE_METHOD &&
tsx->role == PJSIP_ROLE_UAC)
{
/*
* Handle outgoing re-INVITE
*/
if (t
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -