📄 sip_transaction.c
字号:
msec_time = PJSIP_T2_TIMEOUT;
} else {
/* Retransmission of INVITE final response also caps-off at T2 */
pj_assert(tsx->status_code >= 200);
if (msec_time>PJSIP_T2_TIMEOUT)
msec_time = PJSIP_T2_TIMEOUT;
}
timeout.sec = msec_time / 1000;
timeout.msec = msec_time % 1000;
pjsip_endpt_schedule_timer( tsx->endpt, &tsx->retransmit_timer,
&timeout);
}
/*
* Retransmit last message sent.
*/
static pj_status_t tsx_retransmit( pjsip_transaction *tsx, int resched)
{
pj_status_t status;
PJ_ASSERT_RETURN(tsx->last_tx!=NULL, PJ_EBUG);
PJ_LOG(5,(tsx->obj_name, "Retransmiting %s, count=%d, restart?=%d",
pjsip_tx_data_get_info(tsx->last_tx),
tsx->retransmit_count, resched));
++tsx->retransmit_count;
/* Restart timer T1 first before sending the message to ensure that
* retransmission timer is not engaged when loop transport is used.
*/
if (resched) {
pj_assert(tsx->state != PJSIP_TSX_STATE_CONFIRMED);
if (tsx->transport_flag & TSX_HAS_PENDING_TRANSPORT) {
tsx->transport_flag |= TSX_HAS_PENDING_RESCHED;
} else {
tsx_resched_retransmission(tsx);
}
}
status = tsx_send_msg( tsx, tsx->last_tx);
if (status != PJ_SUCCESS) {
return status;
}
return PJ_SUCCESS;
}
/*
* Handler for events in state Null.
*/
static pj_status_t tsx_on_state_null( pjsip_transaction *tsx,
pjsip_event *event )
{
pj_status_t status;
pj_assert(tsx->state == PJSIP_TSX_STATE_NULL);
if (tsx->role == PJSIP_ROLE_UAS) {
/* Set state to Trying. */
pj_assert(event->type == PJSIP_EVENT_RX_MSG &&
event->body.rx_msg.rdata->msg_info.msg->type ==
PJSIP_REQUEST_MSG);
tsx_set_state( tsx, PJSIP_TSX_STATE_TRYING, PJSIP_EVENT_RX_MSG,
event->body.rx_msg.rdata);
} else {
pjsip_tx_data *tdata;
/* Must be transmit event.
* You may got this assertion when using loop transport with delay
* set to zero. That would cause on_rx_response() callback to be
* called before tsx_send_msg() has completed.
*/
PJ_ASSERT_RETURN(event->type == PJSIP_EVENT_TX_MSG, PJ_EBUG);
/* Get the txdata */
tdata = event->body.tx_msg.tdata;
/* Save the message for retransmission. */
if (tsx->last_tx && tsx->last_tx != tdata) {
pjsip_tx_data_dec_ref(tsx->last_tx);
tsx->last_tx = NULL;
}
if (tsx->last_tx != tdata) {
tsx->last_tx = tdata;
pjsip_tx_data_add_ref(tdata);
}
/* Send the message. */
status = tsx_send_msg( tsx, tdata);
if (status != PJ_SUCCESS) {
return status;
}
/* Start Timer B (or called timer F for non-INVITE) for transaction
* timeout. If user has configured the timeout value with
* pjsip_tsx_set_uac_timeout(), use the timeout value there.
*/
if (tsx->msec_timeout > 0) {
pj_time_val timeout;
timeout.sec = tsx->msec_timeout / 1000;
timeout.msec = tsx->msec_timeout % 1000;
pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer,
&timeout);
} else {
pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer,
&timeout_timer_val);
}
/* Start Timer A (or timer E) for retransmission only if unreliable
* transport is being used.
*/
if (!tsx->is_reliable) {
tsx->retransmit_count = 0;
if (tsx->transport_flag & TSX_HAS_PENDING_TRANSPORT) {
tsx->transport_flag |= TSX_HAS_PENDING_RESCHED;
} else {
pjsip_endpt_schedule_timer(tsx->endpt, &tsx->retransmit_timer,
&t1_timer_val);
}
}
/* Move state. */
tsx_set_state( tsx, PJSIP_TSX_STATE_CALLING,
PJSIP_EVENT_TX_MSG, tdata);
}
return PJ_SUCCESS;
}
/*
* State Calling is for UAC after it sends request but before any responses
* is received.
*/
static pj_status_t tsx_on_state_calling( pjsip_transaction *tsx,
pjsip_event *event )
{
pj_assert(tsx->state == PJSIP_TSX_STATE_CALLING);
pj_assert(tsx->role == PJSIP_ROLE_UAC);
if (event->type == PJSIP_EVENT_TIMER &&
event->body.timer.entry == &tsx->retransmit_timer)
{
pj_status_t status;
/* Retransmit the request. */
status = tsx_retransmit( tsx, 1 );
if (status != PJ_SUCCESS) {
return status;
}
} else if (event->type == PJSIP_EVENT_TIMER &&
event->body.timer.entry == &tsx->timeout_timer)
{
/* Cancel retransmission timer. */
if (tsx->retransmit_timer._timer_id != -1) {
pjsip_endpt_cancel_timer(tsx->endpt, &tsx->retransmit_timer);
tsx->retransmit_timer._timer_id = -1;
}
tsx->transport_flag &= ~(TSX_HAS_PENDING_RESCHED);
/* Set status code */
tsx_set_status_code(tsx, PJSIP_SC_TSX_TIMEOUT, NULL);
/* Inform TU. */
tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED,
PJSIP_EVENT_TIMER, &tsx->timeout_timer);
/* Transaction is destroyed */
//return PJSIP_ETSXDESTROYED;
} else if (event->type == PJSIP_EVENT_RX_MSG) {
pjsip_msg *msg;
int code;
/* Get message instance */
msg = event->body.rx_msg.rdata->msg_info.msg;
/* Better be a response message. */
if (msg->type != PJSIP_RESPONSE_MSG)
return PJSIP_ENOTRESPONSEMSG;
/* Cancel retransmission timer A. */
if (tsx->retransmit_timer._timer_id != -1) {
pjsip_endpt_cancel_timer(tsx->endpt, &tsx->retransmit_timer);
tsx->retransmit_timer._timer_id = -1;
}
tsx->transport_flag &= ~(TSX_HAS_PENDING_RESCHED);
/* Cancel timer B (transaction timeout) but look at the timeout policy
* as set by pjsip_tsx_set_uac_timeout().
*/
code = msg->line.status.code;
if ((code==100 && tsx->timeout_policy==PJSIP_TSX_IGNORE_100) ||
(code<200 && tsx->timeout_policy==PJSIP_TSX_IGNORE_1xx))
{
/* Don't cancel the timeout timer */
}
else {
pjsip_endpt_cancel_timer(tsx->endpt, &tsx->timeout_timer);
}
/* Discard retransmission message if it is not INVITE.
* The INVITE tdata is needed in case we have to generate ACK for
* the final response.
*/
/* Keep last_tx for authorization. */
//blp: always keep last_tx until transaction is destroyed
//code = msg->line.status.code;
//if (tsx->method.id != PJSIP_INVITE_METHOD && code!=401 && code!=407) {
// pjsip_tx_data_dec_ref(tsx->last_tx);
// tsx->last_tx = NULL;
//}
/* Processing is similar to state Proceeding. */
tsx_on_state_proceeding_uac( tsx, event);
} else {
pj_assert(!"Unexpected event");
return PJ_EBUG;
}
return PJ_SUCCESS;
}
/*
* State Trying is for UAS after it received request but before any responses
* is sent.
* Note: this is different than RFC3261, which can use Trying state for
* non-INVITE client transaction (bug in RFC?).
*/
static pj_status_t tsx_on_state_trying( pjsip_transaction *tsx,
pjsip_event *event)
{
pj_status_t status;
pj_assert(tsx->state == PJSIP_TSX_STATE_TRYING);
/* This state is only for UAS */
pj_assert(tsx->role == PJSIP_ROLE_UAS);
/* Better be transmission of response message.
* If we've got request retransmission, this means that the TU hasn't
* transmitted any responses within 500 ms, which is not allowed. If
* this happens, just ignore the event (we couldn't retransmit last
* response because we haven't sent any!).
*/
if (event->type != PJSIP_EVENT_TX_MSG) {
return PJ_SUCCESS;
}
/* The rest of the processing of the event is exactly the same as in
* "Proceeding" state.
*/
status = tsx_on_state_proceeding_uas( tsx, event);
/* Inform the TU of the state transision if state is still State_Trying */
if (status==PJ_SUCCESS && tsx->state == PJSIP_TSX_STATE_TRYING) {
tsx_set_state( tsx, PJSIP_TSX_STATE_PROCEEDING,
PJSIP_EVENT_TX_MSG, event->body.tx_msg.tdata);
}
return status;
}
/*
* Handler for events in Proceeding for UAS
* This state happens after the TU sends provisional response.
*/
static pj_status_t tsx_on_state_proceeding_uas( pjsip_transaction *tsx,
pjsip_event *event)
{
pj_assert(tsx->state == PJSIP_TSX_STATE_PROCEEDING ||
tsx->state == PJSIP_TSX_STATE_TRYING);
/* This state is only for UAS. */
pj_assert(tsx->role == PJSIP_ROLE_UAS);
/* Receive request retransmission. */
if (event->type == PJSIP_EVENT_RX_MSG) {
pj_status_t status;
/* Must have last response sent. */
PJ_ASSERT_RETURN(tsx->last_tx != NULL, PJ_EBUG);
/* Send last response */
if (tsx->transport_flag & TSX_HAS_PENDING_TRANSPORT) {
tsx->transport_flag |= TSX_HAS_PENDING_SEND;
} else {
status = tsx_send_msg(tsx, tsx->last_tx);
if (status != PJ_SUCCESS)
return status;
}
} else if (event->type == PJSIP_EVENT_TX_MSG ) {
pjsip_tx_data *tdata = event->body.tx_msg.tdata;
pj_status_t status;
/* The TU sends response message to the request. Save this message so
* that we can retransmit the last response in case we receive request
* retransmission.
*/
pjsip_msg *msg = tdata->msg;
/* This can only be a response message. */
PJ_ASSERT_RETURN(msg->type==PJSIP_RESPONSE_MSG, PJSIP_ENOTRESPONSEMSG);
/* Update last status */
tsx_set_status_code(tsx, msg->line.status.code,
&msg->line.status.reason);
/* Discard the saved last response (it will be updated later as
* necessary).
*/
if (tsx->last_tx && tsx->last_tx != tdata) {
pjsip_tx_data_dec_ref( tsx->last_tx );
tsx->last_tx = NULL;
}
/* Send the message. */
status = tsx_send_msg(tsx, tdata);
if (status != PJ_SUCCESS) {
return status;
}
// Update To tag header for RFC2543 transaction.
// TODO:
/* Update transaction state */
if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 100)) {
if (tsx->last_tx != tdata) {
tsx->last_tx = tdata;
pjsip_tx_data_add_ref( tdata );
}
tsx_set_state( tsx, PJSIP_TSX_STATE_PROCEEDING,
PJSIP_EVENT_TX_MSG, tdata );
} else if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 200)) {
if (tsx->method.id == PJSIP_INVITE_METHOD && tsx->handle_200resp==0) {
/* 2xx class message is not saved, because retransmission
* is handled by TU.
*/
tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED,
PJSIP_EVENT_TX_MSG, tdata );
/* Transaction is destroyed. */
//return PJSIP_ETSXDESTROYED;
} else {
pj_time_val timeout;
if (tsx->method.id == PJSIP_INVITE_METHOD) {
tsx->retransmit_count = 0;
if (tsx->transport_flag & TSX_HAS_PENDING_TRANSPORT) {
tsx->transport_flag |= TSX_HAS_PENDING_RESCHED;
} else {
pjsip_endpt_schedule_timer( tsx->endpt,
&tsx->retransmit_timer,
&t1_timer_val);
}
}
/* Save last response sent for retransmission when request
* retransmission is received.
*/
if (tsx->last_tx != tdata) {
tsx->last_tx = tdata;
pjsip_tx_data_add_ref(tdata);
}
/* Setup timeout timer: */
if (tsx->method.id == PJSIP_INVITE_METHOD) {
/* Start Timer H at 64*T1 for INVITE server transaction,
* regardless of transport.
*/
timeout = timeout_timer_val;
} else if (PJSIP_TRANSPORT_IS_RELIABLE(tsx->transport)==0) {
/* For non-INVITE, start timer J at 64*T1 for unreliable
* transport.
*/
timeout = timeout_timer_val;
} else {
/* Transaction terminates immediately for non-INVITE when
* reliable transport is used.
*/
timeout.sec = timeout.msec = 0;
}
pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer,
&timeout);
/* Set state to "Completed" */
tsx_set_state( tsx, PJSIP_TSX_STATE_COMPLETED,
PJSIP_EVENT_TX_MSG, tdata );
}
} else if (tsx->status_code >= 300) {
/* 3xx-6xx class message causes transaction to move to
* "Completed" state.
*/
if (tsx->last_tx != tdata) {
tsx->last_tx = tdata;
pjsip_tx_data_add_ref( tdata );
}
/* For INVITE, start timer H for transaction termination
* regardless whether transport is reliable or not.
* For non-INVITE, start timer J with the value of 64*T1 for
* non-reliable transports, and zero for reliable transports.
*/
if (tsx->method.id == PJSIP_INVITE_METHOD) {
/* Start timer H for INVITE */
pjsip_endpt_schedule_timer(tsx->endpt,&tsx->timeout_timer,
&timeout_timer_val);
} else if (!tsx->is_reliable) {
/* Start timer J on 64*T1 seconds for non-INVITE */
pjsip_endpt_schedule_timer(tsx->endpt,&tsx->timeout_timer,
&timeout_timer_val);
} else {
/* Start timer J on zero seconds for non-INVITE */
pj_time_val zero_time = { 0, 0 };
pjsip_endpt_schedule_timer(tsx->endpt,&tsx->timeout_timer,
&zero_time);
}
/* For INVITE, if unre
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -