sip_inv.c

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

C
2,560
字号
    case PJSIP_INV_STATE_CONNECTING:    case PJSIP_INV_STATE_CONFIRMED:	/* For established dialog, send BYE */	status = pjsip_dlg_create_request(inv->dlg, &pjsip_bye_method, -1, 					  &tdata);	break;    case PJSIP_INV_STATE_DISCONNECTED:	/* No need to do anything. */	return PJSIP_ESESSIONTERMINATED;    default:	pj_assert("!Invalid operation!");	return PJ_EINVALIDOP;    }    if (status != PJ_SUCCESS)	return status;    /* Done */    *p_tdata = tdata;    return PJ_SUCCESS;}/* * Create re-INVITE. */PJ_DEF(pj_status_t) pjsip_inv_reinvite( pjsip_inv_session *inv,					const pj_str_t *new_contact,					const pjmedia_sdp_session *new_offer,					pjsip_tx_data **p_tdata ){    pj_status_t status;    pjsip_contact_hdr *contact_hdr = NULL;    /* Check arguments. */    PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);    /* Must NOT have a pending INVITE transaction */    PJ_ASSERT_RETURN(inv->invite_tsx==NULL, PJ_EINVALIDOP);    pjsip_dlg_inc_lock(inv->dlg);    if (new_contact) {	pj_str_t tmp;	const pj_str_t STR_CONTACT = { "Contact", 7 };	pj_strdup_with_null(inv->dlg->pool, &tmp, new_contact);	contact_hdr = pjsip_parse_hdr(inv->dlg->pool, &STR_CONTACT, 				      tmp.ptr, tmp.slen, NULL);	if (!contact_hdr) {	    status = PJSIP_EINVALIDURI;	    goto on_return;	}    }    if (new_offer) {	if (!inv->neg) {	    status = pjmedia_sdp_neg_create_w_local_offer(inv->pool, new_offer,							  &inv->neg);	    if (status != PJ_SUCCESS)		goto on_return;	} else switch (pjmedia_sdp_neg_get_state(inv->neg)) {	    case PJMEDIA_SDP_NEG_STATE_NULL:		pj_assert(!"Unexpected SDP neg state NULL");		status = PJ_EBUG;		goto on_return;	    case PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER:		PJ_LOG(4,(inv->obj_name, 			  "pjsip_inv_reinvite: already have an offer, new "			  "offer is ignored"));		break;	    case PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER:		status = pjmedia_sdp_neg_set_local_answer(inv->pool, inv->neg,							  new_offer);		if (status != PJ_SUCCESS)		    goto on_return;		break;	    case PJMEDIA_SDP_NEG_STATE_WAIT_NEGO:		PJ_LOG(4,(inv->obj_name, 			  "pjsip_inv_reinvite: SDP in WAIT_NEGO state, new "			  "offer is ignored"));		break;	    case PJMEDIA_SDP_NEG_STATE_DONE:		status = pjmedia_sdp_neg_modify_local_offer(inv->pool,inv->neg,							    new_offer);		if (status != PJ_SUCCESS)		    goto on_return;		break;	}    }    if (contact_hdr)	inv->dlg->local.contact = contact_hdr;    status = pjsip_inv_invite(inv, p_tdata);on_return:    pjsip_dlg_dec_lock(inv->dlg);    return status;}/* * Create UPDATE. */PJ_DEF(pj_status_t) pjsip_inv_update (	pjsip_inv_session *inv,					const pj_str_t *new_contact,					const pjmedia_sdp_session *new_offer,					pjsip_tx_data **p_tdata ){    PJ_UNUSED_ARG(inv);    PJ_UNUSED_ARG(new_contact);    PJ_UNUSED_ARG(new_offer);    PJ_UNUSED_ARG(p_tdata);    PJ_TODO(CREATE_UPDATE_REQUEST);    return PJ_ENOTSUP;}/* * Send a request or response message. */PJ_DEF(pj_status_t) pjsip_inv_send_msg( pjsip_inv_session *inv,					pjsip_tx_data *tdata){    pj_status_t status;    /* Verify arguments. */    PJ_ASSERT_RETURN(inv && tdata, PJ_EINVAL);    PJ_LOG(5,(inv->obj_name, "Sending %s", 	      pjsip_tx_data_get_info(tdata)));    if (tdata->msg->type == PJSIP_REQUEST_MSG) {	struct tsx_inv_data *tsx_inv_data;	pjsip_dlg_inc_lock(inv->dlg);	tsx_inv_data = pj_pool_zalloc(inv->pool, sizeof(struct tsx_inv_data));	tsx_inv_data->inv = inv;	pjsip_dlg_dec_lock(inv->dlg);	status = pjsip_dlg_send_request(inv->dlg, tdata, mod_inv.mod.id, 					tsx_inv_data);	if (status != PJ_SUCCESS)	    return status;    } else {	pjsip_cseq_hdr *cseq;	/* Can only do this to send response to original INVITE	 * request.	 */	PJ_ASSERT_RETURN((cseq=pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL))!=NULL			  && (cseq->cseq == inv->invite_tsx->cseq),			 PJ_EINVALIDOP);	status = pjsip_dlg_send_response(inv->dlg, inv->invite_tsx, tdata);	if (status != PJ_SUCCESS)	    return status;    }    /* Done (?) */    return PJ_SUCCESS;}/* * Respond to incoming CANCEL request. */static void inv_respond_incoming_cancel(pjsip_inv_session *inv,					pjsip_transaction *cancel_tsx,					pjsip_rx_data *rdata){    pjsip_tx_data *tdata;    pjsip_transaction *invite_tsx;    pj_str_t key;    pj_status_t status;    /* See if we have matching INVITE server transaction: */    pjsip_tsx_create_key(rdata->tp_info.pool, &key, PJSIP_ROLE_UAS,			 &pjsip_invite_method, rdata);    invite_tsx = pjsip_tsx_layer_find_tsx(&key, PJ_TRUE);    if (invite_tsx == NULL) {	/* Invite transaction not found! 	 * Respond CANCEL with 491 (RFC 3261 Section 9.2 page 42)	 */	status = pjsip_dlg_create_response( inv->dlg, rdata, 200, NULL, 					    &tdata);    } else {	/* Always answer CANCEL will 200 (OK) regardless of	 * the state of the INVITE transaction.	 */	status = pjsip_dlg_create_response( inv->dlg, rdata, 200, NULL, 					    &tdata);    }    /* See if we have created the response successfully. */    if (status != PJ_SUCCESS) return;    /* Send the CANCEL response */    status = pjsip_dlg_send_response(inv->dlg, cancel_tsx, tdata);    if (status != PJ_SUCCESS) return;    /* See if we need to terminate the UAS INVITE transaction     * with 487 (Request Terminated) response.      */    if (invite_tsx && invite_tsx->status_code < 200) {	pj_assert(invite_tsx->last_tx != NULL);	tdata = invite_tsx->last_tx;	status = pjsip_dlg_modify_response(inv->dlg, tdata, 487, NULL);	if (status == PJ_SUCCESS)	    pjsip_dlg_send_response(inv->dlg, invite_tsx, tdata);    }    if (invite_tsx)	pj_mutex_unlock(invite_tsx->mutex);}/* * Respond to incoming BYE request. */static void inv_respond_incoming_bye( pjsip_inv_session *inv,				      pjsip_transaction *bye_tsx,				      pjsip_rx_data *rdata,				      pjsip_event *e ){    pj_status_t status;    pjsip_tx_data *tdata;    /* Respond BYE with 200: */    status = pjsip_dlg_create_response(inv->dlg, rdata, 200, NULL, &tdata);    if (status != PJ_SUCCESS) return;    status = pjsip_dlg_send_response(inv->dlg, bye_tsx, tdata);    if (status != PJ_SUCCESS) return;    /* Terminate session: */    if (inv->state != PJSIP_INV_STATE_DISCONNECTED) {	inv_set_cause(inv, PJSIP_SC_OK, NULL);	inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);    }}/* * Respond to BYE request. */static void inv_handle_bye_response( pjsip_inv_session *inv,				     pjsip_transaction *tsx,				     pjsip_rx_data *rdata,				     pjsip_event *e ){    pj_status_t status;        if (e->body.tsx_state.type != PJSIP_EVENT_RX_MSG) {	inv_set_cause(inv, PJSIP_SC_OK, NULL);	inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);	return;    }    /* Handle 401/407 challenge. */    if (tsx->status_code == 401 || tsx->status_code == 407) {	pjsip_tx_data *tdata;		status = pjsip_auth_clt_reinit_req( &inv->dlg->auth_sess, 					    rdata,					    tsx->last_tx,					    &tdata);		if (status != PJ_SUCCESS) {	    	    /* Does not have proper credentials. 	     * End the session anyway.	     */	    inv_set_cause(inv, PJSIP_SC_OK, NULL);	    inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);	    	} else {	    /* Re-send BYE. */	    status = pjsip_inv_send_msg(inv, tdata);	}    } else {	/* End the session. */	inv_set_cause(inv, PJSIP_SC_OK, NULL);	inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);    }}/* * State NULL is before anything is sent/received. */static void inv_on_state_null( 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_INVITE_METHOD) {	/* Keep the initial INVITE transaction. */	if (inv->invite_tsx == NULL)	    inv->invite_tsx = tsx;	if (dlg->role == PJSIP_ROLE_UAC) {	    switch (tsx->state) {	    case PJSIP_TSX_STATE_CALLING:		inv_set_state(inv, PJSIP_INV_STATE_CALLING, e);		break;	    default:		inv_on_state_calling(inv, e);		break;	    }	} else {	    switch (tsx->state) {	    case PJSIP_TSX_STATE_TRYING:		inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e);		break;	    case PJSIP_TSX_STATE_PROCEEDING:		inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e);		if (tsx->status_code > 100)		    inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);		break;	    default:		inv_on_state_incoming(inv, e);		break;	    }	}    } else {	pj_assert(!"Unexpected transaction type");    }}/* * State CALLING is after sending initial INVITE request but before * any response (with tag) is received. */static void inv_on_state_calling( pjsip_inv_session *inv, pjsip_event *e){    pjsip_transaction *tsx = e->body.tsx_state.tsx;    pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);    pj_status_t status;    PJ_ASSERT_ON_FAIL(tsx && dlg, return);        if (tsx == inv->invite_tsx) {	switch (tsx->state) {	case PJSIP_TSX_STATE_CALLING:	    inv_set_state(inv, PJSIP_INV_STATE_CALLING, e);	    break;	case PJSIP_TSX_STATE_PROCEEDING:	    if (dlg->remote.info->tag.slen) {		inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);		inv_check_sdp_in_incoming_msg(inv, tsx, 					      e->body.tsx_state.src.rdata);	    } else {		/* Ignore 100 (Trying) response, as it doesn't change		 * session state. It only ceases retransmissions.		 */	    }	    break;	case PJSIP_TSX_STATE_COMPLETED:	    if (tsx->status_code/100 == 2) {				/* This should not happen.		 * When transaction receives 2xx, it should be terminated		 */		pj_assert(0);		inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);    		inv_check_sdp_in_incoming_msg(inv, tsx, 					      e->body.tsx_state.src.rdata);	    } else if (tsx->status_code==401 || tsx->status_code==407) {		/* Handle authentication failure:		 * Resend the request with Authorization header.		 */		pjsip_tx_data *tdata;		status = pjsip_auth_clt_reinit_req(&inv->dlg->auth_sess, 						   e->body.tsx_state.src.rdata,						   tsx->last_tx,						   &tdata);		if (status != PJ_SUCCESS) {		    /* Does not have proper credentials. 		     * End the session.		     */		    inv_set_cause(inv, tsx->status_code, &tsx->status_text);		    inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);		} else {		    /* Restart session. */		    inv->state = PJSIP_INV_STATE_NULL;		    inv->invite_tsx = NULL;		    /* Send the request. */		    status = pjsip_inv_send_msg(inv, tdata);		}	    } 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:	    /* 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) {

⌨️ 快捷键说明

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