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

📄 sip_inv.c

📁 一个开源SIP协议栈
💻 C
📖 第 1 页 / 共 5 页
字号:

	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);

		inv_check_sdp_in_incoming_msg(inv, tsx, 
					      e->body.tsx_state.src.rdata);

		/* Send ACK */
		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:
	    break;
	}

    } 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 INCOMING is after we received the request, but before
 * responses with tag are sent.
 */
static void inv_on_state_incoming( 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 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 (t

⌨️ 快捷键说明

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