sip_inv.c

来自「基于sip协议的网络电话源码」· C语言 代码 · 共 2,560 行 · 第 1/5 页

C
2,560
字号
	/*	 * 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 (tsx->state == PJSIP_TSX_STATE_TERMINATED &&	    tsx->status_code/100 == 2) 	{	    /* Re-INVITE was accepted. */	    /* Process SDP */	    inv_check_sdp_in_incoming_msg(inv, tsx, 					  e->body.tsx_state.src.rdata);	    /* Send ACK */	    inv_send_ack(inv, e->body.tsx_state.src.rdata);	} else if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&		   (tsx->status_code==401 || tsx->status_code==407))	{	    pjsip_tx_data *tdata;	    pj_status_t status;	    /* Handle authentication challenge. */	    status = pjsip_auth_clt_reinit_req( &dlg->auth_sess,						e->body.tsx_state.src.rdata,						tsx->last_tx,						&tdata);	    if (status != PJ_SUCCESS)		return;	    /* Send re-INVITE */	    status = pjsip_inv_send_msg( inv, tdata);	} else if (tsx->status_code==PJSIP_SC_CALL_TSX_DOES_NOT_EXIST ||		   tsx->status_code==PJSIP_SC_REQUEST_TIMEOUT ||		   tsx->status_code >= 700)	{	    /*	     * Handle responses that terminates dialog.	     */	    inv_set_cause(inv, tsx->status_code, &tsx->status_text);	    inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);	}    }}/* * After session has been terminated, but before dialog is destroyed * (because dialog has other usages, or because dialog is waiting for * the last transaction to terminate). */static void inv_on_state_disconnected( 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->role == PJSIP_ROLE_UAS &&	tsx->status_code < 200 &&	e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)     {	pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;	/*	 * Respond BYE with 200/OK	 */	if (tsx->method.id == PJSIP_BYE_METHOD) {	    inv_respond_incoming_bye( inv, tsx, rdata, e );	} else if (tsx->method.id == PJSIP_CANCEL_METHOD) {	    /*	     * Respond CANCEL with 200/OK too.	     */	    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;	}    }}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?