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

📄 evsub.c

📁 基于sip协议的网络电话源码
💻 C
📖 第 1 页 / 共 4 页
字号:
    PJ_ASSERT_RETURN(st_code/100 == 2, PJ_EINVALIDOP);    /* Subscription MUST have been attached to the transaction.     * Initial subscription request will be attached on evsub_create_uas(),     * while subsequent requests will be attached in tsx_state()     */    tsx = pjsip_rdata_get_tsx(rdata);    PJ_ASSERT_RETURN(tsx->mod_data[mod_evsub.mod.id] != NULL,		     PJ_EINVALIDOP);    /* Lock dialog */    pjsip_dlg_inc_lock(sub->dlg);    /* Create response: */    status = pjsip_dlg_create_response( sub->dlg, rdata, st_code, NULL, 					&tdata);    if (status != PJ_SUCCESS)	goto on_return;    /* Add expires header: */    pjsip_msg_add_hdr( tdata->msg,		       pjsip_hdr_shallow_clone(tdata->pool, sub->expires));    /* Add additional header, if any. */    if (hdr_list) {	const pjsip_hdr *hdr = hdr_list->next;	while (hdr != hdr_list) {	    pjsip_msg_add_hdr( tdata->msg,			       pjsip_hdr_clone(tdata->pool, hdr));	    hdr = hdr->next;	}    }    /* Send the response: */    status = pjsip_dlg_send_response( sub->dlg, tsx, tdata );    if (status != PJ_SUCCESS)	goto on_return;on_return:    pjsip_dlg_dec_lock(sub->dlg);    return status;}/* * Create Subscription-State header based on current server subscription * state. */static pjsip_sub_state_hdr* sub_state_create( pj_pool_t *pool,					      pjsip_evsub *sub,					      pjsip_evsub_state state,					      const pj_str_t *state_str,					      const pj_str_t *reason ){    pjsip_sub_state_hdr *sub_state;    pj_time_val now, delay;    /* Get the remaining time before refresh is required */    pj_gettimeofday(&now);    delay = sub->refresh_time;    PJ_TIME_VAL_SUB(delay, now);    /* Create the Subscription-State header */    sub_state = pjsip_sub_state_hdr_create(pool);    /* Fill up the header */    switch (state) {    case PJSIP_EVSUB_STATE_NULL:    case PJSIP_EVSUB_STATE_SENT:    case PJSIP_EVSUB_STATE_ACCEPTED:	pj_assert(!"Invalid state!");	/* Treat as pending */    case PJSIP_EVSUB_STATE_PENDING:	sub_state->sub_state = STR_PENDING;	sub_state->expires_param = delay.sec;	break;    case PJSIP_EVSUB_STATE_ACTIVE:	sub_state->sub_state = STR_ACTIVE;	sub_state->expires_param = delay.sec;	break;    case PJSIP_EVSUB_STATE_TERMINATED:	sub_state->sub_state = STR_TERMINATED;	if (reason != NULL)	    pj_strdup(pool, &sub_state->reason_param, reason);	break;    case PJSIP_EVSUB_STATE_UNKNOWN:	pj_assert(state_str != NULL);	pj_strdup(pool, &sub_state->sub_state, state_str);	break;    }        return sub_state;}/* * Create and send NOTIFY request. */PJ_DEF(pj_status_t) pjsip_evsub_notify( pjsip_evsub *sub,					pjsip_evsub_state state,					const pj_str_t *state_str,					const pj_str_t *reason,					pjsip_tx_data **p_tdata){    pjsip_tx_data *tdata;    pjsip_sub_state_hdr *sub_state;    pj_status_t status;    /* Check arguments. */    PJ_ASSERT_RETURN(sub!=NULL && p_tdata!=NULL, PJ_EINVAL);    /* Lock dialog. */    pjsip_dlg_inc_lock(sub->dlg);    /* Create NOTIFY request */    status = pjsip_dlg_create_request( sub->dlg, &pjsip_notify_method, -1, 				       &tdata);    if (status != PJ_SUCCESS)	goto on_return;    /* Add Event header */    pjsip_msg_add_hdr(tdata->msg,		      pjsip_hdr_shallow_clone(tdata->pool, sub->event));    /* Add Subscription-State header */    sub_state = sub_state_create(tdata->pool, sub, state, state_str,				 reason);    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)sub_state);    /* Add Allow-Events header */    pjsip_msg_add_hdr(tdata->msg,		      pjsip_hdr_shallow_clone(tdata->pool, mod_evsub.allow_events_hdr));    /* Add Authentication headers. */    pjsip_auth_clt_init_req( &sub->dlg->auth_sess, tdata );        /* Save destination state. */    sub->dst_state = state;    if (state_str)	pj_strdup(sub->pool, &sub->dst_state_str, state_str);    else	sub->dst_state_str.slen = 0;    *p_tdata = tdata;on_return:    /* Unlock dialog */    pjsip_dlg_dec_lock(sub->dlg);    return status;}/* * Create NOTIFY to reflect current status. */PJ_DEF(pj_status_t) pjsip_evsub_current_notify( pjsip_evsub *sub,						pjsip_tx_data **p_tdata ){    return pjsip_evsub_notify( sub, sub->state, &sub->state_str, 			       NULL, p_tdata );}/* * Send request. */PJ_DEF(pj_status_t) pjsip_evsub_send_request( pjsip_evsub *sub,					      pjsip_tx_data *tdata){    pj_status_t status;    /* Must be request message. */    PJ_ASSERT_RETURN(tdata->msg->type == PJSIP_REQUEST_MSG,		     PJSIP_ENOTREQUESTMSG);    /* Lock */    pjsip_dlg_inc_lock(sub->dlg);    /* Send the request. */    status = pjsip_dlg_send_request(sub->dlg, tdata, -1, NULL);    if (status != PJ_SUCCESS)	goto on_return;    /* Special case for NOTIFY:     * The new state was set in pjsip_evsub_notify(), but we apply the     * new state now, when the request was actually sent.     */    if (pjsip_method_cmp(&tdata->msg->line.req.method, 			 &pjsip_notify_method)==0)     {	PJ_ASSERT_ON_FAIL(  sub->dst_state!=PJSIP_EVSUB_STATE_NULL,			    {goto on_return;});	set_state(sub, sub->dst_state, 		  (sub->dst_state_str.slen ? &sub->dst_state_str : NULL), 		  NULL);	sub->dst_state = PJSIP_EVSUB_STATE_NULL;	sub->dst_state_str.slen = 0;    }on_return:    pjsip_dlg_dec_lock(sub->dlg);    return status;}/* * Attach subscription session to newly created transaction, if appropriate. */static pjsip_evsub *on_new_transaction( pjsip_transaction *tsx,				        pjsip_event *event){    /*     * Newly created transaction will not have subscription session     * attached to it. Find the subscription session from the dialog,     * by matching the Event header.     */    pjsip_dialog *dlg;    pjsip_event_hdr *event_hdr;    pjsip_msg *msg;    struct dlgsub *dlgsub_head, *dlgsub;    pjsip_evsub *sub;        dlg = pjsip_tsx_get_dlg(tsx);    if (!dlg) {	pj_assert(!"Transaction should have a dialog instance!");	return NULL;    }    switch (event->body.tsx_state.type) {    case PJSIP_EVENT_RX_MSG:	msg = event->body.tsx_state.src.rdata->msg_info.msg;	break;    case PJSIP_EVENT_TX_MSG:	msg = event->body.tsx_state.src.tdata->msg;	break;    default:	if (tsx->role == PJSIP_ROLE_UAC)	    msg = tsx->last_tx->msg;	else	    msg = NULL;	break;    }        if (!msg) {	//Note:	// this transaction can be other transaction in the dialog.	// The assertion below probably only valid for dialog that	// only has one event subscription usage.	//pj_assert(!"First transaction event is not TX or RX!");	return NULL;    }    event_hdr = pjsip_msg_find_hdr_by_name(msg, &STR_EVENT, NULL);    if (!event_hdr) {	/* Not subscription related message */	return NULL;    }    /* Find the subscription in the dialog, based on the content     * of Event header:      */    dlgsub_head = dlg->mod_data[mod_evsub.mod.id];    if (dlgsub_head == NULL) {	dlgsub_head = pj_pool_alloc(dlg->pool, sizeof(struct dlgsub));	pj_list_init(dlgsub_head);	dlg->mod_data[mod_evsub.mod.id] = dlgsub_head;    }    dlgsub = dlgsub_head->next;    while (dlgsub != dlgsub_head) {	if (pj_stricmp(&dlgsub->sub->event->event_type, 		       &event_hdr->event_type)==0)	{	    /* Event type matched. 	     * Check if event ID matched too.	     */	    if (pj_strcmp(&dlgsub->sub->event->id_param, 			  &event_hdr->id_param)==0)	    {				break;	    }	    /*	     * Otherwise if it is an UAC subscription, AND	     * PJSIP_EVSUB_NO_EVENT_ID flag is set, AND	     * the session's event id is NULL, AND	     * the incoming request is NOTIFY with event ID, then	     * we consider it as a match, and update the	     * session's event id.	     */	    else if (dlgsub->sub->role == PJSIP_ROLE_UAC &&		     (dlgsub->sub->option & PJSIP_EVSUB_NO_EVENT_ID)!=0 &&		     dlgsub->sub->event->id_param.slen==0 &&		     !pjsip_method_cmp(&tsx->method, &pjsip_notify_method))	    {		/* Update session's event id. */		pj_strdup(dlgsub->sub->pool, 			  &dlgsub->sub->event->id_param,			  &event_hdr->id_param);		break;	    }	}		dlgsub = dlgsub->next;    }    if (dlgsub == dlgsub_head) {	/* This could be incoming request to create new subscription */	PJ_LOG(4,(THIS_FILE, 		  "Subscription not found for %.*s, event=%.*s;id=%.*s",		  (int)tsx->method.name.slen,		  tsx->method.name.ptr,		  (int)event_hdr->event_type.slen,		  event_hdr->event_type.ptr,		  (int)event_hdr->id_param.slen,		  event_hdr->id_param.ptr));	/* If this is an incoming NOTIFY, reject with 481 */	if (tsx->state == PJSIP_TSX_STATE_TRYING &&	    pjsip_method_cmp(&tsx->method, &pjsip_notify_method)==0)	{	    pj_str_t reason = pj_str("Subscription Does Not Exist");	    pjsip_tx_data *tdata;	    pj_status_t status;	    status = pjsip_dlg_create_response(dlg, 					       event->body.tsx_state.src.rdata, 					       481, &reason, 					       &tdata);	    if (status == PJ_SUCCESS) {		status = pjsip_dlg_send_response(dlg, tsx, tdata);	    }	}	return NULL;    }    /* Found! */    sub = dlgsub->sub;    /* Attach session to the transaction */    tsx->mod_data[mod_evsub.mod.id] = sub;    sub->pending_tsx++;    /* Special case for outgoing/UAC SUBSCRIBE/REFER transaction.      * We can only have one pending UAC SUBSCRIBE/REFER, so if another      * transaction is started while previous one still alive, terminate     * the older one.     *     * Sample scenario:     *	- subscribe sent to destination that doesn't exist, transaction     *	  is still retransmitting request, then unsubscribe is sent.     */    if (tsx->role == PJSIP_ROLE_UAC &&	tsx->state == PJSIP_TSX_STATE_CALLING &&	(pjsip_method_cmp(&tsx->method, &sub->method) == 0  ||	 pjsip_method_cmp(&tsx->method, &pjsip_subscribe_method) == 0))    {	if (sub->pending_sub && 	    sub->pending_sub->state < PJSIP_TSX_STATE_COMPLETED) 	{	    PJ_LOG(4,(sub->obj_name, 		      "Cancelling pending subscription request"));	    /* By convention, we use 490 (Request Updated) status code.	     * When transaction handler (below) see this status code, it	     * will ignore the transaction.	     */	    pjsip_tsx_terminate(sub->pending_sub, PJSIP_SC_REQUEST_UPDATED);	}	sub->pending_sub = tsx;    }    return sub;}/* * Create response, adding custome headers and msg body. */static pj_status_t create_response( pjsip_evsub *sub,				    pjsip_rx_data *rdata,				    int st_code,				    const pj_str_t *st_text,				    const pjsip_hdr *res_hdr,				    const pjsip_msg_body *body,				    pjsip_tx_data **p_tdata){    pjsip_tx_data *tdata;    pjsip_hdr *hdr;    pj_status_t status;    status = pjsip_dlg_create_response(sub->dlg, rdata,				       st_code, st_text, &tdata);    if (status != PJ_SUCCESS)	return status;    *p_tdata = tdata;    /* Add response headers. */    hdr = res_hdr->next;    while (hdr != res_hdr) {	pjsip_msg_add_hdr( tdata->msg, 			   pjsip_hdr_clone(tdata->pool, hdr));	hdr = hdr->next;    }    /* Add msg body, if any */    if (body) {	tdata->msg->body = pjsip_msg_body_clone(tdata->pool, body);	if (tdata->msg->body == NULL) {	    PJ_LOG(4,(THIS_FILE, "Error: unable to clone msg body"));	    /* Ignore */	    return PJ_SUCCESS;	}    }    return PJ_SUCCESS;}/* * Get subscription state from the value of Subscription-State header. */static void get_hdr_state( pjsip_sub_state_hdr *sub_state,			   pjsip_evsub_state *state,			   pj_str_t **state_str ){    if (pj_stricmp(&sub_state->sub_state, &STR_TERMINATED)==0) {	*state = PJSIP_EVSUB_STATE_TERMINATED;	*state_str = NULL;    } else if (pj_stricmp(&sub_state->sub_state, &STR_ACTIVE)==0) {	*state = PJSIP_EVSUB_STATE_ACTIVE;	*state_str = NULL;    } else if (pj_stricmp(&sub_state->sub_state, &STR_PENDING)==0) {	*state = PJSIP_EVSUB_STATE_PENDING;	*state_str = NULL;    } else {	*state = PJSIP_EVSUB_STATE_UNKNOWN;	*state_str = &sub_state->sub_state;    }}/* * Transaction event processing by UAC, after subscription is sent. */static void on_tsx_state_uac( pjsip_evsub *sub, pjsip_transaction *tsx,			      pjsip_event *event ){    if (pjsip_method_cmp(&tsx->method, &sub->method)==0 || 	pjsip_method_cmp(&tsx->method, &pjsip_subscribe_method)==0)     {	/* Received response to outgoing request that establishes/refresh	 * subscription. 	 */	/* First time initial request is sent. */	if (sub->state == PJSIP_EVSUB_STATE_NULL &&	    tsx->state == PJSIP_TSX_STATE_CALLING)	{	    set_state(sub, PJSIP_EVSUB_STATE_SENT, NULL, event);

⌨️ 快捷键说明

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