📄 sip_transaction.c
字号:
}/* * Forcely terminate transaction. */PJ_DEF(pj_status_t) pjsip_tsx_terminate( pjsip_transaction *tsx, int code ){ struct tsx_lock_data lck; PJ_LOG(5,(tsx->obj_name, "Request to terminate transaction")); PJ_ASSERT_RETURN(tsx != NULL, PJ_EINVAL); PJ_ASSERT_RETURN(code >= 200, PJ_EINVAL); if (tsx->state == PJSIP_TSX_STATE_TERMINATED) return PJ_SUCCESS; lock_tsx(tsx, &lck); tsx_set_status_code(tsx, code, NULL); tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, PJSIP_EVENT_USER, NULL); unlock_tsx(tsx, &lck); return PJ_SUCCESS;}/* * This function is called by TU to send a message. */PJ_DEF(pj_status_t) pjsip_tsx_send_msg( pjsip_transaction *tsx, pjsip_tx_data *tdata ){ pjsip_event event; struct tsx_lock_data lck; pj_status_t status; if (tdata == NULL) tdata = tsx->last_tx; PJ_ASSERT_RETURN(tdata != NULL, PJ_EINVALIDOP); PJ_LOG(5,(tsx->obj_name, "Sending %s in state %s", pjsip_tx_data_get_info(tdata), state_str[tsx->state])); PJSIP_EVENT_INIT_TX_MSG(event, tdata); /* Dispatch to transaction. */ lock_tsx(tsx, &lck); /* Set transport selector to tdata */ pjsip_tx_data_set_transport(tdata, &tsx->tp_sel); /* Dispatch to state handler */ status = (*tsx->state_handler)(tsx, &event); unlock_tsx(tsx, &lck); /* Only decrement reference counter when it returns success. * (This is the specification from the .PDF design document). */ if (status == PJ_SUCCESS) { pjsip_tx_data_dec_ref(tdata); } return status;}/* * This function is called by endpoint when incoming message for the * transaction is received. */PJ_DEF(void) pjsip_tsx_recv_msg( pjsip_transaction *tsx, pjsip_rx_data *rdata){ pjsip_event event; struct tsx_lock_data lck; pj_status_t status; PJ_LOG(5,(tsx->obj_name, "Incoming %s in state %s", pjsip_rx_data_get_info(rdata), state_str[tsx->state])); /* Put the transaction in the rdata's mod_data. */ rdata->endpt_info.mod_data[mod_tsx_layer.mod.id] = tsx; /* Init event. */ PJSIP_EVENT_INIT_RX_MSG(event, rdata); /* Dispatch to transaction. */ lock_tsx(tsx, &lck); status = (*tsx->state_handler)(tsx, &event); unlock_tsx(tsx, &lck);}/* Callback called by send message framework */static void send_msg_callback( pjsip_send_state *send_state, pj_ssize_t sent, pj_bool_t *cont ){ pjsip_transaction *tsx = send_state->token; struct tsx_lock_data lck; lock_tsx(tsx, &lck); if (sent > 0) { /* Successfully sent! */ pj_assert(send_state->cur_transport != NULL); if (tsx->transport != send_state->cur_transport) { /* Update transport. */ if (tsx->transport) { pjsip_transport_dec_ref(tsx->transport); tsx->transport = NULL; } tsx->transport = send_state->cur_transport; pjsip_transport_add_ref(tsx->transport); /* Update remote address. */ tsx->addr_len = send_state->addr.entry[send_state->cur_addr].addr_len; pj_memcpy(&tsx->addr, &send_state->addr.entry[send_state->cur_addr].addr, tsx->addr_len); /* Update is_reliable flag. */ tsx->is_reliable = PJSIP_TRANSPORT_IS_RELIABLE(tsx->transport); } /* Clear pending transport flag. */ tsx->transport_flag &= ~(TSX_HAS_PENDING_TRANSPORT); /* Mark that we have resolved the addresses. */ tsx->transport_flag |= TSX_HAS_RESOLVED_SERVER; /* Pending destroy? */ if (tsx->transport_flag & TSX_HAS_PENDING_DESTROY) { tsx_set_state( tsx, PJSIP_TSX_STATE_DESTROYED, PJSIP_EVENT_UNKNOWN, NULL ); unlock_tsx(tsx, &lck); return; } /* Need to transmit a message? */ if (tsx->transport_flag & TSX_HAS_PENDING_SEND) { tsx->transport_flag &= ~(TSX_HAS_PENDING_SEND); tsx_send_msg(tsx, tsx->last_tx); } /* Need to reschedule retransmission? */ if (tsx->transport_flag & TSX_HAS_PENDING_RESCHED) { tsx->transport_flag &= ~(TSX_HAS_PENDING_RESCHED); /* Only update when transport turns out to be unreliable. */ if (!tsx->is_reliable) { tsx_resched_retransmission(tsx); } } } else { /* Failed to send! */ pj_assert(sent != 0); /* If transaction is using the same transport as the failed one, * release the transport. */ if (send_state->cur_transport==tsx->transport && tsx->transport != NULL) { pjsip_transport_dec_ref(tsx->transport); tsx->transport = NULL; } if (!*cont) { char errmsg[PJ_ERR_MSG_SIZE]; pj_str_t err; tsx->transport_err = -sent; err =pj_strerror(-sent, errmsg, sizeof(errmsg)); PJ_LOG(2,(tsx->obj_name, "Failed to send %s! err=%d (%s)", pjsip_tx_data_get_info(send_state->tdata), -sent, errmsg)); /* Clear pending transport flag. */ tsx->transport_flag &= ~(TSX_HAS_PENDING_TRANSPORT); /* Mark that we have resolved the addresses. */ tsx->transport_flag |= TSX_HAS_RESOLVED_SERVER; /* Terminate transaction, if it's not already terminated. */ tsx_set_status_code(tsx, PJSIP_SC_TSX_TRANSPORT_ERROR, &err); if (tsx->state != PJSIP_TSX_STATE_TERMINATED && tsx->state != PJSIP_TSX_STATE_DESTROYED) { tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, PJSIP_EVENT_TRANSPORT_ERROR, send_state->tdata); } } else { char errmsg[PJ_ERR_MSG_SIZE]; PJ_LOG(2,(tsx->obj_name, "Temporary failure in sending %s, " "will try next server. Err=%d (%s)", pjsip_tx_data_get_info(send_state->tdata), -sent, pj_strerror(-sent, errmsg, sizeof(errmsg)).ptr)); } } unlock_tsx(tsx, &lck);}/* Transport callback. */static void transport_callback(void *token, pjsip_tx_data *tdata, pj_ssize_t sent){ if (sent < 0) { pjsip_transaction *tsx = token; struct tsx_lock_data lck; char errmsg[PJ_ERR_MSG_SIZE]; pj_str_t err; tsx->transport_err = -sent; err = pj_strerror(-sent, errmsg, sizeof(errmsg)); PJ_LOG(2,(tsx->obj_name, "Transport failed to send %s! Err=%d (%s)", pjsip_tx_data_get_info(tdata), -sent, errmsg)); lock_tsx(tsx, &lck); /* Dereference transport. */ pjsip_transport_dec_ref(tsx->transport); tsx->transport = NULL; /* Terminate transaction. */ tsx_set_status_code(tsx, PJSIP_SC_TSX_TRANSPORT_ERROR, &err); tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, PJSIP_EVENT_TRANSPORT_ERROR, tdata ); unlock_tsx(tsx, &lck); }}/* * Send message to the transport. */static pj_status_t tsx_send_msg( pjsip_transaction *tsx, pjsip_tx_data *tdata){ pj_status_t status = PJ_SUCCESS; PJ_ASSERT_RETURN(tsx && tdata, PJ_EINVAL); /* Send later if transport is still pending. */ if (tsx->transport_flag & TSX_HAS_PENDING_TRANSPORT) { tsx->transport_flag |= TSX_HAS_PENDING_SEND; return PJ_SUCCESS; } /* If we have the transport, send the message using that transport. * Otherwise perform full transport resolution. */ if (tsx->transport) { status = pjsip_transport_send( tsx->transport, tdata, &tsx->addr, tsx->addr_len, tsx, &transport_callback); if (status == PJ_EPENDING) status = PJ_SUCCESS; if (status != PJ_SUCCESS) { char errmsg[PJ_ERR_MSG_SIZE]; PJ_LOG(2,(tsx->obj_name, "Error sending %s: Err=%d (%s)", pjsip_tx_data_get_info(tdata), status, pj_strerror(status, errmsg, sizeof(errmsg)).ptr)); /* On error, release transport to force using full transport * resolution procedure. */ if (tsx->transport) { pjsip_transport_dec_ref(tsx->transport); tsx->transport = NULL; } tsx->addr_len = 0; tsx->res_addr.transport = NULL; tsx->res_addr.addr_len = 0; } else { return PJ_SUCCESS; } } /* We are here because we don't have transport, or we failed to send * the message using existing transport. If we haven't resolved the * server before, then begin the long process of resolving the server * and send the message with possibly new server. */ pj_assert(status != PJ_SUCCESS || tsx->transport == NULL); /* If we have resolved the server, we treat the error as permanent error. * Terminate transaction with transport error failure. */ if (tsx->transport_flag & TSX_HAS_RESOLVED_SERVER) { char errmsg[PJ_ERR_MSG_SIZE]; pj_str_t err; if (status == PJ_SUCCESS) { pj_assert(!"Unexpected status!"); status = PJ_EUNKNOWN; } /* We have resolved the server!. * Treat this as permanent transport error. */ err = pj_strerror(status, errmsg, sizeof(errmsg)); PJ_LOG(2,(tsx->obj_name, "Transport error, terminating transaction. " "Err=%d (%s)", status, errmsg)); tsx_set_status_code(tsx, PJSIP_SC_TSX_TRANSPORT_ERROR, &err); tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, PJSIP_EVENT_TRANSPORT_ERROR, NULL ); return status; } /* Must add reference counter because the send request functions * decrement the reference counter. */ pjsip_tx_data_add_ref(tdata); /* Begin resolving destination etc to send the message. */ if (tdata->msg->type == PJSIP_REQUEST_MSG) { tsx->transport_flag |= TSX_HAS_PENDING_TRANSPORT; status = pjsip_endpt_send_request_stateless(tsx->endpt, tdata, tsx, &send_msg_callback); if (status == PJ_EPENDING) status = PJ_SUCCESS; if (status != PJ_SUCCESS) pjsip_tx_data_dec_ref(tdata); /* Check if transaction is terminated. */ if (status==PJ_SUCCESS && tsx->state == PJSIP_TSX_STATE_TERMINATED) status = tsx->transport_err; } else { tsx->transport_flag |= TSX_HAS_PENDING_TRANSPORT; status = pjsip_endpt_send_response( tsx->endpt, &tsx->res_addr, tdata, tsx, &send_msg_callback); if (status == PJ_EPENDING) status = PJ_SUCCESS; if (status != PJ_SUCCESS) pjsip_tx_data_dec_ref(tdata); /* Check if transaction is terminated. */ if (status==PJ_SUCCESS && tsx->state == PJSIP_TSX_STATE_TERMINATED) status = tsx->transport_err; } return status;}/* * Retransmit last message sent. */static void tsx_resched_retransmission( pjsip_transaction *tsx ){ pj_time_val timeout; int msec_time; pj_assert((tsx->transport_flag & TSX_HAS_PENDING_TRANSPORT) == 0); if (tsx->role==PJSIP_ROLE_UAC && tsx->status_code >= 100) msec_time = PJSIP_T2_TIMEOUT; else msec_time = (1 << (tsx->retransmit_count)) * PJSIP_T1_TIMEOUT; if (tsx->role == PJSIP_ROLE_UAC) { pj_assert(tsx->status_code < 200); /* Retransmission for non-INVITE transaction caps-off at T2 */ if (msec_time>PJSIP_T2_TIMEOUT && tsx->method.id!=PJSIP_INVITE_METHOD) 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -