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

📄 sip_inv.c

📁 基于sip协议的网络电话源码
💻 C
📖 第 1 页 / 共 5 页
字号:
    pjsip_require_hdr *req_hdr;    int code = 200;    unsigned rem_option = 0;    pj_status_t status = PJ_SUCCESS;    pjsip_hdr res_hdr_list;    /* Init return arguments. */    if (p_tdata) *p_tdata = NULL;    /* Verify arguments. */    PJ_ASSERT_RETURN(rdata != NULL && options != NULL, PJ_EINVAL);    /* Normalize options */    if (*options & PJSIP_INV_REQUIRE_100REL)	*options |= PJSIP_INV_SUPPORT_100REL;    if (*options & PJSIP_INV_REQUIRE_TIMER)	*options |= PJSIP_INV_SUPPORT_TIMER;    /* Get the message in rdata */    msg = rdata->msg_info.msg;    /* Must be INVITE request. */    PJ_ASSERT_RETURN(msg->type == PJSIP_REQUEST_MSG &&		     msg->line.req.method.id == PJSIP_INVITE_METHOD,		     PJ_EINVAL);    /* If tdata is specified, then either dlg or endpt must be specified */    PJ_ASSERT_RETURN((!p_tdata) || (endpt || dlg), PJ_EINVAL);    /* Get the endpoint */    endpt = endpt ? endpt : dlg->endpt;    /* Init response header list */    pj_list_init(&res_hdr_list);    /* Check the request body, see if it'inv something that we support     * (i.e. SDP).      */    if (msg->body) {	pjsip_msg_body *body = msg->body;	pj_str_t str_application = {"application", 11};	pj_str_t str_sdp = { "sdp", 3 };	pjmedia_sdp_session *sdp;	/* Check content type. */	if (pj_stricmp(&body->content_type.type, &str_application) != 0 ||	    pj_stricmp(&body->content_type.subtype, &str_sdp) != 0)	{	    /* Not "application/sdp" */	    code = PJSIP_SC_UNSUPPORTED_MEDIA_TYPE;	    status = PJSIP_ERRNO_FROM_SIP_STATUS(code);	    if (p_tdata) {		/* Add Accept header to response */		pjsip_accept_hdr *acc;		acc = pjsip_accept_hdr_create(rdata->tp_info.pool);		PJ_ASSERT_RETURN(acc, PJ_ENOMEM);		acc->values[acc->count++] = pj_str("application/sdp");		pj_list_push_back(&res_hdr_list, acc);	    }	    goto on_return;	}	/* Parse and validate SDP */	status = pjmedia_sdp_parse(rdata->tp_info.pool, body->data, body->len,				   &sdp);	if (status == PJ_SUCCESS)	    status = pjmedia_sdp_validate(sdp);	if (status != PJ_SUCCESS) {	    /* Unparseable or invalid SDP */	    code = PJSIP_SC_BAD_REQUEST;	    if (p_tdata) {		/* Add Warning header. */		pjsip_warning_hdr *w;		w = pjsip_warning_hdr_create_from_status(rdata->tp_info.pool,							 pjsip_endpt_name(endpt),							 status);		PJ_ASSERT_RETURN(w, PJ_ENOMEM);		pj_list_push_back(&res_hdr_list, w);	    }	    goto on_return;	}	/* Negotiate with local SDP */	if (l_sdp) {	    pjmedia_sdp_neg *neg;	    /* Local SDP must be valid! */	    PJ_ASSERT_RETURN((status=pjmedia_sdp_validate(l_sdp))==PJ_SUCCESS,			     status);	    /* Create SDP negotiator */	    status = pjmedia_sdp_neg_create_w_remote_offer(			    rdata->tp_info.pool, l_sdp, sdp, &neg);	    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);	    /* Negotiate SDP */	    status = pjmedia_sdp_neg_negotiate(rdata->tp_info.pool, neg, 0);	    if (status != PJ_SUCCESS) {		/* Incompatible media */		code = PJSIP_SC_NOT_ACCEPTABLE_HERE;		if (p_tdata) {		    pjsip_accept_hdr *acc;		    pjsip_warning_hdr *w;		    /* Add Warning header. */		    w = pjsip_warning_hdr_create_from_status(					    rdata->tp_info.pool, 					    pjsip_endpt_name(endpt), status);		    PJ_ASSERT_RETURN(w, PJ_ENOMEM);		    pj_list_push_back(&res_hdr_list, w);		    /* Add Accept header to response */		    acc = pjsip_accept_hdr_create(rdata->tp_info.pool);		    PJ_ASSERT_RETURN(acc, PJ_ENOMEM);		    acc->values[acc->count++] = pj_str("application/sdp");		    pj_list_push_back(&res_hdr_list, acc);		}		goto on_return;	    }	}    }    /* Check supported methods, see if peer supports UPDATE.     * We just assume that peer supports standard INVITE, ACK, CANCEL, and BYE     * implicitly by sending this INVITE.     */    allow = pjsip_msg_find_hdr(msg, PJSIP_H_ALLOW, NULL);    if (allow) {	unsigned i;	const pj_str_t STR_UPDATE = { "UPDATE", 6 };	for (i=0; i<allow->count; ++i) {	    if (pj_stricmp(&allow->values[i], &STR_UPDATE)==0)		break;	}	if (i != allow->count) {	    /* UPDATE is present in Allow */	    rem_option |= PJSIP_INV_SUPPORT_UPDATE;	}    }    /* Check Supported header */    sup_hdr = pjsip_msg_find_hdr(msg, PJSIP_H_SUPPORTED, NULL);    if (sup_hdr) {	unsigned i;	pj_str_t STR_100REL = { "100rel", 6};	pj_str_t STR_TIMER = { "timer", 5 };	for (i=0; i<sup_hdr->count; ++i) {	    if (pj_stricmp(&sup_hdr->values[i], &STR_100REL)==0)		rem_option |= PJSIP_INV_SUPPORT_100REL;	    else if (pj_stricmp(&sup_hdr->values[i], &STR_TIMER)==0)		rem_option |= PJSIP_INV_SUPPORT_TIMER;	}    }    /* Check Require header */    req_hdr = pjsip_msg_find_hdr(msg, PJSIP_H_REQUIRE, NULL);    if (req_hdr) {	unsigned i;	const pj_str_t STR_100REL = { "100rel", 6};	const pj_str_t STR_TIMER = { "timer", 5 };	const pj_str_t STR_REPLACES = { "replaces", 8 };	unsigned unsupp_cnt = 0;	pj_str_t unsupp_tags[PJSIP_GENERIC_ARRAY_MAX_COUNT];		for (i=0; i<req_hdr->count; ++i) {	    if ((*options & PJSIP_INV_SUPPORT_100REL) && 		pj_stricmp(&req_hdr->values[i], &STR_100REL)==0)	    {		rem_option |= PJSIP_INV_REQUIRE_100REL;	    } else if ((*options && PJSIP_INV_SUPPORT_TIMER) &&		       pj_stricmp(&req_hdr->values[i], &STR_TIMER)==0)	    {		rem_option |= PJSIP_INV_REQUIRE_TIMER;	    } else if (pj_stricmp(&req_hdr->values[i], &STR_REPLACES)==0) {		pj_bool_t supp;				supp = pjsip_endpt_has_capability(endpt, PJSIP_H_SUPPORTED, 						  NULL, &STR_REPLACES);		if (!supp)		    unsupp_tags[unsupp_cnt++] = req_hdr->values[i];	    } else {		/* Unknown/unsupported extension tag!  */		unsupp_tags[unsupp_cnt++] = req_hdr->values[i];	    }	}	/* Check if there are required tags that we don't support */	if (unsupp_cnt) {	    code = PJSIP_SC_BAD_EXTENSION;	    status = PJSIP_ERRNO_FROM_SIP_STATUS(code);	    if (p_tdata) {		pjsip_unsupported_hdr *unsupp_hdr;		const pjsip_hdr *h;		/* Add Unsupported header. */		unsupp_hdr = pjsip_unsupported_hdr_create(rdata->tp_info.pool);		PJ_ASSERT_RETURN(unsupp_hdr != NULL, PJ_ENOMEM);		unsupp_hdr->count = unsupp_cnt;		for (i=0; i<unsupp_cnt; ++i)		    unsupp_hdr->values[i] = unsupp_tags[i];		pj_list_push_back(&res_hdr_list, unsupp_hdr);		/* Add Supported header. */		h = pjsip_endpt_get_capability(endpt, PJSIP_H_SUPPORTED, 					       NULL);		pj_assert(h);		if (h) {		    sup_hdr = pjsip_hdr_clone(rdata->tp_info.pool, h);		    pj_list_push_back(&res_hdr_list, sup_hdr);		}	    }	    goto on_return;	}    }    /* Check if there are local requirements that are not supported     * by peer.     */    if ( ((*options & PJSIP_INV_REQUIRE_100REL)!=0 && 	  (rem_option & PJSIP_INV_SUPPORT_100REL)==0) ||	 ((*options & PJSIP_INV_REQUIRE_TIMER)!=0 &&	  (rem_option & PJSIP_INV_SUPPORT_TIMER)==0))    {	code = PJSIP_SC_EXTENSION_REQUIRED;	status = PJSIP_ERRNO_FROM_SIP_STATUS(code);	if (p_tdata) {	    const pjsip_hdr *h;	    /* Add Require header. */	    req_hdr = pjsip_require_hdr_create(rdata->tp_info.pool);	    PJ_ASSERT_RETURN(req_hdr != NULL, PJ_ENOMEM);	    if (*options & PJSIP_INV_REQUIRE_100REL)		req_hdr->values[req_hdr->count++] = pj_str("100rel");	    if (*options & PJSIP_INV_REQUIRE_TIMER)		req_hdr->values[req_hdr->count++] = pj_str("timer");	    pj_list_push_back(&res_hdr_list, req_hdr);	    /* Add Supported header. */	    h = pjsip_endpt_get_capability(endpt, PJSIP_H_SUPPORTED, 					   NULL);	    pj_assert(h);	    if (h) {		sup_hdr = pjsip_hdr_clone(rdata->tp_info.pool, h);		pj_list_push_back(&res_hdr_list, sup_hdr);	    }	}	goto on_return;    }on_return:    /* Create response if necessary */    if (code != 200 && p_tdata) {	pjsip_tx_data *tdata;	const pjsip_hdr *h;	if (dlg) {	    status = pjsip_dlg_create_response(dlg, rdata, code, NULL, 					       &tdata);	} else {	    status = pjsip_endpt_create_response(endpt, rdata, code, NULL, 						 &tdata);	}	if (status != PJ_SUCCESS)	    return status;	/* Add response headers. */	h = res_hdr_list.next;	while (h != &res_hdr_list) {	    pjsip_hdr *cloned;	    cloned = pjsip_hdr_clone(tdata->pool, h);	    PJ_ASSERT_RETURN(cloned, PJ_ENOMEM);	    pjsip_msg_add_hdr(tdata->msg, cloned);	    h = h->next;	}	*p_tdata = tdata;	/* Can not return PJ_SUCCESS when response message is produced.	 * Ref: PROTOS test ~#2490	 */	if (status == PJ_SUCCESS)	    status = PJSIP_ERRNO_FROM_SIP_STATUS(code);    }    return status;}/* * Create UAS invite session. */PJ_DEF(pj_status_t) pjsip_inv_create_uas( pjsip_dialog *dlg,					  pjsip_rx_data *rdata,					  const pjmedia_sdp_session *local_sdp,					  unsigned options,					  pjsip_inv_session **p_inv){    pjsip_inv_session *inv;    struct tsx_inv_data *tsx_inv_data;    pjsip_msg *msg;    pjmedia_sdp_session *rem_sdp = NULL;    pj_status_t status;    /* Verify arguments. */    PJ_ASSERT_RETURN(dlg && rdata && p_inv, PJ_EINVAL);    /* Dialog MUST have been initialised. */    PJ_ASSERT_RETURN(pjsip_rdata_get_tsx(rdata) != NULL, PJ_EINVALIDOP);    msg = rdata->msg_info.msg;    /* rdata MUST contain INVITE request */    PJ_ASSERT_RETURN(msg->type == PJSIP_REQUEST_MSG &&		     msg->line.req.method.id == PJSIP_INVITE_METHOD,		     PJ_EINVALIDOP);    /* Lock dialog */    pjsip_dlg_inc_lock(dlg);    /* Normalize options */    if (options & PJSIP_INV_REQUIRE_100REL)	options |= PJSIP_INV_SUPPORT_100REL;    if (options & PJSIP_INV_REQUIRE_TIMER)	options |= PJSIP_INV_SUPPORT_TIMER;    /* Create the session */    inv = pj_pool_zalloc(dlg->pool, sizeof(pjsip_inv_session));    pj_assert(inv != NULL);    inv->pool = dlg->pool;    inv->role = PJSIP_ROLE_UAS;    inv->state = PJSIP_INV_STATE_NULL;    inv->dlg = dlg;    inv->options = options;    inv->notify = PJ_TRUE;    inv->cause = 0;    /* Object name will use the same dialog pointer. */    pj_ansi_snprintf(inv->obj_name, PJ_MAX_OBJ_NAME, "inv%p", dlg);    /* Parse SDP in message body, if present. */    if (msg->body) {	pjsip_msg_body *body = msg->body;	/* Parse and validate SDP */	status = pjmedia_sdp_parse(inv->pool, body->data, body->len,				   &rem_sdp);	if (status == PJ_SUCCESS)	    status = pjmedia_sdp_validate(rem_sdp);	if (status != PJ_SUCCESS) {	    pjsip_dlg_dec_lock(dlg);	    return status;	}    }    /* Create negotiator. */    if (rem_sdp) {	status = pjmedia_sdp_neg_create_w_remote_offer(inv->pool, local_sdp,						       rem_sdp, &inv->neg);						    } else if (local_sdp) {	status = pjmedia_sdp_neg_create_w_local_offer(inv->pool, local_sdp,						      &inv->neg);    } else {	status = PJ_SUCCESS;    }    if (status != PJ_SUCCESS) {	pjsip_dlg_dec_lock(dlg);	return status;    }    /* Register invite as dialog usage. */    status = pjsip_dlg_add_usage(dlg, &mod_inv.mod, inv);    if (status != PJ_SUCCESS) {	pjsip_dlg_dec_lock(dlg);	return status;    }    /* Increment session in the dialog. */    pjsip_dlg_inc_session(dlg, &mod_inv.mod);    /* Save the invite transaction. */    inv->invite_tsx = pjsip_rdata_get_tsx(rdata);    /* Attach our data to the transaction. */    tsx_inv_data = pj_pool_zalloc(inv->invite_tsx->pool, 				  sizeof(struct tsx_inv_data));    tsx_inv_data->inv = inv;    inv->invite_tsx->mod_data[mod_inv.mod.id] = tsx_inv_data;    /* Done */    pjsip_dlg_dec_lock(dlg);    *p_inv = inv;    PJ_LOG(5,(inv->obj_name, "UAS invite session created for dialog %s",	      dlg->obj_name));    return PJ_SUCCESS;}/* * Forcefully terminate the session. */PJ_DEF(pj_status_t) pjsip_inv_terminate( pjsip_inv_session *inv,				         int st_code,					 pj_bool_t notify){    PJ_ASSERT_RETURN(inv, PJ_EINVAL);    /* Lock dialog. */    pjsip_dlg_inc_lock(inv->dlg);    /* Set callback notify flag. */    inv->notify = notify;    /* If there's pending transaction, terminate the transaction.      * This may subsequently set the INVITE session state to     * disconnected.     */    if (inv->invite_tsx && 	inv->invite_tsx->state <= PJSIP_TSX_STATE_COMPLETED)    {	pjsip_tsx_terminate(inv->invite_tsx, st_code);    }    /* Set cause. */    inv_set_cause(inv, st_code, NULL);    /* Forcefully terminate the session if state is not DISCONNECTED */    if (inv->state != PJSIP_INV_STATE_DISCONNECTED) {	inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, NULL);    }    /* Done.     * The dec_lock() below will actually destroys the dialog if it     * has no other session.     */    pjsip_dlg_dec_lock(inv->dlg);    return PJ_SUCCESS;}static void *clone_sdp(pj_pool_t *pool, const void *data, unsigned len){    PJ_UNUSED_ARG(len);    return pjmedia_sdp_session_clone(pool, data);}static int print_sdp(pjsip_msg_body *body, char *buf, pj_size_t len){    return pjmedia_sdp_print(body->data, buf, len);}PJ_DEF(pj_status_t) pjsip_create_sdp_body( pj_pool_t *pool,					   pjmedia_sdp_session *sdp,					   pjsip_msg_body **p_body){    const pj_str_t STR_APPLICATION = { "application", 11};    const pj_str_t STR_SDP = { "sdp", 3 };    pjsip_msg_body *body;    body = pj_pool_zalloc(pool, sizeof(pjsip_msg_body));    PJ_ASSERT_RETURN(body != NULL, PJ_ENOMEM);    body->content_type.type = STR_APPLICATION;    body->content_type.subtype = STR_SDP;    body->data = sdp;    body->len = 0;    body->clone_data = &clone_sdp;

⌨️ 快捷键说明

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