📄 sip_transaction.c
字号:
* 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. */ 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; code = msg->line.status.code; /* If the response is final, cancel both retransmission and timeout * timer. */ if (code >= 200) { if (tsx->retransmit_timer._timer_id != -1) { pjsip_endpt_cancel_timer(tsx->endpt, &tsx->retransmit_timer); tsx->retransmit_timer._timer_id = -1; } if (tsx->timeout_timer._timer_id != -1) { pjsip_endpt_cancel_timer(tsx->endpt, &tsx->timeout_timer); tsx->timeout_timer._timer_id = -1; } } else { /* Cancel retransmit timer (for non-INVITE transaction, the * retransmit timer will be rescheduled at T2. */ if (tsx->retransmit_timer._timer_id != -1) { pjsip_endpt_cancel_timer(tsx->endpt, &tsx->retransmit_timer); tsx->retransmit_timer._timer_id = -1; } /* For provisional response, only cancel retransmit when this * is an INVITE transaction. For non-INVITE, section 17.1.2.1 * of RFC 3261 says that: * - retransmit timer is set to T2 * - timeout timer F is not deleted. */ if (tsx->method.id == PJSIP_INVITE_METHOD) { /* Cancel timeout timer */ pjsip_endpt_cancel_timer(tsx->endpt, &tsx->timeout_timer); } else { if (!tsx->is_reliable) { pjsip_endpt_schedule_timer(tsx->endpt, &tsx->retransmit_timer, &t2_timer_val); } } } tsx->transport_flag &= ~(TSX_HAS_PENDING_RESCHED); /* 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 unreliable transport is used, retransmission * timer G will be scheduled (retransmission). */ if (!tsx->is_reliable) { pjsip_cseq_hdr *cseq = pjsip_msg_find_hdr( msg, PJSIP_H_CSEQ, NULL); if (cseq->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); } } } /* Inform TU */ tsx_set_state( tsx, PJSIP_TSX_STATE_COMPLETED, PJSIP_EVENT_TX_MSG, tdata ); } else { pj_assert(0); } } else if (event->type == PJSIP_EVENT_TIMER && event->body.timer.entry == &tsx->retransmit_timer) { /* Retransmission timer elapsed. */ pj_status_t status; /* Must not be triggered while transport is pending. */ pj_assert((tsx->transport_flag & TSX_HAS_PENDING_TRANSPORT) == 0); /* Must have last response to retransmit. */ pj_assert(tsx->last_tx != NULL); /* Retransmit the last response. */ 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) { /* Timeout timer. should not happen? */ pj_assert(!"Should not happen(?)"); tsx_set_status_code(tsx, PJSIP_SC_TSX_TIMEOUT, NULL); tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, PJSIP_EVENT_TIMER, &tsx->timeout_timer); return PJ_EBUG; } else { pj_assert(!"Unexpected event"); return PJ_EBUG; } return PJ_SUCCESS;}/* * Handler for events in Proceeding for UAC * This state happens after provisional response(s) has been received from * UAS. */static pj_status_t tsx_on_state_proceeding_uac(pjsip_transaction *tsx, pjsip_event *event){ pj_asser
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -