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

📄 evsub.c

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

	/* Only interested in final response */
	if (tsx->state != PJSIP_TSX_STATE_COMPLETED &&
	    tsx->state != PJSIP_TSX_STATE_TERMINATED)
	{
	    return;
	}

	/* Clear pending subscription */
	if (tsx == sub->pending_sub)
	    sub->pending_sub = NULL;

	/* Handle authentication. */
	if (tsx->status_code==401 || tsx->status_code==407) {
	    pjsip_tx_data *tdata;
	    pj_status_t status;

	    if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
		/* Previously failed transaction has terminated */
		return;
	    }

	    status = pjsip_auth_clt_reinit_req(&sub->dlg->auth_sess,
					       event->body.tsx_state.src.rdata,
					       tsx->last_tx, &tdata);
	    if (status == PJ_SUCCESS) 
		status = pjsip_dlg_send_request(sub->dlg, tdata, -1, NULL);
	    
	    if (status != PJ_SUCCESS) {
		/* Authentication failed! */
		set_state(sub, PJSIP_EVSUB_STATE_TERMINATED,
			       NULL,
			       event);
		return;
	    }

	    return;
	}

	if (tsx->status_code/100 == 2) {

	    /* Successfull SUBSCRIBE request! 
	     * This could be:
	     *	- response to initial SUBSCRIBE request
	     *	- response to subsequent refresh
	     *	- response to unsubscription
	     */

	    if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
		/* Ignore; this transaction has been processed before */
		return;
	    }

	    /* Update UAC refresh time, if response contains Expires header,
	     * only when we're not unsubscribing. 
	     */
	    if (sub->expires->ivalue != 0) {
		pjsip_msg *msg;
		pjsip_expires_hdr *expires;

		msg = event->body.tsx_state.src.rdata->msg_info.msg;
		expires = pjsip_msg_find_hdr(msg, PJSIP_H_EXPIRES, NULL);
		if (expires) {
		    sub->expires->ivalue = expires->ivalue;
		}
	    }

	    /* Update time */
	    update_expires(sub, sub->expires->ivalue);

	    /* Start UAC refresh timer, only when we're not unsubscribing */
	    if (sub->expires->ivalue != 0) {
		unsigned timeout = (sub->expires->ivalue > TIME_UAC_REFRESH) ?
		    sub->expires->ivalue - TIME_UAC_REFRESH : sub->expires->ivalue;

		PJ_LOG(5,(sub->obj_name, "Will refresh in %d seconds", 
			  timeout));
		set_timer(sub, TIMER_TYPE_UAC_REFRESH, timeout);

	    } else {
		/* Otherwise set timer to terminate client subscription when
		 * NOTIFY to end subscription is not received.
		 */
		set_timer(sub, TIMER_TYPE_UAC_TERMINATE, TIME_UAC_TERMINATE);
	    }
	    
	    /* Set state, if necessary */
	    pj_assert(sub->state != PJSIP_EVSUB_STATE_NULL);
	    if (sub->state == PJSIP_EVSUB_STATE_SENT) {
		set_state(sub, PJSIP_EVSUB_STATE_ACCEPTED, NULL, event);
	    }

	} else {

	    /* Failed SUBSCRIBE request! 
	     *
	     * The RFC 3265 says that if outgoing SUBSCRIBE fails with status
	     * other than 481, the subscription is still considered valid for
	     * the duration of the last Expires.
	     *
	     * Since we send refresh about 5 seconds (TIME_UAC_REFRESH) before 
	     * expiration, theoritically the expiration is still valid for the 
	     * next 5 seconds even when we receive non-481 failed response.
	     *
	     * Ah, what the heck!
	     *
	     * Just terminate now!
	     *
	     */

	    if (sub->state == PJSIP_EVSUB_STATE_TERMINATED) {
		/* Ignore, has been handled before */
		return;
	    }

	    /* Ignore 490 (Request Updated) status. 
	     * This happens when application sends SUBSCRIBE/REFER while 
	     * another one is still in progress.
	     */
	    if (tsx->status_code == PJSIP_SC_REQUEST_UPDATED) {
		return;
	    }

	    /* Kill any timer. */
	    set_timer(sub, TIMER_TYPE_NONE, 0);

	    /* Set state to TERMINATED */
	    set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, 
		      NULL, event);

	}

    } else if (pjsip_method_cmp(&tsx->method, &pjsip_notify_method) == 0) {

	/* Incoming NOTIFY. 
	 * This can be the result of:
	 *  - Initial subscription response
	 *  - UAS updating the resource info.
	 *  - Unsubscription response.
	 */
	int st_code = 200;
	pj_str_t *st_text = NULL;
	pjsip_hdr res_hdr;
	pjsip_msg_body *body = NULL;

	pjsip_rx_data *rdata;
	pjsip_msg *msg;
	pjsip_sub_state_hdr *sub_state;

	pjsip_evsub_state new_state;
	pj_str_t *new_state_str;

	pjsip_tx_data *tdata;
	pj_status_t status;
	int next_refresh;

	/* Only want to handle initial NOTIFY receive event. */
	if (tsx->state != PJSIP_TSX_STATE_TRYING)
	    return;


	rdata = event->body.tsx_state.src.rdata;
	msg = rdata->msg_info.msg;

	pj_list_init(&res_hdr);

	/* Get subscription state header. */
	sub_state = pjsip_msg_find_hdr_by_name(msg, &STR_SUB_STATE, NULL);
	if (sub_state == NULL) {

	    pjsip_warning_hdr *warn_hdr;
	    pj_str_t warn_text = { "Missing Subscription-State header", 33};

	    /* Bad request! Add warning header. */
	    st_code = PJSIP_SC_BAD_REQUEST;
	    warn_hdr = pjsip_warning_hdr_create(rdata->tp_info.pool, 399,
					        pjsip_endpt_name(sub->endpt),
						&warn_text);
	    pj_list_push_back(&res_hdr, warn_hdr);
	}

	/* Call application registered callback to handle incoming NOTIFY,
	 * if any.
	 */
	if (st_code==200 && sub->user.on_rx_notify && sub->call_cb) {
	    (*sub->user.on_rx_notify)(sub, rdata, &st_code, &st_text, 
				      &res_hdr, &body);

	    /* Application MUST specify final response! */
	    PJ_ASSERT_ON_FAIL(st_code >= 200, {st_code=200; });

	    /* Must be a valid status code */
	    PJ_ASSERT_ON_FAIL(st_code <= 699, {st_code=500; });
	}


	/* If non-2xx should be returned, then send the response.
	 * No need to update server subscription state.
	 */
	if (st_code >= 300) {
	    status = create_response(sub, rdata, st_code, st_text, &res_hdr,
				     body, &tdata);
	    if (status == PJ_SUCCESS) {
		status = pjsip_dlg_send_response(sub->dlg, tsx, tdata);
	    }

	    /* Start timer to terminate subscription, just in case server
	     * is not able to generate NOTIFY to our response.
	     */
	    if (status == PJ_SUCCESS) {
		unsigned timeout = TIME_UAC_WAIT_NOTIFY;
		set_timer(sub, TIMER_TYPE_UAC_WAIT_NOTIFY, timeout);
	    } else {
		set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, NULL);
	    }

	    return;
	}

	/* Update expiration from the value of expires param in
	 * Subscription-State header, but ONLY when subscription state 
	 * is "active" or "pending", AND the header contains expires param.
	 */
	if (sub->expires->ivalue != 0 &&
	    sub_state->expires_param >= 0 &&
	    (pj_stricmp(&sub_state->sub_state, &STR_ACTIVE)==0 ||
	     pj_stricmp(&sub_state->sub_state, &STR_PENDING)==0))
	{
	    next_refresh = sub_state->expires_param;

	} else {
	    next_refresh = sub->expires->ivalue;
	}

	/* Update time */
	update_expires(sub, next_refresh);

	/* Start UAC refresh timer, only when we're not unsubscribing */
	if (sub->expires->ivalue != 0) {
	    unsigned timeout = (next_refresh > TIME_UAC_REFRESH) ?
		next_refresh - TIME_UAC_REFRESH : next_refresh;

	    PJ_LOG(5,(sub->obj_name, "Will refresh in %d seconds", timeout));
	    set_timer(sub, TIMER_TYPE_UAC_REFRESH, timeout);
	}
	
	/* Find out the state */
	get_hdr_state(sub_state, &new_state, &new_state_str);

	/* Send response. */
	status = create_response(sub, rdata, st_code, st_text, &res_hdr,
				 body, &tdata);
	if (status == PJ_SUCCESS)
	    status = pjsip_dlg_send_response(sub->dlg, tsx, tdata);

	/* Set the state */
	if (status == PJ_SUCCESS) {
	    set_state(sub, new_state, new_state_str, event);
	} else {
	    set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, event);
	}


    } else {

	/*
	 * Unexpected method!
	 */
	PJ_LOG(4,(sub->obj_name, "Unexpected transaction method %.*s",
		 (int)tsx->method.name.slen, tsx->method.name.ptr));
    }
}


/*
 * Transaction event processing by UAS, after subscription is accepted.
 */
static void on_tsx_state_uas( 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) 
    {
	
	/*
	 * Incoming request (e.g. SUBSCRIBE or REFER) to refresh subsciption.
	 *
	 */
	pjsip_rx_data *rdata;
	pjsip_event_hdr *event_hdr;
	pjsip_expires_hdr *expires;
	pjsip_msg *msg;
	pjsip_tx_data *tdata;
	int st_code = 200;
	pj_str_t *st_text = NULL;
	pjsip_hdr res_hdr;
	pjsip_msg_body *body = NULL;
	pjsip_evsub_state old_state;
	pj_str_t old_state_str;
	pj_status_t status;


	/* Only wants to handle the first event when the request is 
	 * received.
	 */
	if (tsx->state != PJSIP_TSX_STATE_TRYING)
	    return;

	rdata = event->body.tsx_state.src.rdata;
	msg = rdata->msg_info.msg;

	/* Set expiration time based on client request (in Expires header),
	 * or package default expiration time.
	 */
	event_hdr = pjsip_msg_find_hdr_by_name(msg, &STR_EVENT, NULL);
	expires = pjsip_msg_find_hdr(msg, PJSIP_H_EXPIRES, NULL);
	if (event_hdr && expires) {
	    struct evpkg *evpkg;

	    evpkg = find_pkg(&event_hdr->event_type);
	    if (evpkg) {
		if (expires->ivalue < (pj_int32_t)evpkg->pkg_expires)
		    sub->expires->ivalue = expires->ivalue;
		else
		    sub->expires->ivalue = evpkg->pkg_expires;
	    }
	}
	
	/* Update time (before calling on_rx_refresh, since application
	 * will send NOTIFY.
	 */
	update_expires(sub, sub->expires->ivalue);


	/* Save old state.
	 * If application respond with non-2xx, revert to old state.
	 */
	old_state = sub->state;
	old_state_str = sub->state_str;

	if (sub->expires->ivalue == 0) {
	    sub->state = PJSIP_EVSUB_STATE_TERMINATED;
	    sub->state_str = evsub_state_names[sub->state];
	} else  if (sub->state == PJSIP_EVSUB_STATE_NULL) {
	    sub->state = PJSIP_EVSUB_STATE_ACCEPTED;
	    sub->state_str = evsub_state_names[sub->state];
	}

	/* Call application's on_rx_refresh, just in case it wants to send
	 * response other than 200 (OK)
	 */
	pj_list_init(&res_hdr);

	if (sub->user.on_rx_refresh && sub->call_cb) {
	    (*sub->user.on_rx_refresh)(sub, rdata, &st_code, &st_text, 
				       &res_hdr, &body);
	}

	/* Application MUST specify final response! */
	PJ_ASSERT_ON_FAIL(st_code >= 200, {st_code=200; });

	/* Must be a valid status code */
	PJ_ASSERT_ON_FAIL(st_code <= 699, {st_code=500; });


	/* Create and send response */
	status = create_response(sub, rdata, st_code, st_text, &res_hdr,
				 body, &tdata);
	if (status == PJ_SUCCESS) {
	    /* Add expires header: */
	    pjsip_msg_add_hdr( tdata->msg,
			       pjsip_hdr_shallow_clone(tdata->pool, 
						       sub->expires));

	    /* Send */
	    status = pjsip_dlg_send_response(sub->dlg, tsx, tdata);
	}

	/* Update state or revert state */
	if (st_code/100==2) {
	    
	    if (sub->expires->ivalue == 0) {
		set_state(sub, sub->state, NULL, event);
	    } else  if (sub->state == PJSIP_EVSUB_STATE_NULL) {
		set_state(sub, sub->state, NULL, event);
	    }

	    /* Set UAS timeout timer, when state is not terminated. */
	    if (sub->state != PJSIP_EVSUB_STATE_TERMINATED) {
		PJ_LOG(5,(sub->obj_name, "UAS timeout in %d seconds",
			  sub->expires->ivalue));
		set_timer(sub, TIMER_TYPE_UAS_TIMEOUT, 
			  sub->expires->ivalue);
	    }

	}  else {
	    sub->state = old_state;
	    sub->state_str = old_state_str;
	}


    } else if (pjsip_method_cmp(&tsx->method, &pjsip_notify_method)==0) {

	/* Handle authentication */ 
	if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
	    (tsx->status_code==401 || tsx->status_code==407))
	{
	    pjsip_rx_data *rdata = event->body.tsx_state.src.rdata;
	    pjsip_tx_data *tdata;
	    pj_status_t status;

	    status = pjsip_auth_clt_reinit_req( &sub->dlg->auth_sess, rdata, 
						tsx->last_tx, &tdata);
	    if (status == PJ_SUCCESS)
		status = pjsip_dlg_send_request( sub->dlg, tdata, -1, NULL );

	    if (status != PJ_SUCCESS) {
		/* Can't authenticate. Terminate session (?) */
		set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, NULL);
		return;
	    }

	}
	/*
	 * Terminate event usage if we receive 481, 408, and 7 class
	 * responses.
	 */
	if (sub->state != PJSIP_EVSUB_STATE_TERMINATED &&
	    (tsx->status_code==481 || tsx->status_code==408 ||
	     tsx->status_code/100 == 7))
	{
	    set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, event);
	    return;
	}

    } else {

	/*
	 * Unexpected method!
	 */
	PJ_LOG(4,(sub->obj_name, "Unexpected transaction method %.*s",
		 (int)tsx->method.name.slen, tsx->method.name.ptr));
    
    }
}


/*
 * Notification when transaction state has changed!
 */
static void mod_evsub_on_tsx_state(pjsip_transaction *tsx, pjsip_event *event)
{
    pjsip_evsub *sub = pjsip_tsx_get_evsub(tsx);

    if (sub == NULL) {
	sub = on_new_transaction(tsx, event);
	if (sub == NULL)
	    return;
    }


    /* Call on_tsx_state callback, if any. */
    if (sub->user.on_tsx_state && sub->call_cb)
	(*sub->user.on_tsx_state)(sub, tsx, event);


    /* Process the event: */

    if (sub->role == PJSIP_ROLE_UAC) {
	on_tsx_state_uac(sub, tsx, event);
    } else {
	on_tsx_state_uas(sub, tsx, event);
    }


    /* Check transaction TERMINATE event */
    if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {

	--sub->pending_tsx;

	if (sub->state == PJSIP_EVSUB_STATE_TERMINATED &&
	    sub->pending_tsx == 0)
	{
	    evsub_destroy(sub);
	}

    }
}


⌨️ 快捷键说明

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