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

📄 evsub.c

📁 基于sip协议的网络电话源码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* $Id: evsub.c 974 2007-02-19 01:13:53Z bennylp $ *//*  * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  */#include <pjsip-simple/evsub.h>#include <pjsip-simple/evsub_msg.h>#include <pjsip-simple/errno.h>#include <pjsip/sip_errno.h>#include <pjsip/sip_module.h>#include <pjsip/sip_endpoint.h>#include <pjsip/sip_dialog.h>#include <pjsip/sip_auth.h>#include <pjsip/sip_transaction.h>#include <pjsip/sip_event.h>#include <pj/assert.h>#include <pj/guid.h>#include <pj/log.h>#include <pj/os.h>#include <pj/pool.h>#include <pj/string.h>#define THIS_FILE	"evsub.c"/* * Global constant *//* Let's define this enum, so that it'll trigger compilation error * when somebody define the same enum in sip_msg.h */enum{    PJSIP_SUBSCRIBE_METHOD = PJSIP_OTHER_METHOD,    PJSIP_NOTIFY_METHOD = PJSIP_OTHER_METHOD};const pjsip_method pjsip_subscribe_method = {    PJSIP_SUBSCRIBE_METHOD,    { "SUBSCRIBE", 9 }};const pjsip_method pjsip_notify_method = {    PJSIP_NOTIFY_METHOD,    { "NOTIFY", 6 }};/* * Static prototypes. */static void	   mod_evsub_on_tsx_state(pjsip_transaction*, pjsip_event*);static pj_status_t mod_evsub_unload(void);/* * State names. */static pj_str_t evsub_state_names[] = {    { "NULL",	    4},    { "SENT",	    4},    { "ACCEPTED",   8},    { "PENDING",    7},    { "ACTIVE",	    6},    { "TERMINATED", 10},    { "UNKNOWN",    7}};/* * Timer constants. *//* Number of seconds to send SUBSCRIBE before the actual expiration */#define TIME_UAC_REFRESH	5/* Time to wait for the final NOTIFY after sending unsubscription */#define TIME_UAC_TERMINATE	5/* If client responds NOTIFY with non-2xx final response (such as 401), * wait for this seconds for further NOTIFY, otherwise client will * unsubscribe */#define TIME_UAC_WAIT_NOTIFY	5/* * Timer id */enum timer_id{    /* No timer. */    TIMER_TYPE_NONE,    /* Time to refresh client subscription.      * The action is to call on_client_refresh() callback.     */    TIMER_TYPE_UAC_REFRESH,    /* UAS timeout after to subscription refresh.      * The action is to call on_server_timeout() callback.     */    TIMER_TYPE_UAS_TIMEOUT,    /* UAC waiting for final NOTIFY after unsubscribing      * The action is to terminate.     */    TIMER_TYPE_UAC_TERMINATE,    /* UAC waiting for further NOTIFY after sending non-2xx response to      * NOTIFY. The action is to unsubscribe.     */    TIMER_TYPE_UAC_WAIT_NOTIFY,    /* Max nb of timer types. */    TIMER_TYPE_MAX};static const char *timer_names[] = {    "None",    "UAC_REFRESH",    "UAS_TIMEOUT"    "UAC_TERMINATE",    "UAC_WAIT_NOTIFY",    "INVALID_TIMER"};/* * Definition of event package. */struct evpkg{    PJ_DECL_LIST_MEMBER(struct evpkg);    pj_str_t		 pkg_name;    pjsip_module	*pkg_mod;    unsigned		 pkg_expires;    pjsip_accept_hdr	*pkg_accept;};/* * Event subscription module (mod-evsub). */static struct mod_evsub{    pjsip_module	     mod;    pj_pool_t		    *pool;    pjsip_endpoint	    *endpt;    struct evpkg	     pkg_list;    pjsip_allow_events_hdr  *allow_events_hdr;} mod_evsub = {    {	NULL, NULL,			    /* prev, next.		*/	{ "mod-evsub", 9 },		    /* Name.			*/	-1,				    /* Id			*/	PJSIP_MOD_PRIORITY_DIALOG_USAGE,    /* Priority			*/	NULL,				    /* load()			*/	NULL,				    /* start()			*/	NULL,				    /* stop()			*/	&mod_evsub_unload,		    /* unload()			*/	NULL,				    /* on_rx_request()		*/	NULL,				    /* on_rx_response()		*/	NULL,				    /* on_tx_request.		*/	NULL,				    /* on_tx_response()		*/	&mod_evsub_on_tsx_state,	    /* on_tsx_state()		*/    }};/* * Event subscription session. */struct pjsip_evsub{    char		  obj_name[PJ_MAX_OBJ_NAME]; /**< Name.		    */    pj_pool_t		 *pool;		/**< Pool.			    */    pjsip_endpoint	 *endpt;	/**< Endpoint instance.		    */    pjsip_dialog	 *dlg;		/**< Underlying dialog.		    */    struct evpkg	 *pkg;		/**< The event package.		    */    unsigned		  option;	/**< Options.			    */    pjsip_evsub_user	  user;		/**< Callback.			    */    pj_bool_t		  call_cb;	/**< Notify callback?		    */    pjsip_role_e	  role;		/**< UAC=subscriber, UAS=notifier   */    pjsip_evsub_state	  state;	/**< Subscription state.	    */    pj_str_t		  state_str;	/**< String describing the state.   */    pjsip_evsub_state	  dst_state;	/**< Pending state to be set.	    */    pj_str_t		  dst_state_str;/**< Pending state to be set.	    */    pjsip_method	  method;	/**< Method that established subscr.*/    pjsip_event_hdr	 *event;	/**< Event description.		    */    pjsip_expires_hdr	 *expires;	/**< Expires header		    */    pjsip_accept_hdr	 *accept;	/**< Local Accept header.	    */    pj_time_val		  refresh_time;	/**< Time to refresh.		    */    pj_timer_entry	  timer;	/**< Internal timer.		    */    int			  pending_tsx;	/**< Number of pending transactions.*/    pjsip_transaction	 *pending_sub;	/**< Pending UAC SUBSCRIBE tsx.	    */    void		 *mod_data[PJSIP_MAX_MODULE];	/**< Module data.   */};/* * This is the structure that will be "attached" to dialog. * The purpose is to allow multiple subscriptions inside a dialog. */struct dlgsub{    PJ_DECL_LIST_MEMBER(struct dlgsub);    pjsip_evsub *sub;};/* Static vars. */static const pj_str_t STR_EVENT	     = { "Event", 5 };static const pj_str_t STR_SUB_STATE  = { "Subscription-State", 18 };static const pj_str_t STR_TERMINATED = { "terminated", 10 };static const pj_str_t STR_ACTIVE     = { "active", 6 };static const pj_str_t STR_PENDING    = { "pending", 7 };static const pj_str_t STR_TIMEOUT    = { "timeout", 7};/* * On unload module. */static pj_status_t mod_evsub_unload(void){    pjsip_endpt_release_pool(mod_evsub.endpt, mod_evsub.pool);    mod_evsub.pool = NULL;    return PJ_SUCCESS;}/* Proto for pjsipsimple_strerror(). * Defined in errno.c */PJ_DECL(pj_str_t) pjsipsimple_strerror( pj_status_t statcode, 				        char *buf, pj_size_t bufsize );/* * Init and register module. */PJ_DEF(pj_status_t) pjsip_evsub_init_module(pjsip_endpoint *endpt){    pj_status_t status;    pj_str_t method_tags[] = {	{ "SUBSCRIBE", 9},	{ "NOTIFY", 6}    };    pj_register_strerror(PJSIP_SIMPLE_ERRNO_START, PJ_ERRNO_SPACE_SIZE,			 &pjsipsimple_strerror);    PJ_ASSERT_RETURN(endpt != NULL, PJ_EINVAL);    PJ_ASSERT_RETURN(mod_evsub.mod.id == -1, PJ_EINVALIDOP);    /* Keep endpoint for future reference: */    mod_evsub.endpt = endpt;    /* Init event package list: */    pj_list_init(&mod_evsub.pkg_list);    /* Create pool: */    mod_evsub.pool = pjsip_endpt_create_pool(endpt, "evsub", 4000, 4000);    if (!mod_evsub.pool)	return PJ_ENOMEM;    /* Register module: */    status = pjsip_endpt_register_module(endpt, &mod_evsub.mod);    if (status  != PJ_SUCCESS)	goto on_error;     /* Create Allow-Events header: */    mod_evsub.allow_events_hdr = pjsip_allow_events_hdr_create(mod_evsub.pool);    /* Register SIP-event specific headers parser: */    pjsip_evsub_init_parser();    /* Register new methods SUBSCRIBE and NOTIFY in Allow-ed header */    pjsip_endpt_add_capability(endpt, &mod_evsub.mod, PJSIP_H_ALLOW, NULL,			       2, method_tags);    /* Done. */    return PJ_SUCCESS;on_error:    if (mod_evsub.pool) {	pjsip_endpt_release_pool(endpt, mod_evsub.pool);	mod_evsub.pool = NULL;    }    mod_evsub.endpt = NULL;    return status;}/* * Get the instance of the module. */PJ_DEF(pjsip_module*) pjsip_evsub_instance(void){    PJ_ASSERT_RETURN(mod_evsub.mod.id != -1, NULL);    return &mod_evsub.mod;}/* * Get the event subscription instance in the transaction. */PJ_DEF(pjsip_evsub*) pjsip_tsx_get_evsub(pjsip_transaction *tsx){    return tsx->mod_data[mod_evsub.mod.id];}/* * Set event subscription's module data. */PJ_DEF(void) pjsip_evsub_set_mod_data( pjsip_evsub *sub, unsigned mod_id,				       void *data ){    PJ_ASSERT_ON_FAIL(mod_id < PJSIP_MAX_MODULE, return);    sub->mod_data[mod_id] = data;}/* * Get event subscription's module data. */PJ_DEF(void*) pjsip_evsub_get_mod_data( pjsip_evsub *sub, unsigned mod_id ){    PJ_ASSERT_RETURN(mod_id < PJSIP_MAX_MODULE, NULL);    return sub->mod_data[mod_id];}/* * Find registered event package with matching name. */static struct evpkg* find_pkg(const pj_str_t *event_name){    struct evpkg *pkg;    pkg = mod_evsub.pkg_list.next;    while (pkg != &mod_evsub.pkg_list) {	if (pj_stricmp(&pkg->pkg_name, event_name) == 0) {	    return pkg;	}	pkg = pkg->next;    }    return NULL;}/* * Register an event package */PJ_DEF(pj_status_t) pjsip_evsub_register_pkg( pjsip_module *pkg_mod,					      const pj_str_t *event_name,					      unsigned expires,					      unsigned accept_cnt,					      const pj_str_t accept[]){    struct evpkg *pkg;    unsigned i;    PJ_ASSERT_RETURN(pkg_mod && event_name, PJ_EINVAL);    PJ_ASSERT_RETURN(accept_cnt < PJ_ARRAY_SIZE(pkg->pkg_accept->values), 		     PJ_ETOOMANY);    /* Make sure no module with the specified name already registered: */    PJ_ASSERT_RETURN(find_pkg(event_name) == NULL, PJSIP_SIMPLE_EPKGEXISTS);    /* Create new event package: */    pkg = pj_pool_alloc(mod_evsub.pool, sizeof(struct evpkg));    pkg->pkg_mod = pkg_mod;    pkg->pkg_expires = expires;    pj_strdup(mod_evsub.pool, &pkg->pkg_name, event_name);    pkg->pkg_accept = pjsip_accept_hdr_create(mod_evsub.pool);    pkg->pkg_accept->count = accept_cnt;    for (i=0; i<accept_cnt; ++i) {	pj_strdup(mod_evsub.pool, &pkg->pkg_accept->values[i], &accept[i]);    }    /* Add to package list: */    pj_list_push_back(&mod_evsub.pkg_list, pkg);    /* Add to Allow-Events header: */    if (mod_evsub.allow_events_hdr->count !=	PJ_ARRAY_SIZE(mod_evsub.allow_events_hdr->values))    {	mod_evsub.allow_events_hdr->values[mod_evsub.allow_events_hdr->count] =	    pkg->pkg_name;	++mod_evsub.allow_events_hdr->count;    }        /* Add to endpoint's Accept header */    pjsip_endpt_add_capability(mod_evsub.endpt, &mod_evsub.mod,			       PJSIP_H_ACCEPT, NULL,			       pkg->pkg_accept->count,			       pkg->pkg_accept->values);    /* Done */    PJ_LOG(5,(THIS_FILE, "Event pkg \"%.*s\" registered by %.*s",	      (int)event_name->slen, event_name->ptr,	      (int)pkg_mod->name.slen, pkg_mod->name.ptr));    return PJ_SUCCESS;}/* * Retrieve Allow-Events header */PJ_DEF(const pjsip_hdr*) pjsip_evsub_get_allow_events_hdr(pjsip_module *m){    struct mod_evsub *mod;    if (m == NULL)	m = pjsip_evsub_instance();    mod = (struct mod_evsub*)m;    return (pjsip_hdr*) mod->allow_events_hdr;}/* * Update expiration time. */static void update_expires( pjsip_evsub *sub, pj_uint32_t interval ){    pj_gettimeofday(&sub->refresh_time);    sub->refresh_time.sec += interval;}/*  * Schedule timer. */static void set_timer( pjsip_evsub *sub, int timer_id,		       pj_int32_t seconds){    if (sub->timer.id != TIMER_TYPE_NONE) {	PJ_LOG(5,(sub->obj_name, "%s %s timer", 		  (timer_id==sub->timer.id ? "Updating" : "Cancelling"),		  timer_names[sub->timer.id]));	pjsip_endpt_cancel_timer(sub->endpt, &sub->timer);	sub->timer.id = TIMER_TYPE_NONE;    }    if (timer_id != TIMER_TYPE_NONE) {	pj_time_val timeout;	PJ_ASSERT_ON_FAIL(seconds > 0, return);	PJ_ASSERT_ON_FAIL(timer_id>TIMER_TYPE_NONE && timer_id<TIMER_TYPE_MAX,			  return);	timeout.sec = seconds;	timeout.msec = 0;	sub->timer.id = timer_id;	pjsip_endpt_schedule_timer(sub->endpt, &sub->timer, &timeout);	PJ_LOG(5,(sub->obj_name, "Timer %s scheduled in %d seconds", 		  timer_names[sub->timer.id], timeout.sec));    }}

⌨️ 快捷键说明

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