⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sip_transaction.c

📁 基于sip协议的网络电话源码
💻 C
📖 第 1 页 / 共 5 页
字号:
}/* * 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 + -