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

📄 evsub.c

📁 基于sip协议的网络电话源码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * Destroy session. */static void evsub_destroy( pjsip_evsub *sub ){    struct dlgsub *dlgsub_head, *dlgsub;    PJ_LOG(4,(sub->obj_name, "Subscription destroyed"));    /* Kill timer */    set_timer(sub, TIMER_TYPE_NONE, 0);    /* Remote this session from dialog's list of subscription */    dlgsub_head = sub->dlg->mod_data[mod_evsub.mod.id];    dlgsub = dlgsub_head->next;    while (dlgsub != dlgsub_head) {		if (dlgsub->sub == sub) {	    pj_list_erase(dlgsub);	    break;	}	dlgsub = dlgsub->next;    }    /* Decrement dialog's session */    pjsip_dlg_dec_session(sub->dlg, &mod_evsub.mod);}/* * Set subscription session state. */static void set_state( pjsip_evsub *sub, pjsip_evsub_state state,		       const pj_str_t *state_str, pjsip_event *event){    pjsip_evsub_state prev_state = sub->state;    pj_str_t old_state_str = sub->state_str;    sub->state = state;    if (state_str && state_str->slen)	pj_strdup_with_null(sub->pool, &sub->state_str, state_str);    else	sub->state_str = evsub_state_names[state];    PJ_LOG(4,(sub->obj_name, 	      "Subscription state changed %.*s --> %.*s",	      (int)old_state_str.slen,	      old_state_str.ptr,	      (int)sub->state_str.slen,	      sub->state_str.ptr));    if (sub->user.on_evsub_state && sub->call_cb)	(*sub->user.on_evsub_state)(sub, event);    if (state == PJSIP_EVSUB_STATE_TERMINATED &&	prev_state != PJSIP_EVSUB_STATE_TERMINATED)     {	if (sub->pending_tsx == 0) {	    evsub_destroy(sub);	}    }}/* * Timer callback. */static void on_timer( pj_timer_heap_t *timer_heap,		      struct pj_timer_entry *entry){    pjsip_evsub *sub;    int timer_id;    PJ_UNUSED_ARG(timer_heap);    sub = entry->user_data;    pjsip_dlg_inc_lock(sub->dlg);    timer_id = entry->id;    entry->id = TIMER_TYPE_NONE;    switch (timer_id) {    case TIMER_TYPE_UAC_REFRESH:	/* Time for UAC to refresh subscription */	if (sub->user.on_client_refresh && sub->call_cb) {	    (*sub->user.on_client_refresh)(sub);	} else {	    pjsip_tx_data *tdata;	    pj_status_t status;	    PJ_LOG(5,(sub->obj_name, "Refreshing subscription."));	    status = pjsip_evsub_initiate(sub, NULL, 					  sub->expires->ivalue,					  &tdata);	    if (status == PJ_SUCCESS)		pjsip_evsub_send_request(sub, tdata);	}	break;    case TIMER_TYPE_UAS_TIMEOUT:	/* Refresh from UAC has not been received */	if (sub->user.on_server_timeout && sub->call_cb) {	    (*sub->user.on_server_timeout)(sub);	} else {	    pjsip_tx_data *tdata;	    pj_status_t status;	    PJ_LOG(5,(sub->obj_name, "Timeout waiting for refresh. "				     "Sending NOTIFY to terminate."));	    status = pjsip_evsub_notify( sub, PJSIP_EVSUB_STATE_TERMINATED, 					 NULL, &STR_TIMEOUT, &tdata);	    if (status == PJ_SUCCESS)		pjsip_evsub_send_request(sub, tdata);	}	break;    case TIMER_TYPE_UAC_TERMINATE:	{	    PJ_LOG(5,(sub->obj_name, "Timeout waiting for final NOTIFY. "				     "Terminating.."));	    set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, NULL);	}	break;    case TIMER_TYPE_UAC_WAIT_NOTIFY:	{	    pjsip_tx_data *tdata;	    pj_status_t status;	    PJ_LOG(5,(sub->obj_name, 		     "Timeout waiting for subsequent NOTIFY (we did "		     "send non-2xx response for previous NOTIFY). "		     "Unsubscribing.."));	    status = pjsip_evsub_initiate( sub, NULL, 0, &tdata);	    if (status == PJ_SUCCESS)		pjsip_evsub_send_request(sub, tdata);	}	break;    default:	pj_assert(!"Invalid timer id");    }    pjsip_dlg_dec_lock(sub->dlg);}/* * Create subscription session, used for both client and notifier. */static pj_status_t evsub_create( pjsip_dialog *dlg,				 pjsip_role_e role,				 const pjsip_evsub_user *user_cb,				 const pj_str_t *event,				 unsigned option,				 pjsip_evsub **p_evsub ){    pjsip_evsub *sub;    struct evpkg *pkg;    struct dlgsub *dlgsub_head, *dlgsub;    pj_status_t status;    /* Make sure there's package register for the event name: */    pkg = find_pkg(event);    if (pkg == NULL)	return PJSIP_SIMPLE_ENOPKG;    /* Must lock dialog before using pool etc. */    pjsip_dlg_inc_lock(dlg);    /* Init attributes: */    sub = pj_pool_zalloc(dlg->pool, sizeof(struct pjsip_evsub));    sub->pool = dlg->pool;    sub->endpt = dlg->endpt;    sub->dlg = dlg;    sub->pkg = pkg;    sub->role = role;    sub->call_cb = PJ_TRUE;    sub->option = option;    sub->state = PJSIP_EVSUB_STATE_NULL;    sub->state_str = evsub_state_names[sub->state];    sub->expires = pjsip_expires_hdr_create(sub->pool, pkg->pkg_expires);    sub->accept = pjsip_hdr_clone(sub->pool, pkg->pkg_accept);    sub->timer.user_data = sub;    sub->timer.cb = &on_timer;    /* Set name. */    pj_ansi_snprintf(sub->obj_name, PJ_ARRAY_SIZE(sub->obj_name),		     "evsub%p", sub);    /* Copy callback, if any: */    if (user_cb)	pj_memcpy(&sub->user, user_cb, sizeof(pjsip_evsub_user));    /* Create Event header: */    sub->event = pjsip_event_hdr_create(sub->pool);    pj_strdup(sub->pool, &sub->event->event_type, event);    /* Create subcription list: */    dlgsub_head = pj_pool_alloc(sub->pool, sizeof(struct dlgsub));    dlgsub = pj_pool_alloc(sub->pool, sizeof(struct dlgsub));    dlgsub->sub = sub;    pj_list_init(dlgsub_head);    pj_list_push_back(dlgsub_head, dlgsub);    /* Register as dialog usage: */    status = pjsip_dlg_add_usage(dlg, &mod_evsub.mod, dlgsub_head);    if (status != PJ_SUCCESS) {	pjsip_dlg_dec_lock(dlg);	return status;    }    PJ_LOG(5,(sub->obj_name, "%s subscription created, using dialog %s",	      (role==PJSIP_ROLE_UAC ? "UAC" : "UAS"),	      dlg->obj_name));    *p_evsub = sub;    pjsip_dlg_dec_lock(dlg);    return PJ_SUCCESS;}/* * Create client subscription session. */PJ_DEF(pj_status_t) pjsip_evsub_create_uac( pjsip_dialog *dlg,					    const pjsip_evsub_user *user_cb,					    const pj_str_t *event,					    unsigned option,					    pjsip_evsub **p_evsub){    pjsip_evsub *sub;    pj_status_t status;    PJ_ASSERT_RETURN(dlg && event && p_evsub, PJ_EINVAL);    pjsip_dlg_inc_lock(dlg);    status = evsub_create(dlg, PJSIP_UAC_ROLE, user_cb, event, option, &sub);    if (status != PJ_SUCCESS)	goto on_return;    /* Add unique Id to Event header, only when PJSIP_EVSUB_NO_EVENT_ID     * is not specified.     */    if ((option & PJSIP_EVSUB_NO_EVENT_ID) == 0) {	pj_create_unique_string(sub->pool, &sub->event->id_param);    }    /* Increment dlg session. */    pjsip_dlg_inc_session(sub->dlg, &mod_evsub.mod);    /* Done */    *p_evsub = sub;on_return:    pjsip_dlg_dec_lock(dlg);    return status;}/* * Create server subscription session from incoming request. */PJ_DEF(pj_status_t) pjsip_evsub_create_uas( pjsip_dialog *dlg,					    const pjsip_evsub_user *user_cb,					    pjsip_rx_data *rdata,					    unsigned option,					    pjsip_evsub **p_evsub){    pjsip_evsub *sub;    pjsip_transaction *tsx;    pjsip_accept_hdr *accept_hdr;    pjsip_event_hdr *event_hdr;    pjsip_expires_hdr *expires_hdr;    pj_status_t status;    /* Check arguments: */    PJ_ASSERT_RETURN(dlg && rdata && p_evsub, PJ_EINVAL);    /* MUST be request message: */    PJ_ASSERT_RETURN(rdata->msg_info.msg->type == PJSIP_REQUEST_MSG,		     PJSIP_ENOTREQUESTMSG);    /* Transaction MUST have been created (in the dialog) */    tsx = pjsip_rdata_get_tsx(rdata);    PJ_ASSERT_RETURN(tsx != NULL, PJSIP_ENOTSX);    /* No subscription must have been attached to transaction */    PJ_ASSERT_RETURN(tsx->mod_data[mod_evsub.mod.id] == NULL, 		     PJSIP_ETYPEEXISTS);    /* Package MUST implement on_rx_refresh */    PJ_ASSERT_RETURN(user_cb->on_rx_refresh, PJ_EINVALIDOP);    /* Request MUST have "Event" header. We need the Event header to get      * the package name (don't want to add more arguments in the function).     */    event_hdr = (pjsip_event_hdr*) 	pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &STR_EVENT, NULL);    if (event_hdr == NULL) {	return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_BAD_REQUEST);    }    /* Start locking the mutex: */    pjsip_dlg_inc_lock(dlg);    /* Create the session: */    status = evsub_create(dlg, PJSIP_UAS_ROLE, user_cb, 			  &event_hdr->event_type, option, &sub);    if (status != PJ_SUCCESS)	goto on_return;    /* Just duplicate Event header from the request */    sub->event = pjsip_hdr_clone(sub->pool, event_hdr);    /* Set the method: */    pjsip_method_copy(sub->pool, &sub->method, 		      &rdata->msg_info.msg->line.req.method);    /* Update expiration time according to client request: */    expires_hdr = (pjsip_expires_hdr*)	pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL);    if (expires_hdr) {	sub->expires->ivalue = expires_hdr->ivalue;    }    /* Update time. */    update_expires(sub, sub->expires->ivalue);    /* Update Accept header: */    accept_hdr = (pjsip_accept_hdr*)	pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_ACCEPT, NULL);    if (accept_hdr)	sub->accept = pjsip_hdr_clone(sub->pool, accept_hdr);    /* We can start the session: */    pjsip_dlg_inc_session(dlg, &mod_evsub.mod);    sub->pending_tsx++;    tsx->mod_data[mod_evsub.mod.id] = sub;    /* Done. */    *p_evsub = sub;on_return:    pjsip_dlg_dec_lock(dlg);    return status;}/* * Forcefully destroy subscription. */PJ_DEF(pj_status_t) pjsip_evsub_terminate( pjsip_evsub *sub,					   pj_bool_t notify ){    PJ_ASSERT_RETURN(sub, PJ_EINVAL);    pjsip_dlg_inc_lock(sub->dlg);    /* I think it's pretty safe to disable this check.         if (sub->pending_tsx) {	pj_assert(!"Unable to terminate when there's pending tsx");	pjsip_dlg_dec_lock(sub->dlg);	return PJ_EINVALIDOP;    }    */    sub->call_cb = notify;    set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, NULL);    pjsip_dlg_dec_lock(sub->dlg);    return PJ_SUCCESS;}/* * Get subscription state. */PJ_DEF(pjsip_evsub_state) pjsip_evsub_get_state(pjsip_evsub *sub){    return sub->state;}/* * Get state name. */PJ_DEF(const char*) pjsip_evsub_get_state_name(pjsip_evsub *sub){    return sub->state_str.ptr;}/* * Initiate client subscription */PJ_DEF(pj_status_t) pjsip_evsub_initiate( pjsip_evsub *sub,					  const pjsip_method *method,					  pj_int32_t expires,					  pjsip_tx_data **p_tdata){    pjsip_tx_data *tdata;    pj_status_t status;    PJ_ASSERT_RETURN(sub!=NULL && p_tdata!=NULL, PJ_EINVAL);    /* Use SUBSCRIBE if method is not specified */    if (method == NULL)	method = &pjsip_subscribe_method;    pjsip_dlg_inc_lock(sub->dlg);    /* Update method: */    if (sub->state == PJSIP_EVSUB_STATE_NULL)	pjsip_method_copy(sub->pool, &sub->method, method);    status = pjsip_dlg_create_request( sub->dlg, 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));    /* Update and add expires header: */    if (expires >= 0)	sub->expires->ivalue = expires;    pjsip_msg_add_hdr( tdata->msg,		       pjsip_hdr_shallow_clone(tdata->pool, sub->expires));    /* Add Accept header: */    pjsip_msg_add_hdr( tdata->msg,		       pjsip_hdr_shallow_clone(tdata->pool, sub->accept));        /* Add Allow-Events header: */    pjsip_msg_add_hdr( tdata->msg,		       pjsip_hdr_shallow_clone(tdata->pool, 					       mod_evsub.allow_events_hdr));       *p_tdata = tdata;on_return:    pjsip_dlg_dec_lock(sub->dlg);    return status;}/* * Accept incoming subscription request. */PJ_DEF(pj_status_t) pjsip_evsub_accept( pjsip_evsub *sub,					pjsip_rx_data *rdata,				        int st_code,					const pjsip_hdr *hdr_list ){    pjsip_tx_data *tdata;    pjsip_transaction *tsx;    pj_status_t status;    /* Check arguments */    PJ_ASSERT_RETURN(sub && rdata, PJ_EINVAL);    /* Can only be for server subscription: */    PJ_ASSERT_RETURN(sub->role == PJSIP_ROLE_UAS, PJ_EINVALIDOP);    /* Only expect 2xx status code (for now) */

⌨️ 快捷键说明

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