Ignore:
Timestamp:
Feb 19, 2006 1:38:06 AM (18 years ago)
Author:
bennylp
Message:

Initial SIMPLE implementation

File:
1 moved

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjsip/src/pjsip-simple/evsub.c

    • Property svn:keywords set to id
    r187 r197  
    1717 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
    1818 */ 
    19 #include <pjsip_simple/event_notify.h> 
    20 #include <pjsip/sip_msg.h> 
    21 #include <pjsip/sip_util.h> 
     19#include <pjsip-simple/evsub.h> 
     20#include <pjsip-simple/evsub_msg.h> 
     21#include <pjsip-simple/errno.h> 
     22#include <pjsip/sip_errno.h> 
     23#include <pjsip/sip_module.h> 
    2224#include <pjsip/sip_endpoint.h> 
    23 #include <pjsip/sip_module.h> 
     25#include <pjsip/sip_dialog.h> 
     26#include <pjsip/sip_auth.h> 
    2427#include <pjsip/sip_transaction.h> 
    2528#include <pjsip/sip_event.h> 
     29#include <pj/assert.h> 
     30#include <pj/guid.h> 
     31#include <pj/log.h> 
     32#include <pj/os.h> 
    2633#include <pj/pool.h> 
    27 #include <pj/timer.h> 
    2834#include <pj/string.h> 
    29 #include <pj/hash.h> 
    30 #include <pj/os.h> 
    31 #include <pj/except.h> 
    32 #include <pj/log.h> 
    33 #include <pj/guid.h> 
    34  
    35 #define THIS_FILE               "event_sub" 
    36  
    37 /* String names for state.  
    38  * The names here should be compliant with sub_state names in RFC3265. 
    39  */ 
    40 static const pj_str_t state[] = { 
    41     { "null", 4 },  
    42     { "active", 6 }, 
    43     { "pending", 7 }, 
    44     { "terminated", 10 }, 
    45     { "unknown", 7 } 
     35 
     36 
     37#define THIS_FILE       "evsub.c" 
     38 
     39/* 
     40 * Global constant 
     41 */ 
     42 
     43/* Let's define this enum, so that it'll trigger compilation error 
     44 * when somebody define the same enum in sip_msg.h 
     45 */ 
     46enum 
     47{ 
     48    PJSIP_SUBSCRIBE_METHOD = PJSIP_OTHER_METHOD, 
     49    PJSIP_NOTIFY_METHOD = PJSIP_OTHER_METHOD 
    4650}; 
    4751 
    48 /* Timer IDs */ 
    49 #define TIMER_ID_REFRESH        1 
    50 #define TIMER_ID_UAS_EXPIRY     2 
    51  
    52 /* Static configuration. */ 
    53 #define SECONDS_BEFORE_EXPIRY   10 
    54 #define MGR_POOL_SIZE           512 
    55 #define MGR_POOL_INC            0 
    56 #define SUB_POOL_SIZE           2048 
    57 #define SUB_POOL_INC            0 
    58 #define HASH_TABLE_SIZE         32 
     52const pjsip_method pjsip_subscribe_method =  
     53{ 
     54    PJSIP_SUBSCRIBE_METHOD, 
     55    { "SUBSCRIBE", 9 } 
     56}; 
     57 
     58const pjsip_method pjsip_notify_method =  
     59{ 
     60    PJSIP_NOTIFY_METHOD, 
     61    { "NOTIFY", 6 } 
     62}; 
     63 
     64/* 
     65 * Static prototypes. 
     66 */ 
     67static void        mod_evsub_on_tsx_state(pjsip_transaction*, pjsip_event*); 
     68static pj_status_t mod_evsub_unload(void); 
     69 
     70 
     71/* 
     72 * State names. 
     73 */ 
     74static pj_str_t evsub_state_names[] =  
     75{ 
     76    { "NULL",       4}, 
     77    { "SENT",       4}, 
     78    { "ACCEPTED",   8}, 
     79    { "PENDING",    7}, 
     80    { "ACTIVE",     6}, 
     81    { "TERMINATED", 10}, 
     82    { "UNKNOWN",    7} 
     83}; 
     84 
     85/* 
     86 * Timer constants. 
     87 */ 
     88 
     89/* Number of seconds to send SUBSCRIBE before the actual expiration */ 
     90#define TIME_UAC_REFRESH        5 
     91 
     92/* Time to wait for the final NOTIFY after sending unsubscription */ 
     93#define TIME_UAC_TERMINATE      5 
     94 
     95/* If client responds NOTIFY with non-2xx final response (such as 401), 
     96 * wait for this seconds for further NOTIFY, otherwise client will 
     97 * unsubscribe 
     98 */ 
     99#define TIME_UAC_WAIT_NOTIFY    5 
     100 
     101 
     102/* 
     103 * Timer id 
     104 */ 
     105enum timer_id 
     106{ 
     107    /* No timer. */ 
     108    TIMER_TYPE_NONE, 
     109 
     110    /* Time to refresh client subscription.  
     111     * The action is to call on_client_refresh() callback. 
     112     */ 
     113    TIMER_TYPE_UAC_REFRESH, 
     114 
     115    /* UAS timeout after to subscription refresh.  
     116     * The action is to call on_server_timeout() callback. 
     117     */ 
     118    TIMER_TYPE_UAS_TIMEOUT, 
     119 
     120    /* UAC waiting for final NOTIFY after unsubscribing  
     121     * The action is to terminate. 
     122     */ 
     123    TIMER_TYPE_UAC_TERMINATE, 
     124 
     125    /* UAC waiting for further NOTIFY after sending non-2xx response to  
     126     * NOTIFY. The action is to unsubscribe. 
     127     */ 
     128    TIMER_TYPE_UAC_WAIT_NOTIFY, 
     129 
     130}; 
     131 
     132static const char *timer_names[] =  
     133{ 
     134    "None", 
     135    "UAC_REFRESH", 
     136    "UAS_TIMEOUT" 
     137    "UAC_TERMINATE", 
     138    "UAC_WAIT_NOTIFY", 
     139}; 
     140 
     141/* 
     142 * Definition of event package. 
     143 */ 
     144struct evpkg 
     145{ 
     146    PJ_DECL_LIST_MEMBER(struct evpkg); 
     147 
     148    pj_str_t             pkg_name; 
     149    pjsip_module        *pkg_mod; 
     150    unsigned             pkg_expires; 
     151    pjsip_accept_hdr    *pkg_accept; 
     152}; 
     153 
     154 
     155/* 
     156 * Event subscription module (mod-evsub). 
     157 */ 
     158static struct mod_evsub 
     159{ 
     160    pjsip_module             mod; 
     161    pj_pool_t               *pool; 
     162    pjsip_endpoint          *endpt; 
     163    struct evpkg             pkg_list; 
     164    pjsip_allow_events_hdr  *allow_events_hdr; 
     165 
     166} mod_evsub =  
     167{ 
     168    { 
     169        NULL, NULL,                 /* prev, next.                      */ 
     170        { "mod-evsub", 9 },         /* Name.                            */ 
     171        -1,                         /* Id                               */ 
     172        PJSIP_MOD_PRIORITY_APPLICATION-1,       /* Priority             */ 
     173        NULL,                       /* User data.                       */ 
     174        NULL,                       /* load()                           */ 
     175        NULL,                       /* start()                          */ 
     176        NULL,                       /* stop()                           */ 
     177        &mod_evsub_unload,          /* unload()                         */ 
     178        NULL,                       /* on_rx_request()                  */ 
     179        NULL,                       /* on_rx_response()                 */ 
     180        NULL,                       /* on_tx_request.                   */ 
     181        NULL,                       /* on_tx_response()                 */ 
     182        &mod_evsub_on_tsx_state,    /* on_tsx_state()                   */ 
     183    } 
     184}; 
     185 
     186 
     187/* 
     188 * Event subscription session. 
     189 */ 
     190struct pjsip_evsub 
     191{ 
     192    char                  obj_name[PJ_MAX_OBJ_NAME]; /**< Name.             */ 
     193    pj_pool_t            *pool;         /**< Pool.                          */ 
     194    pjsip_endpoint       *endpt;        /**< Endpoint instance.             */ 
     195    pjsip_dialog         *dlg;          /**< Underlying dialog.             */ 
     196    struct evpkg         *pkg;          /**< The event package.             */ 
     197    pjsip_evsub_user      user;         /**< Callback.                      */ 
     198    pjsip_role_e          role;         /**< UAC=subscriber, UAS=notifier   */ 
     199    pjsip_evsub_state     state;        /**< Subscription state.            */ 
     200    pj_str_t              state_str;    /**< String describing the state.   */ 
     201    pjsip_evsub_state     dst_state;    /**< Pending state to be set.       */ 
     202    pj_str_t              dst_state_str;/**< Pending state to be set.       */ 
     203    pjsip_method          method;       /**< Method that established subscr.*/ 
     204    pjsip_event_hdr      *event;        /**< Event description.             */ 
     205    pjsip_expires_hdr    *expires;      /**< Expires header                 */ 
     206    pjsip_accept_hdr     *accept;       /**< Local Accept header.           */ 
     207 
     208    pj_time_val           refresh_time; /**< Time to refresh.               */ 
     209    pj_timer_entry        timer;        /**< Internal timer.                */ 
     210    int                   pending_tsx;  /**< Number of pending transactions.*/ 
     211 
     212    void                 *mod_data[PJSIP_MAX_MODULE];   /**< Module data.   */ 
     213}; 
     214 
     215 
     216/* 
     217 * This is the structure that will be "attached" to dialog. 
     218 * The purpose is to allow multiple subscriptions inside a dialog. 
     219 */ 
     220struct dlgsub 
     221{ 
     222    PJ_DECL_LIST_MEMBER(struct dlgsub); 
     223    pjsip_evsub *sub; 
     224}; 
     225 
    59226 
    60227/* Static vars. */ 
    61 static int mod_id; 
    62 static const pjsip_method SUBSCRIBE = { PJSIP_OTHER_METHOD, {"SUBSCRIBE", 9}}; 
    63 static const pjsip_method NOTIFY = { PJSIP_OTHER_METHOD, { "NOTIFY", 6}}; 
    64  
    65 typedef struct package 
    66 { 
    67     PJ_DECL_LIST_MEMBER(struct package) 
    68     pj_str_t                event; 
    69     int                     accept_cnt; 
    70     pj_str_t               *accept; 
    71     pjsip_event_sub_pkg_cb  cb; 
    72 } package; 
    73  
    74 /* Event subscription manager singleton instance. */ 
    75 static struct pjsip_event_sub_mgr 
    76 { 
    77     pj_pool_t               *pool; 
    78     pj_hash_table_t         *ht; 
    79     pjsip_endpoint          *endpt; 
    80     pj_mutex_t              *mutex; 
    81     pjsip_allow_events_hdr  *allow_events; 
    82     package                  pkg_list; 
    83 } mgr; 
    84  
    85 /* Fordward declarations for static functions. */ 
    86 static pj_status_t      mod_init(pjsip_endpoint *, pjsip_module *, pj_uint32_t); 
    87 static pj_status_t      mod_deinit(pjsip_module*); 
    88 static void             tsx_handler(pjsip_module*, pjsip_event*); 
    89 static pjsip_event_sub *find_sub(pjsip_rx_data *); 
    90 static void             on_subscribe_request(pjsip_transaction*, pjsip_rx_data*); 
    91 static void             on_subscribe_response(void *, pjsip_event*); 
    92 static void             on_notify_request(pjsip_transaction *, pjsip_rx_data*); 
    93 static void             on_notify_response(void *, pjsip_event *); 
    94 static void             refresh_timer_cb(pj_timer_heap_t*, pj_timer_entry*); 
    95 static void             uas_expire_timer_cb(pj_timer_heap_t*, pj_timer_entry*); 
    96 static pj_status_t      send_sub_refresh( pjsip_event_sub *sub ); 
    97  
    98 /* Module descriptor. */ 
    99 static pjsip_module event_sub_module =  
    100 { 
    101     {"EventSub", 8},                    /* Name.                */ 
    102     0,                                  /* Flag                 */ 
    103     128,                                /* Priority             */ 
    104     &mgr,                               /* User data.           */ 
    105     2,                                  /* Number of methods supported . */ 
    106     { &SUBSCRIBE, &NOTIFY },            /* Array of methods */ 
    107     &mod_init,                          /* init_module()        */ 
    108     NULL,                               /* start_module()       */ 
    109     &mod_deinit,                        /* deinit_module()      */ 
    110     &tsx_handler,                       /* tsx_handler()        */ 
    111 }; 
    112  
    113 /* 
    114  * Module initialization. 
    115  * This will be called by endpoint when it initializes all modules. 
    116  */ 
    117 static pj_status_t mod_init( pjsip_endpoint *endpt, 
    118                              struct pjsip_module *mod, pj_uint32_t id ) 
    119 { 
    120     pj_pool_t *pool; 
    121  
    122     pool = pjsip_endpt_create_pool(endpt, "esubmgr", MGR_POOL_SIZE, MGR_POOL_INC); 
    123     if (!pool) 
    124         return -1; 
    125  
    126     /* Manager initialization: create hash table and mutex. */ 
    127     mgr.pool = pool; 
    128     mgr.endpt = endpt; 
    129     mgr.ht = pj_hash_create(pool, HASH_TABLE_SIZE); 
    130     if (!mgr.ht) 
    131         return -1; 
    132  
    133     mgr.mutex = pj_mutex_create(pool, "esubmgr", PJ_MUTEX_SIMPLE); 
    134     if (!mgr.mutex) 
    135         return -1; 
    136  
    137     /* Attach manager to module. */ 
    138     mod->mod_data = &mgr; 
    139  
    140     /* Init package list. */ 
    141     pj_list_init(&mgr.pkg_list); 
    142  
    143     /* Init Allow-Events header. */ 
    144     mgr.allow_events = pjsip_allow_events_hdr_create(mgr.pool); 
    145  
    146     /* Save the module ID. */ 
    147     mod_id = id; 
    148  
    149     pjsip_event_notify_init_parser(); 
    150     return 0; 
    151 } 
    152  
    153 /* 
    154  * Module deinitialization. 
    155  * Called by endpoint. 
    156  */ 
    157 static pj_status_t mod_deinit( struct pjsip_module *mod ) 
    158 { 
    159     pj_mutex_lock(mgr.mutex); 
    160     pj_mutex_destroy(mgr.mutex); 
    161     pjsip_endpt_destroy_pool(mgr.endpt, mgr.pool); 
    162     return 0; 
    163 } 
    164  
    165 /* 
    166  * This public function is called by application to register callback. 
    167  * In exchange, the instance of the module is returned. 
    168  */ 
    169 PJ_DEF(pjsip_module*) pjsip_event_sub_get_module(void) 
    170 { 
    171     return &event_sub_module; 
    172 } 
    173  
    174 /* 
    175  * Register event package. 
    176  */ 
    177 PJ_DEF(pj_status_t) pjsip_event_sub_register_pkg( const pj_str_t *event, 
    178                                                   int accept_cnt, 
    179                                                   const pj_str_t accept[], 
    180                                                   const pjsip_event_sub_pkg_cb *cb ) 
    181 { 
    182     package *pkg; 
    183     int i; 
    184  
    185     pj_mutex_lock(mgr.mutex); 
    186  
    187     /* Create and register new package. */ 
    188     pkg = pj_pool_alloc(mgr.pool, sizeof(*pkg)); 
    189     pj_strdup(mgr.pool, &pkg->event, event); 
    190     pj_list_insert_before(&mgr.pkg_list, pkg); 
    191  
    192     /* Save Accept specification. */ 
    193     pkg->accept_cnt = accept_cnt; 
    194     pkg->accept = pj_pool_alloc(mgr.pool, accept_cnt*sizeof(pj_str_t)); 
     228static const pj_str_t STR_EVENT      = { "Event", 5 }; 
     229static const pj_str_t STR_SUB_STATE  = { "Subscription-State", 18 }; 
     230static const pj_str_t STR_TERMINATED = { "terminated", 10 }; 
     231static const pj_str_t STR_ACTIVE     = { "active", 6 }; 
     232static const pj_str_t STR_PENDING    = { "pending", 7 }; 
     233static const pj_str_t STR_TIMEOUT    = { "timeout", 7}; 
     234 
     235/* 
     236 * On unload module. 
     237 */ 
     238static pj_status_t mod_evsub_unload(void) 
     239{ 
     240    pjsip_endpt_release_pool(mod_evsub.endpt, mod_evsub.pool); 
     241    mod_evsub.pool = NULL; 
     242 
     243    return PJ_SUCCESS; 
     244} 
     245 
     246/* 
     247 * Init and register module. 
     248 */ 
     249PJ_DEF(pj_status_t) pjsip_evsub_init_module(pjsip_endpoint *endpt) 
     250{ 
     251    pj_status_t status; 
     252 
     253    PJ_ASSERT_RETURN(endpt != NULL, PJ_EINVAL); 
     254    PJ_ASSERT_RETURN(mod_evsub.mod.id == -1, PJ_EINVALIDOP); 
     255 
     256    /* Keep endpoint for future reference: */ 
     257    mod_evsub.endpt = endpt; 
     258 
     259    /* Init event package list: */ 
     260    pj_list_init(&mod_evsub.pkg_list); 
     261 
     262    /* Create pool: */ 
     263    mod_evsub.pool = pjsip_endpt_create_pool(endpt, "evsub", 4000, 4000); 
     264    if (!mod_evsub.pool) 
     265        return PJ_ENOMEM; 
     266 
     267    /* Register module: */ 
     268    status = pjsip_endpt_register_module(endpt, &mod_evsub.mod); 
     269    if (status  != PJ_SUCCESS) 
     270        goto on_error; 
     271  
     272    /* Create Allow-Events header: */ 
     273    mod_evsub.allow_events_hdr = pjsip_allow_events_hdr_create(mod_evsub.pool); 
     274 
     275    /* Register SIP-event specific headers parser: */ 
     276    pjsip_evsub_init_parser(); 
     277 
     278    return PJ_SUCCESS; 
     279 
     280on_error: 
     281    if (mod_evsub.pool) { 
     282        pjsip_endpt_release_pool(endpt, mod_evsub.pool); 
     283        mod_evsub.pool = NULL; 
     284    } 
     285    mod_evsub.endpt = NULL; 
     286    return status; 
     287} 
     288 
     289 
     290/* 
     291 * Get the instance of the module. 
     292 */ 
     293PJ_DEF(pjsip_module*) pjsip_evsub_instance(void) 
     294{ 
     295    PJ_ASSERT_RETURN(mod_evsub.mod.id != -1, NULL); 
     296 
     297    return &mod_evsub.mod; 
     298} 
     299 
     300 
     301/* 
     302 * Get the event subscription instance in the transaction. 
     303 */ 
     304PJ_DEF(pjsip_evsub*) pjsip_tsx_get_evsub(pjsip_transaction *tsx) 
     305{ 
     306    return tsx->mod_data[mod_evsub.mod.id]; 
     307} 
     308 
     309 
     310/* 
     311 * Set event subscription's module data. 
     312 */ 
     313PJ_DEF(void) pjsip_evsub_set_mod_data( pjsip_evsub *sub, unsigned mod_id, 
     314                                       void *data ) 
     315{ 
     316    PJ_ASSERT_ON_FAIL(mod_id < PJSIP_MAX_MODULE, return); 
     317    sub->mod_data[mod_id] = data; 
     318} 
     319 
     320 
     321/* 
     322 * Get event subscription's module data. 
     323 */ 
     324PJ_DEF(void*) pjsip_evsub_get_mod_data( pjsip_evsub *sub, unsigned mod_id ) 
     325{ 
     326    PJ_ASSERT_RETURN(mod_id < PJSIP_MAX_MODULE, NULL); 
     327    return sub->mod_data[mod_id]; 
     328} 
     329 
     330 
     331/* 
     332 * Find registered event package with matching name. 
     333 */ 
     334static struct evpkg* find_pkg(const pj_str_t *event_name) 
     335{ 
     336    struct evpkg *pkg; 
     337 
     338    pkg = mod_evsub.pkg_list.next; 
     339    while (pkg != &mod_evsub.pkg_list) { 
     340 
     341        if (pj_stricmp(&pkg->pkg_name, event_name) == 0) { 
     342            return pkg; 
     343        } 
     344 
     345        pkg = pkg->next; 
     346    } 
     347 
     348    return NULL; 
     349} 
     350 
     351/* 
     352 * Register an event package 
     353 */ 
     354PJ_DEF(pj_status_t) pjsip_evsub_register_pkg( pjsip_module *pkg_mod, 
     355                                              const pj_str_t *event_name, 
     356                                              unsigned expires, 
     357                                              unsigned accept_cnt, 
     358                                              const pj_str_t accept[]) 
     359{ 
     360    struct evpkg *pkg; 
     361    unsigned i; 
     362 
     363    PJ_ASSERT_RETURN(pkg_mod && event_name, PJ_EINVAL); 
     364    PJ_ASSERT_RETURN(accept_cnt < PJ_ARRAY_SIZE(pkg->pkg_accept->values),  
     365                     PJ_ETOOMANY); 
     366 
     367    /* Make sure no module with the specified name already registered: */ 
     368 
     369    PJ_ASSERT_RETURN(find_pkg(event_name) == NULL, PJSIP_SIMPLE_EPKGEXISTS); 
     370 
     371 
     372    /* Create new event package: */ 
     373 
     374    pkg = pj_pool_alloc(mod_evsub.pool, sizeof(struct evpkg)); 
     375    pkg->pkg_mod = pkg_mod; 
     376    pkg->pkg_expires = expires; 
     377    pj_strdup(mod_evsub.pool, &pkg->pkg_name, event_name); 
     378 
     379    pkg->pkg_accept = pjsip_accept_hdr_create(mod_evsub.pool); 
     380    pkg->pkg_accept->count = accept_cnt; 
    195381    for (i=0; i<accept_cnt; ++i) { 
    196         pj_strdup(mgr.pool, &pkg->accept[i], &accept[i]); 
    197     } 
    198  
    199     /* Copy callback. */ 
    200     pj_memcpy(&pkg->cb, cb, sizeof(*cb)); 
    201  
    202     /* Update Allow-Events header. */ 
    203     pj_assert(mgr.allow_events->event_cnt < PJSIP_MAX_ALLOW_EVENTS); 
    204     mgr.allow_events->events[mgr.allow_events->event_cnt++] = pkg->event; 
    205  
    206     pj_mutex_unlock(mgr.mutex); 
    207     return 0; 
    208 } 
    209  
    210 /* 
    211  * Create subscription key (for hash table). 
    212  */ 
    213 static void create_subscriber_key( pj_str_t *key, pj_pool_t *pool, 
    214                                    pjsip_role_e role,  
    215                                    const pj_str_t *call_id, const pj_str_t *from_tag) 
    216 { 
    217     char *p; 
    218  
    219     p = key->ptr = pj_pool_alloc(pool, call_id->slen + from_tag->slen + 3); 
    220     *p++ = (role == PJSIP_ROLE_UAS ? 'S' : 'C'); 
    221     *p++ = '$'; 
    222     pj_memcpy(p, call_id->ptr, call_id->slen); 
    223     p += call_id->slen; 
    224     *p++ = '$'; 
    225     pj_memcpy(p, from_tag->ptr, from_tag->slen); 
    226     p += from_tag->slen; 
    227  
    228     key->slen = p - key->ptr; 
    229 } 
    230  
    231  
    232 /* 
    233  * Create UAC subscription. 
    234  */ 
    235 PJ_DEF(pjsip_event_sub*) pjsip_event_sub_create( pjsip_endpoint *endpt, 
    236                                                  const pj_str_t *from, 
    237                                                  const pj_str_t *to, 
    238                                                  const pj_str_t *event, 
    239                                                  int expires, 
    240                                                  int accept_cnt, 
    241                                                  const pj_str_t accept[], 
    242                                                  void *user_data, 
    243                                                  const pjsip_event_sub_cb *cb) 
    244 { 
    245     pjsip_tx_data *tdata; 
    246     pj_pool_t *pool; 
    247     const pjsip_hdr *hdr; 
    248     pjsip_event_sub *sub; 
    249     PJ_USE_EXCEPTION; 
    250  
    251     PJ_LOG(5,(THIS_FILE, "Creating event subscription %.*s to %.*s", 
    252                          event->slen, event->ptr, to->slen, to->ptr)); 
    253  
    254     /* Create pool for the event subscription. */ 
    255     pool = pjsip_endpt_create_pool(endpt, "esub", SUB_POOL_SIZE, SUB_POOL_INC); 
    256     if (!pool) { 
    257         return NULL; 
    258     } 
    259  
    260     /* Init subscription. */ 
    261     sub = pj_pool_calloc(pool, 1, sizeof(*sub)); 
    262     sub->pool = pool; 
    263     sub->endpt = endpt; 
    264     sub->role = PJSIP_ROLE_UAC; 
    265     sub->state = PJSIP_EVENT_SUB_STATE_PENDING; 
    266     sub->state_str = state[sub->state]; 
    267     sub->user_data = user_data; 
    268     sub->timer.id = 0; 
    269     sub->default_interval = expires; 
    270     pj_memcpy(&sub->cb, cb, sizeof(*cb)); 
    271     pj_list_init(&sub->auth_sess); 
    272     pj_list_init(&sub->route_set); 
    273     sub->mutex = pj_mutex_create(pool, "esub", PJ_MUTEX_RECURSE); 
    274     if (!sub->mutex) { 
    275         pjsip_endpt_destroy_pool(endpt, pool); 
    276         return NULL; 
    277     } 
    278  
    279     /* The easiest way to parse the parameters is to create a dummy request! */ 
    280     tdata = pjsip_endpt_create_request( endpt, &SUBSCRIBE, to, from, to, from, 
    281                                         NULL, -1, NULL); 
    282     if (!tdata) { 
    283         pj_mutex_destroy(sub->mutex); 
    284         pjsip_endpt_destroy_pool(endpt, pool); 
    285         return NULL; 
    286     } 
    287  
    288     /*  
    289      * Duplicate headers in the request to our structure.  
    290      */ 
    291     PJ_TRY { 
    292         int i; 
    293  
    294         /* From */ 
    295         hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_FROM, NULL); 
    296         pj_assert(hdr != NULL); 
    297         sub->from = pjsip_hdr_clone(pool, hdr); 
    298          
    299         /* To */ 
    300         hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_TO, NULL); 
    301         pj_assert(hdr != NULL); 
    302         sub->to = pjsip_hdr_clone(pool, hdr); 
    303  
    304         /* Contact. */ 
    305         sub->contact = pjsip_contact_hdr_create(pool); 
    306         sub->contact->uri = sub->from->uri; 
    307  
    308         /* Call-ID */ 
    309         hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CALL_ID, NULL); 
    310         pj_assert(hdr != NULL); 
    311         sub->call_id = pjsip_hdr_clone(pool, hdr); 
    312  
    313         /* CSeq */ 
    314         sub->cseq = pj_rand() % 0xFFFF; 
    315  
    316         /* Event. */ 
    317         sub->event = pjsip_event_hdr_create(sub->pool); 
    318         pj_strdup(pool, &sub->event->event_type, event); 
    319  
    320         /* Expires. */ 
    321         sub->uac_expires = pjsip_expires_hdr_create(pool); 
    322         sub->uac_expires->ivalue = expires; 
    323  
    324         /* Accept. */ 
    325         sub->local_accept = pjsip_accept_hdr_create(pool); 
    326         for (i=0; i<accept_cnt && i < PJSIP_MAX_ACCEPT_COUNT; ++i) { 
    327             sub->local_accept->count++; 
    328             pj_strdup(sub->pool, &sub->local_accept->values[i], &accept[i]); 
    329         } 
    330  
    331         /* Register to hash table. */ 
    332         create_subscriber_key( &sub->key, pool, PJSIP_ROLE_UAC,  
    333                                &sub->call_id->id, &sub->from->tag); 
    334         pj_mutex_lock( mgr.mutex ); 
    335         pj_hash_set( pool, mgr.ht, sub->key.ptr, sub->key.slen, sub); 
    336         pj_mutex_unlock( mgr.mutex ); 
    337  
    338     } 
    339     PJ_CATCH_ANY { 
    340         PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): caught exception %d during init",  
    341                              sub, state[sub->state].ptr, PJ_GET_EXCEPTION())); 
    342  
    343         pjsip_tx_data_dec_ref(tdata); 
    344         pj_mutex_destroy(sub->mutex); 
    345         pjsip_endpt_destroy_pool(endpt, sub->pool); 
    346         return NULL; 
    347     } 
    348     PJ_END; 
    349  
    350     /* All set, delete temporary transmit data as we don't need it. */ 
    351     pjsip_tx_data_dec_ref(tdata); 
    352  
    353     PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): client created, target=%.*s, event=%.*s", 
    354                          sub, state[sub->state].ptr, 
    355                          to->slen, to->ptr, event->slen, event->ptr)); 
    356  
    357     return sub; 
    358 } 
    359  
    360 /* 
    361  * Set credentials. 
    362  */ 
    363 PJ_DEF(pj_status_t) pjsip_event_sub_set_credentials( pjsip_event_sub *sub, 
    364                                                      int count, 
    365                                                      const pjsip_cred_info cred[]) 
    366 { 
    367     pj_mutex_lock(sub->mutex); 
    368     if (count > 0) { 
    369         sub->cred_info = pj_pool_alloc(sub->pool, count*sizeof(pjsip_cred_info)); 
    370         pj_memcpy( sub->cred_info, cred, count*sizeof(pjsip_cred_info)); 
    371     } 
    372     sub->cred_cnt = count; 
    373     pj_mutex_unlock(sub->mutex); 
    374     return 0; 
    375 } 
    376  
    377 /* 
    378  * Set route-set. 
    379  */ 
    380 PJ_DEF(pj_status_t) pjsip_event_sub_set_route_set( pjsip_event_sub *sub, 
    381                                                    const pjsip_route_hdr *route_set ) 
    382 { 
    383     const pjsip_route_hdr *hdr; 
    384  
    385     pj_mutex_lock(sub->mutex); 
    386  
    387     /* Clear existing route set. */ 
    388     pj_list_init(&sub->route_set); 
    389  
    390     /* Duplicate route headers. */ 
    391     hdr = route_set->next; 
    392     while (hdr != route_set) { 
    393         pjsip_route_hdr *new_hdr = pjsip_hdr_clone(sub->pool, hdr); 
    394         pj_list_insert_before(&sub->route_set, new_hdr); 
    395         hdr = hdr->next; 
    396     } 
    397  
    398     pj_mutex_unlock(sub->mutex); 
    399  
    400     return 0; 
    401 } 
    402  
    403 /* 
    404  * Send subscribe request. 
    405  */ 
    406 PJ_DEF(pj_status_t) pjsip_event_sub_subscribe( pjsip_event_sub *sub ) 
    407 { 
     382        pj_strdup(mod_evsub.pool, &pkg->pkg_accept->values[i], &accept[i]); 
     383    } 
     384 
     385    /* Add to package list: */ 
     386 
     387    pj_list_push_back(&mod_evsub.pkg_list, pkg); 
     388 
     389    /* Add to Allow-Events header: */ 
     390 
     391    if (mod_evsub.allow_events_hdr->count != 
     392        PJ_ARRAY_SIZE(mod_evsub.allow_events_hdr->values)) 
     393    { 
     394        mod_evsub.allow_events_hdr->values[mod_evsub.allow_events_hdr->count] = 
     395            pkg->pkg_name; 
     396        ++mod_evsub.allow_events_hdr->count; 
     397    } 
     398     
     399 
     400    /* Done */ 
     401 
     402    PJ_LOG(5,(THIS_FILE, "Event pkg \"%.*s\" registered by %.*s", 
     403              (int)event_name->slen, event_name->ptr, 
     404              (int)pkg_mod->name.slen, pkg_mod->name.ptr)); 
     405 
     406    return PJ_SUCCESS; 
     407} 
     408 
     409 
     410 
     411/* 
     412 * Update expiration time. 
     413 */ 
     414static void update_expires( pjsip_evsub *sub, pj_uint32_t interval ) 
     415{ 
     416    pj_gettimeofday(&sub->refresh_time); 
     417    sub->refresh_time.sec += interval; 
     418} 
     419 
     420 
     421/*  
     422 * Schedule timer. 
     423 */ 
     424static void set_timer( pjsip_evsub *sub, int timer_id, 
     425                       pj_int32_t seconds) 
     426{ 
     427    if (sub->timer.id != TIMER_TYPE_NONE) { 
     428        PJ_LOG(5,(sub->obj_name, "%s %s timer",  
     429                  (timer_id==sub->timer.id ? "Updating" : "Cancelling"), 
     430                  timer_names[sub->timer.id])); 
     431        pjsip_endpt_cancel_timer(sub->endpt, &sub->timer); 
     432        sub->timer.id = TIMER_TYPE_NONE; 
     433    } 
     434 
     435    if (timer_id != TIMER_TYPE_NONE) { 
     436        pj_time_val timeout; 
     437 
     438        PJ_ASSERT_ON_FAIL(seconds > 0, return); 
     439 
     440        timeout.sec = seconds; 
     441        timeout.msec = 0; 
     442        sub->timer.id = timer_id; 
     443 
     444        pjsip_endpt_schedule_timer(sub->endpt, &sub->timer, &timeout); 
     445 
     446        PJ_LOG(5,(sub->obj_name, "Timer %s scheduled in %d seconds",  
     447                  timer_names[sub->timer.id], timeout.sec)); 
     448    } 
     449} 
     450 
     451 
     452/* 
     453 * Destroy session. 
     454 */ 
     455static void evsub_destroy( pjsip_evsub *sub ) 
     456{ 
     457    struct dlgsub *dlgsub_head, *dlgsub; 
     458 
     459    PJ_LOG(4,(sub->obj_name, "Subscription destroyed")); 
     460 
     461    /* Kill timer */ 
     462    set_timer(sub, TIMER_TYPE_NONE, 0); 
     463 
     464    /* Remote this session from dialog's list of subscription */ 
     465    dlgsub_head = sub->dlg->mod_data[mod_evsub.mod.id]; 
     466    dlgsub = dlgsub_head->next; 
     467    while (dlgsub != dlgsub_head) { 
     468         
     469        if (dlgsub->sub == sub) { 
     470            pj_list_erase(dlgsub); 
     471            break; 
     472        } 
     473 
     474        dlgsub = dlgsub->next; 
     475    } 
     476 
     477    /* Decrement dialog's session */ 
     478    pjsip_dlg_dec_session(sub->dlg, &mod_evsub.mod); 
     479} 
     480 
     481/* 
     482 * Set subscription session state. 
     483 */ 
     484static void set_state( pjsip_evsub *sub, pjsip_evsub_state state, 
     485                       const pj_str_t *state_str, pjsip_event *event) 
     486{ 
     487    pj_str_t old_state_str = sub->state_str; 
     488 
     489    sub->state = state; 
     490 
     491    if (state_str && state_str->slen) 
     492        pj_strdup_with_null(sub->pool, &sub->state_str, state_str); 
     493    else 
     494        sub->state_str = evsub_state_names[state]; 
     495 
     496    PJ_LOG(4,(sub->obj_name,  
     497              "Subscription state changed %.*s --> %.*s", 
     498              (int)old_state_str.slen, 
     499              old_state_str.ptr, 
     500              (int)sub->state_str.slen, 
     501              sub->state_str.ptr)); 
     502 
     503    if (sub->user.on_evsub_state) 
     504        (*sub->user.on_evsub_state)(sub, event); 
     505 
     506    if (state == PJSIP_EVSUB_STATE_TERMINATED) { 
     507         
     508        if (sub->pending_tsx == 0) { 
     509            evsub_destroy(sub); 
     510        } 
     511    } 
     512} 
     513 
     514 
     515/* 
     516 * Timer callback. 
     517 */ 
     518static void on_timer( pj_timer_heap_t *timer_heap, 
     519                      struct pj_timer_entry *entry) 
     520{ 
     521    pjsip_evsub *sub; 
     522    int timer_id; 
     523 
     524    PJ_UNUSED_ARG(timer_heap); 
     525 
     526    sub = entry->user_data; 
     527 
     528    pjsip_dlg_inc_lock(sub->dlg); 
     529 
     530    timer_id = entry->id; 
     531    entry->id = TIMER_TYPE_NONE; 
     532 
     533    switch (timer_id) { 
     534 
     535    case TIMER_TYPE_UAC_REFRESH: 
     536        /* Time for UAC to refresh subscription */ 
     537        if (sub->user.on_client_refresh) { 
     538            (*sub->user.on_client_refresh)(sub); 
     539        } else { 
     540            pjsip_tx_data *tdata; 
     541            pj_status_t status; 
     542 
     543            PJ_LOG(5,(sub->obj_name, "Refreshing subscription.")); 
     544            status = pjsip_evsub_initiate(sub, &sub->method,  
     545                                          sub->expires->ivalue, 
     546                                          &tdata); 
     547            if (status == PJ_SUCCESS) 
     548                pjsip_evsub_send_request(sub, tdata); 
     549        } 
     550        break; 
     551 
     552    case TIMER_TYPE_UAS_TIMEOUT: 
     553        /* Refresh from UAC has not been received */ 
     554        if (sub->user.on_server_timeout) { 
     555            (*sub->user.on_server_timeout)(sub); 
     556        } else { 
     557            pjsip_tx_data *tdata; 
     558            pj_status_t status; 
     559 
     560            PJ_LOG(5,(sub->obj_name, "Timeout waiting for refresh. " 
     561                                     "Sending NOTIFY to terminate.")); 
     562            status = pjsip_evsub_notify( sub, PJSIP_EVSUB_STATE_TERMINATED,  
     563                                         NULL, &STR_TIMEOUT, &tdata); 
     564            if (status == PJ_SUCCESS) 
     565                pjsip_evsub_send_request(sub, tdata); 
     566        } 
     567        break; 
     568 
     569    case TIMER_TYPE_UAC_TERMINATE: 
     570        { 
     571            pjsip_event event; 
     572            pj_str_t reason = { "unsubscribing", 13}; 
     573 
     574            PJSIP_EVENT_INIT_TIMER(event, entry); 
     575            PJ_LOG(5,(sub->obj_name, "Timeout waiting for final NOTIFY. " 
     576                                     "Terminating..")); 
     577            set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, &event); 
     578        } 
     579        break; 
     580 
     581    case TIMER_TYPE_UAC_WAIT_NOTIFY: 
     582        { 
     583            pjsip_tx_data *tdata; 
     584            pj_status_t status; 
     585 
     586            PJ_LOG(5,(sub->obj_name,  
     587                     "Timeout waiting for subsequent NOTIFY (we did " 
     588                     "send non-2xx response for previous NOTIFY). " 
     589                     "Unsubscribing..")); 
     590            status = pjsip_evsub_initiate( sub, &sub->method, 0, &tdata); 
     591            if (status == PJ_SUCCESS) 
     592                pjsip_evsub_send_request(sub, tdata); 
     593        } 
     594        break; 
     595 
     596    default: 
     597        pj_assert(!"Invalid timer id"); 
     598    } 
     599 
     600    pjsip_dlg_dec_lock(sub->dlg); 
     601} 
     602 
     603 
     604/* 
     605 * Create subscription session, used for both client and notifier. 
     606 */ 
     607static pj_status_t evsub_create( pjsip_dialog *dlg, 
     608                                 pjsip_role_e role, 
     609                                 const pjsip_evsub_user *user_cb, 
     610                                 const pj_str_t *event, 
     611                                 pjsip_evsub **p_evsub ) 
     612{ 
     613    pjsip_evsub *sub; 
     614    struct evpkg *pkg; 
     615    struct dlgsub *dlgsub_head, *dlgsub; 
    408616    pj_status_t status; 
    409617 
    410     pj_mutex_lock(sub->mutex); 
    411     status = send_sub_refresh(sub); 
    412     pj_mutex_unlock(sub->mutex); 
    413  
     618    /* Make sure there's package register for the event name: */ 
     619 
     620    pkg = find_pkg(event); 
     621    if (pkg == NULL) 
     622        return PJSIP_SIMPLE_ENOPKG; 
     623 
     624 
     625    /* Init attributes: */ 
     626 
     627    sub = pj_pool_zalloc(dlg->pool, sizeof(struct pjsip_evsub)); 
     628    sub->pool = dlg->pool; 
     629    sub->endpt = dlg->endpt; 
     630    sub->dlg = dlg; 
     631    sub->pkg = pkg; 
     632    sub->role = role; 
     633    sub->state = PJSIP_EVSUB_STATE_NULL; 
     634    sub->state_str = evsub_state_names[sub->state]; 
     635    sub->expires = pjsip_expires_hdr_create(sub->pool, pkg->pkg_expires); 
     636    sub->accept = pjsip_hdr_clone(sub->pool, pkg->pkg_accept); 
     637 
     638    sub->timer.user_data = sub; 
     639    sub->timer.cb = &on_timer; 
     640 
     641    /* Set name. */ 
     642    pj_snprintf(sub->obj_name, PJ_ARRAY_SIZE(sub->obj_name), 
     643                "evsub%p", sub); 
     644 
     645 
     646    /* Copy callback, if any: */ 
     647    if (user_cb) 
     648        pj_memcpy(&sub->user, user_cb, sizeof(pjsip_evsub_user)); 
     649 
     650 
     651    /* Create Event header: */ 
     652    sub->event = pjsip_event_hdr_create(sub->pool); 
     653    pj_strdup(sub->pool, &sub->event->event_type, event); 
     654 
     655 
     656    /* Create subcription list: */ 
     657 
     658    dlgsub_head = pj_pool_alloc(sub->pool, sizeof(struct dlgsub)); 
     659    dlgsub = pj_pool_alloc(sub->pool, sizeof(struct dlgsub)); 
     660    dlgsub->sub = sub; 
     661 
     662    pj_list_init(dlgsub_head); 
     663    pj_list_push_back(dlgsub_head, dlgsub); 
     664 
     665 
     666    /* Register as dialog usage: */ 
     667 
     668    status = pjsip_dlg_add_usage(dlg, &mod_evsub.mod, dlgsub_head); 
     669    if (status != PJ_SUCCESS) 
     670        return status; 
     671 
     672 
     673    PJ_LOG(5,(sub->obj_name, "%s subscription created, using dialog %s", 
     674              (role==PJSIP_ROLE_UAC ? "UAC" : "UAS"), 
     675              dlg->obj_name)); 
     676 
     677    *p_evsub = sub; 
     678 
     679    return PJ_SUCCESS; 
     680} 
     681 
     682 
     683 
     684/* 
     685 * Create client subscription session. 
     686 */ 
     687PJ_DEF(pj_status_t) pjsip_evsub_create_uac( pjsip_dialog *dlg, 
     688                                            const pjsip_evsub_user *user_cb, 
     689                                            const pj_str_t *event, 
     690                                            pjsip_evsub **p_evsub) 
     691{ 
     692    pjsip_evsub *sub; 
     693    pj_status_t status; 
     694 
     695    PJ_ASSERT_RETURN(dlg && event && p_evsub, PJ_EINVAL); 
     696 
     697    pjsip_dlg_inc_lock(dlg); 
     698    status = evsub_create(dlg, PJSIP_UAC_ROLE, user_cb, event, &sub); 
     699    if (status != PJ_SUCCESS) 
     700        goto on_return; 
     701 
     702    /* Add unique Id to Event header */ 
     703    pj_create_unique_string(sub->pool, &sub->event->id_param); 
     704 
     705    /* Increment dlg session. */ 
     706    pjsip_dlg_inc_session(sub->dlg, &mod_evsub.mod); 
     707 
     708    /* Done */ 
     709    *p_evsub = sub; 
     710 
     711on_return: 
     712    pjsip_dlg_dec_lock(dlg); 
    414713    return status; 
    415714} 
    416715 
    417 /* 
    418  * Destroy subscription. 
    419  * If there are pending transactions, then this will just set the flag. 
    420  */ 
    421 PJ_DEF(pj_status_t) pjsip_event_sub_destroy(pjsip_event_sub *sub) 
    422 { 
    423     pj_assert(sub != NULL); 
    424     if (sub == NULL) 
    425         return -1; 
    426  
    427     /* Application must terminate the subscription first. */ 
    428     pj_assert(sub->state == PJSIP_EVENT_SUB_STATE_NULL || 
    429               sub->state == PJSIP_EVENT_SUB_STATE_TERMINATED); 
    430  
    431     PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): about to be destroyed",  
    432                          sub, state[sub->state].ptr)); 
    433  
    434     pj_mutex_lock(mgr.mutex); 
    435     pj_mutex_lock(sub->mutex); 
    436  
    437     /* Set delete flag. */ 
    438     sub->delete_flag = 1; 
    439  
    440     /* Unregister timer, if any. */ 
    441     if (sub->timer.id != 0) { 
    442         pjsip_endpt_cancel_timer(sub->endpt, &sub->timer); 
    443         sub->timer.id = 0; 
    444     } 
    445  
    446     if (sub->pending_tsx > 0) { 
    447         pj_mutex_unlock(sub->mutex); 
    448         pj_mutex_unlock(mgr.mutex); 
    449         PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): has %d pending, will destroy later", 
    450                              sub, state[sub->state].ptr, 
    451                              sub->pending_tsx)); 
    452         return 1; 
    453     } 
    454  
    455     /* Unregister from hash table. */ 
    456     pj_hash_set(sub->pool, mgr.ht, sub->key.ptr, sub->key.slen, NULL); 
    457  
    458     /* Destroy. */ 
    459     pj_mutex_destroy(sub->mutex); 
    460     pjsip_endpt_destroy_pool(sub->endpt, sub->pool); 
    461  
    462     pj_mutex_unlock(mgr.mutex); 
    463  
    464     PJ_LOG(4,(THIS_FILE, "event_sub%p: destroyed", sub)); 
    465     return 0; 
    466 } 
    467  
    468 /* Change state. */ 
    469 static void sub_set_state( pjsip_event_sub *sub, int new_state) 
    470 { 
    471     PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): changed state to %s", 
    472               sub, state[sub->state].ptr, state[new_state].ptr)); 
    473     sub->state = new_state; 
    474     sub->state_str = state[new_state]; 
    475 } 
    476  
    477 /* 
    478  * Refresh subscription. 
    479  */ 
    480 static pj_status_t send_sub_refresh( pjsip_event_sub *sub ) 
     716 
     717/* 
     718 * Create server subscription session from incoming request. 
     719 */ 
     720PJ_DEF(pj_status_t) pjsip_evsub_create_uas( pjsip_dialog *dlg, 
     721                                            const pjsip_evsub_user *user_cb, 
     722                                            pjsip_rx_data *rdata, 
     723                                            pjsip_evsub **p_evsub) 
     724{ 
     725    pjsip_evsub *sub; 
     726    pjsip_transaction *tsx; 
     727    pjsip_accept_hdr *accept_hdr; 
     728    pjsip_event_hdr *event_hdr; 
     729    pjsip_expires_hdr *expires_hdr; 
     730    pj_status_t status; 
     731 
     732    /* Check arguments: */ 
     733    PJ_ASSERT_RETURN(dlg && rdata && p_evsub, PJ_EINVAL); 
     734 
     735    /* MUST be request message: */ 
     736    PJ_ASSERT_RETURN(rdata->msg_info.msg->type == PJSIP_REQUEST_MSG, 
     737                     PJSIP_ENOTREQUESTMSG); 
     738 
     739    /* Transaction MUST have been created (in the dialog) */ 
     740    tsx = pjsip_rdata_get_tsx(rdata); 
     741    PJ_ASSERT_RETURN(tsx != NULL, PJSIP_ENOTSX); 
     742 
     743    /* No subscription must have been attached to transaction */ 
     744    PJ_ASSERT_RETURN(tsx->mod_data[mod_evsub.mod.id] == NULL,  
     745                     PJSIP_ETYPEEXISTS); 
     746 
     747    /* Package MUST implement on_rx_refresh */ 
     748    PJ_ASSERT_RETURN(user_cb->on_rx_refresh, PJ_EINVALIDOP); 
     749 
     750    /* Request MUST have "Event" header: */ 
     751 
     752    event_hdr = (pjsip_event_hdr*)  
     753        pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &STR_EVENT, NULL); 
     754    if (event_hdr == NULL) { 
     755        return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_BAD_REQUEST); 
     756    } 
     757 
     758    /* Start locking the mutex: */ 
     759 
     760    pjsip_dlg_inc_lock(dlg); 
     761 
     762    /* Create the session: */ 
     763 
     764    status = evsub_create(dlg, PJSIP_UAS_ROLE, user_cb,  
     765                          &event_hdr->event_type, &sub); 
     766    if (status != PJ_SUCCESS) 
     767        goto on_return; 
     768 
     769    /* Just duplicate Event header from the request */ 
     770    sub->event = pjsip_hdr_clone(sub->pool, event_hdr); 
     771 
     772    /* Set the method: */ 
     773    pjsip_method_copy(sub->pool, &sub->method,  
     774                      &rdata->msg_info.msg->line.req.method); 
     775 
     776    /* Update expiration time according to client request: */ 
     777 
     778    expires_hdr = (pjsip_expires_hdr*) 
     779        pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL); 
     780    if (expires_hdr) { 
     781        sub->expires->ivalue = expires_hdr->ivalue; 
     782    } 
     783 
     784    /* Update time. */ 
     785    update_expires(sub, sub->expires->ivalue); 
     786 
     787    /* Update Accept header: */ 
     788 
     789    accept_hdr = (pjsip_accept_hdr*) 
     790        pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_ACCEPT, NULL); 
     791    if (accept_hdr) 
     792        sub->accept = pjsip_hdr_clone(sub->pool, accept_hdr); 
     793 
     794    /* We can start the session: */ 
     795 
     796    pjsip_dlg_inc_session(dlg, &mod_evsub.mod); 
     797    sub->pending_tsx++; 
     798    tsx->mod_data[mod_evsub.mod.id] = sub; 
     799 
     800 
     801    /* Done. */ 
     802    *p_evsub = sub; 
     803 
     804 
     805on_return: 
     806    pjsip_dlg_dec_lock(dlg); 
     807    return status; 
     808} 
     809 
     810 
     811/* 
     812 * Get subscription state. 
     813 */ 
     814PJ_DEF(pjsip_evsub_state) pjsip_evsub_get_state(pjsip_evsub *sub) 
     815{ 
     816    return sub->state; 
     817} 
     818 
     819/* 
     820 * Get state name. 
     821 */ 
     822PJ_DEF(const char*) pjsip_evsub_get_state_name(pjsip_evsub *sub) 
     823{ 
     824    return sub->state_str.ptr; 
     825} 
     826 
     827 
     828/* 
     829 * Initiate client subscription 
     830 */ 
     831PJ_DEF(pj_status_t) pjsip_evsub_initiate( pjsip_evsub *sub, 
     832                                          const pjsip_method *method, 
     833                                          pj_int32_t expires, 
     834                                          pjsip_tx_data **p_tdata) 
    481835{ 
    482836    pjsip_tx_data *tdata; 
    483837    pj_status_t status; 
    484     const pjsip_route_hdr *route; 
    485  
    486     pj_assert(sub->role == PJSIP_ROLE_UAC); 
    487     pj_assert(sub->state != PJSIP_EVENT_SUB_STATE_TERMINATED); 
    488     if (sub->role != PJSIP_ROLE_UAC ||  
    489         sub->state == PJSIP_EVENT_SUB_STATE_TERMINATED) 
     838 
     839    PJ_ASSERT_RETURN(sub!=NULL && p_tdata!=NULL, PJ_EINVAL); 
     840 
     841    /* Use SUBSCRIBE if method is not specified */ 
     842    if (method == NULL) 
     843        method = &pjsip_subscribe_method; 
     844 
     845    pjsip_dlg_inc_lock(sub->dlg); 
     846 
     847    /* Update method: */ 
     848    if (sub->state == PJSIP_EVSUB_STATE_NULL) 
     849        pjsip_method_copy(sub->pool, &sub->method, method); 
     850 
     851    status = pjsip_dlg_create_request( sub->dlg, method, -1, &tdata); 
     852    if (status != PJ_SUCCESS) 
     853        goto on_return; 
     854 
     855 
     856    /* Add Event header: */ 
     857    pjsip_msg_add_hdr( tdata->msg, 
     858                       pjsip_hdr_shallow_clone(tdata->pool, sub->event)); 
     859 
     860    /* Update and add expires header: */ 
     861    if (expires >= 0) 
     862        sub->expires->ivalue = expires; 
     863    pjsip_msg_add_hdr( tdata->msg, 
     864                       pjsip_hdr_shallow_clone(tdata->pool, sub->expires)); 
     865 
     866    /* Add Accept header: */ 
     867    pjsip_msg_add_hdr( tdata->msg, 
     868                       pjsip_hdr_shallow_clone(tdata->pool, sub->accept)); 
     869     
     870 
     871    /* Add Allow-Events header: */ 
     872    pjsip_msg_add_hdr( tdata->msg, 
     873                       pjsip_hdr_shallow_clone(tdata->pool,  
     874                                               mod_evsub.allow_events_hdr)); 
     875 
     876    
     877    *p_tdata = tdata; 
     878 
     879 
     880on_return: 
     881 
     882    pjsip_dlg_dec_lock(sub->dlg); 
     883    return status; 
     884} 
     885 
     886 
     887/* 
     888 * Accept incoming subscription request. 
     889 */ 
     890PJ_DEF(pj_status_t) pjsip_evsub_accept( pjsip_evsub *sub, 
     891                                        pjsip_rx_data *rdata, 
     892                                        int st_code, 
     893                                        const pjsip_hdr *hdr_list ) 
     894{ 
     895    pjsip_tx_data *tdata; 
     896    pjsip_transaction *tsx; 
     897    pj_status_t status; 
     898 
     899    /* Check arguments */ 
     900    PJ_ASSERT_RETURN(sub && rdata, PJ_EINVAL); 
     901 
     902    /* Can only be for server subscription: */ 
     903    PJ_ASSERT_RETURN(sub->role == PJSIP_ROLE_UAS, PJ_EINVALIDOP); 
     904 
     905    /* Only expect 2xx status code (for now) */ 
     906    PJ_ASSERT_RETURN(st_code/100 == 2, PJ_EINVALIDOP); 
     907 
     908    /* Subscription MUST have been attached to the transaction. 
     909     * Initial subscription request will be attached on evsub_create_uas(), 
     910     * while subsequent requests will be attached in tsx_state() 
     911     */ 
     912    tsx = pjsip_rdata_get_tsx(rdata); 
     913    PJ_ASSERT_RETURN(tsx->mod_data[mod_evsub.mod.id] != NULL, 
     914                     PJ_EINVALIDOP); 
     915 
     916    /* Lock dialog */ 
     917    pjsip_dlg_inc_lock(sub->dlg); 
     918 
     919    /* Create response: */ 
     920    status = pjsip_dlg_create_response( sub->dlg, rdata, st_code, NULL,  
     921                                        &tdata); 
     922    if (status != PJ_SUCCESS) 
     923        goto on_return; 
     924 
     925 
     926    /* Add expires header: */ 
     927    pjsip_msg_add_hdr( tdata->msg, 
     928                       pjsip_hdr_shallow_clone(tdata->pool, sub->expires)); 
     929 
     930 
     931    /* Send the response: */ 
     932    status = pjsip_dlg_send_response( sub->dlg, tsx, tdata ); 
     933    if (status != PJ_SUCCESS) 
     934        goto on_return; 
     935 
     936 
     937on_return: 
     938 
     939    pjsip_dlg_dec_lock(sub->dlg); 
     940    return status; 
     941} 
     942 
     943 
     944/* 
     945 * Create Subscription-State header based on current server subscription 
     946 * state. 
     947 */ 
     948static pjsip_sub_state_hdr* sub_state_create( pj_pool_t *pool, 
     949                                              pjsip_evsub *sub, 
     950                                              pjsip_evsub_state state, 
     951                                              const pj_str_t *state_str, 
     952                                              const pj_str_t *reason ) 
     953{ 
     954    pjsip_sub_state_hdr *sub_state; 
     955    pj_time_val now, delay; 
     956 
     957    /* Get the remaining time before refresh is required */ 
     958    pj_gettimeofday(&now); 
     959    delay = sub->refresh_time; 
     960    PJ_TIME_VAL_SUB(delay, now); 
     961 
     962    /* Create the Subscription-State header */ 
     963    sub_state = pjsip_sub_state_hdr_create(pool); 
     964 
     965    /* Fill up the header */ 
     966    switch (state) { 
     967    case PJSIP_EVSUB_STATE_SENT: 
     968    case PJSIP_EVSUB_STATE_ACCEPTED: 
     969        pj_assert(!"Invalid state!"); 
     970        /* Treat as pending */ 
     971 
     972    case PJSIP_EVSUB_STATE_PENDING: 
     973        sub_state->sub_state = STR_PENDING; 
     974        sub_state->expires_param = delay.sec; 
     975        break; 
     976 
     977    case PJSIP_EVSUB_STATE_ACTIVE: 
     978        sub_state->sub_state = STR_ACTIVE; 
     979        sub_state->expires_param = delay.sec; 
     980        break; 
     981 
     982    case PJSIP_EVSUB_STATE_TERMINATED: 
     983        sub_state->sub_state = STR_TERMINATED; 
     984        if (reason != NULL) 
     985            pj_strdup(pool, &sub_state->reason_param, reason); 
     986        break; 
     987 
     988    case PJSIP_EVSUB_STATE_UNKNOWN: 
     989        pj_assert(state_str != NULL); 
     990        pj_strdup(pool, &sub_state->sub_state, state_str); 
     991        break; 
     992    } 
     993     
     994    return sub_state; 
     995} 
     996 
     997/* 
     998 * Create and send NOTIFY request. 
     999 */ 
     1000PJ_DEF(pj_status_t) pjsip_evsub_notify( pjsip_evsub *sub, 
     1001                                        pjsip_evsub_state state, 
     1002                                        const pj_str_t *state_str, 
     1003                                        const pj_str_t *reason, 
     1004                                        pjsip_tx_data **p_tdata) 
     1005{ 
     1006    pjsip_tx_data *tdata; 
     1007    pjsip_sub_state_hdr *sub_state; 
     1008    pj_status_t status; 
     1009 
     1010    /* Check arguments. */ 
     1011    PJ_ASSERT_RETURN(sub!=NULL && p_tdata!=NULL, PJ_EINVAL); 
     1012 
     1013    /* Lock dialog. */ 
     1014    pjsip_dlg_inc_lock(sub->dlg); 
     1015 
     1016    /* Create NOTIFY request */ 
     1017    status = pjsip_dlg_create_request( sub->dlg, &pjsip_notify_method, -1,  
     1018                                       &tdata); 
     1019    if (status != PJ_SUCCESS) 
     1020        goto on_return; 
     1021 
     1022    /* Add Event header */ 
     1023    pjsip_msg_add_hdr(tdata->msg, 
     1024                      pjsip_hdr_shallow_clone(tdata->pool, sub->event)); 
     1025 
     1026    /* Add Subscription-State header */ 
     1027    sub_state = sub_state_create(tdata->pool, sub, state, state_str, 
     1028                                 reason); 
     1029    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)sub_state); 
     1030 
     1031    /* Add Allow-Events header */ 
     1032    pjsip_msg_add_hdr(tdata->msg, 
     1033                      pjsip_hdr_shallow_clone(tdata->pool, mod_evsub.allow_events_hdr)); 
     1034 
     1035    /* Add Authentication headers. */ 
     1036    pjsip_auth_clt_init_req( &sub->dlg->auth_sess, tdata ); 
     1037 
     1038     
     1039 
     1040    /* Save destination state. */ 
     1041    sub->dst_state = state; 
     1042    if (state_str) 
     1043        pj_strdup(sub->pool, &sub->dst_state_str, state_str); 
     1044    else 
     1045        sub->dst_state_str.slen = 0; 
     1046 
     1047 
     1048    *p_tdata = tdata; 
     1049 
     1050on_return: 
     1051    /* Unlock dialog */ 
     1052    pjsip_dlg_dec_lock(sub->dlg); 
     1053    return status; 
     1054} 
     1055 
     1056 
     1057/* 
     1058 * Create NOTIFY to reflect current status. 
     1059 */ 
     1060PJ_DEF(pj_status_t) pjsip_evsub_current_notify( pjsip_evsub *sub, 
     1061                                                pjsip_tx_data **p_tdata ) 
     1062{ 
     1063    return pjsip_evsub_notify( sub, sub->state, &sub->state_str,  
     1064                               NULL, p_tdata ); 
     1065} 
     1066 
     1067 
     1068/* 
     1069 * Send request. 
     1070 */ 
     1071PJ_DEF(pj_status_t) pjsip_evsub_send_request( pjsip_evsub *sub, 
     1072                                              pjsip_tx_data *tdata) 
     1073{ 
     1074    pj_status_t status; 
     1075 
     1076    /* Must be request message. */ 
     1077    PJ_ASSERT_RETURN(tdata->msg->type == PJSIP_REQUEST_MSG, 
     1078                     PJSIP_ENOTREQUESTMSG); 
     1079 
     1080    /* Lock */ 
     1081    pjsip_dlg_inc_lock(sub->dlg); 
     1082 
     1083    /* Send the request. */ 
     1084    status = pjsip_dlg_send_request(sub->dlg, tdata, NULL); 
     1085    if (status != PJ_SUCCESS) 
     1086        goto on_return; 
     1087 
     1088 
     1089    /* Special case for NOTIFY: 
     1090     * The new state was set in pjsip_evsub_notify(), but we apply the 
     1091     * new state now, when the request was actually sent. 
     1092     */ 
     1093    if (pjsip_method_cmp(&tdata->msg->line.req.method,  
     1094                         &pjsip_notify_method)==0)  
    4901095    { 
    491         return -1; 
    492     } 
    493  
    494     PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): refreshing subscription",  
    495                          sub, state[sub->state].ptr)); 
    496  
    497     /* Create request. */ 
    498     tdata = pjsip_endpt_create_request_from_hdr( sub->endpt,  
    499                                                  &SUBSCRIBE, 
    500                                                  sub->to->uri, 
    501                                                  sub->from, sub->to,  
    502                                                  sub->contact, sub->call_id, 
    503                                                  sub->cseq++, 
    504                                                  NULL); 
    505  
    506     if (!tdata) { 
    507         PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): refresh: unable to create tx data!", 
    508                              sub, state[sub->state].ptr)); 
    509         return -1; 
    510     } 
    511  
    512     pjsip_msg_add_hdr( tdata->msg,  
    513                        pjsip_hdr_shallow_clone(tdata->pool, sub->event)); 
    514     pjsip_msg_add_hdr( tdata->msg,  
    515                        pjsip_hdr_shallow_clone(tdata->pool, sub->uac_expires)); 
    516     pjsip_msg_add_hdr( tdata->msg,  
    517                        pjsip_hdr_shallow_clone(tdata->pool, sub->local_accept)); 
    518     pjsip_msg_add_hdr( tdata->msg,  
    519                        pjsip_hdr_shallow_clone(tdata->pool, mgr.allow_events)); 
    520  
    521     /* Authentication */ 
    522     pjsip_auth_init_req( sub->pool, tdata, &sub->auth_sess, 
    523                          sub->cred_cnt, sub->cred_info); 
    524  
    525     /* Route set. */ 
    526     route = sub->route_set.next; 
    527     while (route != &sub->route_set) { 
    528         pj_list_insert_before( &tdata->msg->hdr, 
    529                                pjsip_hdr_shallow_clone(tdata->pool, route)); 
    530         route = route->next; 
    531     } 
    532  
    533     /* Send */ 
    534     status = pjsip_endpt_send_request( sub->endpt, tdata, -1, sub,  
    535                                        &on_subscribe_response); 
    536     if (status == 0) { 
    537         sub->pending_tsx++; 
     1096        PJ_ASSERT_ON_FAIL(  sub->dst_state!=PJSIP_EVSUB_STATE_NULL, 
     1097                            {goto on_return;}); 
     1098 
     1099        set_state(sub, sub->dst_state,  
     1100                  (sub->dst_state_str.slen ? &sub->dst_state_str : NULL),  
     1101                  NULL); 
     1102 
     1103        sub->dst_state = PJSIP_EVSUB_STATE_NULL; 
     1104        sub->dst_state_str.slen = 0; 
     1105 
     1106    } 
     1107 
     1108 
     1109on_return: 
     1110    pjsip_dlg_dec_lock(sub->dlg); 
     1111    return status; 
     1112} 
     1113 
     1114 
     1115 
     1116/* 
     1117 * Attach subscription session to newly created transaction, if appropriate. 
     1118 */ 
     1119static pjsip_evsub *on_new_transaction( pjsip_transaction *tsx, 
     1120                                        pjsip_event *event) 
     1121{ 
     1122    /* 
     1123     * Newly created transaction will not have subscription session 
     1124     * attached to it. Find the subscription session from the dialog, 
     1125     * by matching the Event header. 
     1126     */ 
     1127    pjsip_dialog *dlg; 
     1128    pjsip_event_hdr *event_hdr; 
     1129    pjsip_msg *msg; 
     1130    struct dlgsub *dlgsub_head, *dlgsub; 
     1131    pjsip_evsub *sub; 
     1132     
     1133    dlg = pjsip_tsx_get_dlg(tsx); 
     1134    if (!dlg) { 
     1135        pj_assert(!"Transaction should have a dialog instance!"); 
     1136        return NULL; 
     1137    } 
     1138 
     1139    switch (event->body.tsx_state.type) { 
     1140    case PJSIP_EVENT_RX_MSG: 
     1141        msg = event->body.tsx_state.src.rdata->msg_info.msg; 
     1142        break; 
     1143    case PJSIP_EVENT_TX_MSG: 
     1144        msg = event->body.tsx_state.src.tdata->msg; 
     1145        break; 
     1146    default: 
     1147        if (tsx->role == PJSIP_ROLE_UAC) 
     1148            msg = tsx->last_tx->msg; 
     1149        else 
     1150            msg = NULL; 
     1151        break; 
     1152    } 
     1153     
     1154    if (!msg) { 
     1155        pj_assert(!"First transaction event is not TX or RX!"); 
     1156        return NULL; 
     1157    } 
     1158 
     1159    event_hdr = pjsip_msg_find_hdr_by_name(msg, &STR_EVENT, NULL); 
     1160    if (!event_hdr) { 
     1161        /* Not subscription related message */ 
     1162        return NULL; 
     1163    } 
     1164 
     1165    /* Find the subscription in the dialog, based on the content 
     1166     * of Event header:  
     1167     */ 
     1168 
     1169    dlgsub_head = dlg->mod_data[mod_evsub.mod.id]; 
     1170    if (dlgsub_head == NULL) { 
     1171        dlgsub_head = pj_pool_alloc(dlg->pool, sizeof(struct dlgsub)); 
     1172        pj_list_init(dlgsub_head); 
     1173        dlg->mod_data[mod_evsub.mod.id] = dlgsub_head; 
     1174    } 
     1175    dlgsub = dlgsub_head->next; 
     1176 
     1177    while (dlgsub != dlgsub_head) { 
     1178 
     1179        /* Match event type and Id */ 
     1180        if (pj_strcmp(&dlgsub->sub->event->id_param, &event_hdr->id_param)==0 && 
     1181            pj_stricmp(&dlgsub->sub->event->event_type, &event_hdr->event_type)==0) 
     1182        { 
     1183            break; 
     1184        } 
     1185        dlgsub = dlgsub->next; 
     1186    } 
     1187 
     1188    if (dlgsub == dlgsub_head) { 
     1189        /* This could be incoming request to create new subscription */ 
     1190        PJ_LOG(4,(THIS_FILE,  
     1191                  "Subscription not found for %.*s, event=%.*s;id=%.*s", 
     1192                  (int)event_hdr->event_type.slen, 
     1193                  event_hdr->event_type.ptr, 
     1194                  (int)event_hdr->id_param.slen, 
     1195                  event_hdr->id_param.ptr)); 
     1196 
     1197        /* If this is an incoming NOTIFY, reject with 481 */ 
     1198        if (tsx->state == PJSIP_TSX_STATE_TRYING && 
     1199            pjsip_method_cmp(&tsx->method, &pjsip_notify_method)==0) 
     1200        { 
     1201            pj_str_t reason = pj_str("Subscription Does Not Exist"); 
     1202            pjsip_tx_data *tdata; 
     1203            pj_status_t status; 
     1204 
     1205            status = pjsip_dlg_create_response(dlg,  
     1206                                               event->body.tsx_state.src.rdata,  
     1207                                               481, &reason,  
     1208                                               &tdata); 
     1209            if (status == PJ_SUCCESS) { 
     1210                status = pjsip_dlg_send_response(dlg, tsx, tdata); 
     1211            } 
     1212        } 
     1213        return NULL; 
     1214    } 
     1215 
     1216    /* Found! */ 
     1217    sub = dlgsub->sub; 
     1218 
     1219    /* Attach session to the transaction */ 
     1220    tsx->mod_data[mod_evsub.mod.id] = sub; 
     1221    sub->pending_tsx++; 
     1222 
     1223    return sub; 
     1224} 
     1225 
     1226 
     1227/* 
     1228 * Create response, adding custome headers and msg body. 
     1229 */ 
     1230static pj_status_t create_response( pjsip_evsub *sub, 
     1231                                    pjsip_rx_data *rdata, 
     1232                                    int st_code, 
     1233                                    const pj_str_t *st_text, 
     1234                                    const pjsip_hdr *res_hdr, 
     1235                                    const pjsip_msg_body *body, 
     1236                                    pjsip_tx_data **p_tdata) 
     1237{ 
     1238    pjsip_tx_data *tdata; 
     1239    pjsip_hdr *hdr; 
     1240    pj_status_t status; 
     1241 
     1242    status = pjsip_dlg_create_response(sub->dlg, rdata, 
     1243                                       st_code, st_text, &tdata); 
     1244    if (status != PJ_SUCCESS) 
     1245        return status; 
     1246 
     1247    *p_tdata = tdata; 
     1248 
     1249    /* Add response headers. */ 
     1250    hdr = res_hdr->next; 
     1251    while (hdr != res_hdr) { 
     1252        pjsip_msg_add_hdr( tdata->msg,  
     1253                           pjsip_hdr_clone(tdata->pool, hdr)); 
     1254        hdr = hdr->next; 
     1255    } 
     1256 
     1257    /* Add msg body, if any */ 
     1258    if (body) { 
     1259        tdata->msg->body = pj_pool_zalloc(tdata->pool,  
     1260                                          sizeof(pjsip_msg_body)); 
     1261        status = pjsip_msg_body_clone(tdata->pool,  
     1262                                      tdata->msg->body,  
     1263                                      body); 
     1264        if (status != PJ_SUCCESS) { 
     1265            tdata->msg->body = NULL; 
     1266            /* Ignore */ 
     1267            return PJ_SUCCESS; 
     1268        } 
     1269    } 
     1270 
     1271    return PJ_SUCCESS; 
     1272} 
     1273 
     1274/* 
     1275 * Get subscription state from the value of Subscription-State header. 
     1276 */ 
     1277static void get_hdr_state( pjsip_sub_state_hdr *sub_state, 
     1278                           pjsip_evsub_state *state, 
     1279                           pj_str_t **state_str ) 
     1280{ 
     1281    if (pj_stricmp(&sub_state->sub_state, &STR_TERMINATED)==0) { 
     1282 
     1283        *state = PJSIP_EVSUB_STATE_TERMINATED; 
     1284        *state_str = NULL; 
     1285 
     1286    } else if (pj_stricmp(&sub_state->sub_state, &STR_ACTIVE)==0) { 
     1287 
     1288        *state = PJSIP_EVSUB_STATE_ACTIVE; 
     1289        *state_str = NULL; 
     1290 
     1291    } else if (pj_stricmp(&sub_state->sub_state, &STR_PENDING)==0) { 
     1292 
     1293        *state = PJSIP_EVSUB_STATE_PENDING; 
     1294        *state_str = NULL; 
     1295 
    5381296    } else { 
    539         PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): FAILED to refresh subscription!",  
    540                              sub, state[sub->state].ptr)); 
    541     } 
    542  
    543     return status; 
    544 } 
    545  
    546 /* 
    547  * Stop subscription. 
    548  */ 
    549 PJ_DEF(pj_status_t) pjsip_event_sub_unsubscribe( pjsip_event_sub *sub ) 
    550 { 
    551     pjsip_tx_data *tdata; 
    552     const pjsip_route_hdr *route; 
    553     pj_status_t status; 
    554  
    555     PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): unsubscribing...",  
    556                          sub, state[sub->state].ptr)); 
    557  
    558     /* Lock subscription. */ 
    559     pj_mutex_lock(sub->mutex); 
    560  
    561     pj_assert(sub->role == PJSIP_ROLE_UAC); 
    562  
    563     /* Kill refresh timer, if any. */ 
    564     if (sub->timer.id != 0) { 
    565         sub->timer.id = 0; 
    566         pjsip_endpt_cancel_timer(sub->endpt, &sub->timer); 
    567     } 
    568  
    569     /* Create request. */ 
    570     tdata = pjsip_endpt_create_request_from_hdr( sub->endpt,  
    571                                                  &SUBSCRIBE, 
    572                                                  sub->to->uri, 
    573                                                  sub->from, sub->to,  
    574                                                  sub->contact, sub->call_id, 
    575                                                  sub->cseq++, 
    576                                                  NULL); 
    577  
    578     if (!tdata) { 
    579         pj_mutex_unlock(sub->mutex); 
    580         return -1; 
    581     } 
    582  
    583     /* Add headers to request. */ 
    584     pjsip_msg_add_hdr( tdata->msg, pjsip_hdr_shallow_clone(tdata->pool, sub->event)); 
    585     sub->uac_expires->ivalue = 0; 
    586     pjsip_msg_add_hdr( tdata->msg, pjsip_hdr_shallow_clone(tdata->pool, sub->uac_expires)); 
    587  
    588     /* Add authentication. */ 
    589     pjsip_auth_init_req( sub->pool, tdata, &sub->auth_sess, 
    590                          sub->cred_cnt, sub->cred_info); 
    591  
    592  
    593     /* Route set. */ 
    594     route = sub->route_set.next; 
    595     while (route != &sub->route_set) { 
    596         pj_list_insert_before( &tdata->msg->hdr, 
    597                                pjsip_hdr_shallow_clone(tdata->pool, route)); 
    598         route = route->next; 
    599     } 
    600  
    601     /* Prevent timer from refreshing itself. */ 
    602     sub->default_interval = 0; 
    603  
    604     /* Set state. */ 
    605     sub_set_state( sub, PJSIP_EVENT_SUB_STATE_TERMINATED ); 
    606  
    607     /* Send the request. */ 
    608     status = pjsip_endpt_send_request( sub->endpt, tdata, -1, sub,  
    609                                        &on_subscribe_response); 
    610     if (status == 0) { 
    611         sub->pending_tsx++; 
    612     } 
    613  
    614     pj_mutex_unlock(sub->mutex); 
    615  
    616     if (status != 0) { 
    617         PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): FAILED to unsubscribe!",  
    618                              sub, state[sub->state].ptr)); 
    619     } 
    620  
    621     return status; 
    622 } 
    623  
    624 /* 
    625  * Send notify. 
    626  */ 
    627 PJ_DEF(pj_status_t) pjsip_event_sub_notify(pjsip_event_sub *sub, 
    628                                            pjsip_event_sub_state new_state, 
    629                                            const pj_str_t *reason, 
    630                                            pjsip_msg_body *body) 
    631 { 
    632     pjsip_tx_data *tdata; 
    633     pjsip_sub_state_hdr *ss_hdr; 
    634     const pjsip_route_hdr *route; 
    635     pj_time_val now; 
    636     pj_status_t status; 
    637     pjsip_event_sub_state old_state = sub->state; 
    638  
    639     pj_gettimeofday(&now); 
    640  
    641     pj_assert(sub->role == PJSIP_ROLE_UAS); 
    642     if (sub->role != PJSIP_ROLE_UAS) 
    643         return -1; 
    644  
    645     PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): sending NOTIFY",  
    646                          sub, state[new_state].ptr)); 
    647  
    648     /* Lock subscription. */ 
    649     pj_mutex_lock(sub->mutex); 
    650  
    651     /* Can not send NOTIFY if current state is NULL. We can accept TERMINATED. */ 
    652     if (sub->state==PJSIP_EVENT_SUB_STATE_NULL) { 
    653         pj_assert(0); 
    654         pj_mutex_unlock(sub->mutex); 
    655         return -1; 
    656     } 
    657  
    658     /* Update state no matter what. */ 
    659     sub_set_state(sub, new_state); 
    660  
    661     /* Create transmit data. */ 
    662     tdata = pjsip_endpt_create_request_from_hdr( sub->endpt, 
    663                                                  &NOTIFY, 
    664                                                  sub->to->uri, 
    665                                                  sub->from, sub->to, 
    666                                                  sub->contact, sub->call_id, 
    667                                                  sub->cseq++, 
    668                                                  NULL); 
    669     if (!tdata) { 
    670         pj_mutex_unlock(sub->mutex); 
    671         return -1; 
    672     } 
    673  
    674     /* Add Event header. */ 
    675     pjsip_msg_add_hdr(tdata->msg, pjsip_hdr_shallow_clone(tdata->pool, sub->event)); 
    676  
    677     /* Add Subscription-State header. */ 
    678     ss_hdr = pjsip_sub_state_hdr_create(tdata->pool); 
    679     ss_hdr->sub_state = state[new_state]; 
    680     ss_hdr->expires_param = sub->expiry_time.sec - now.sec; 
    681     if (ss_hdr->expires_param < 0) 
    682         ss_hdr->expires_param = 0; 
    683     if (reason) 
    684         pj_strdup(tdata->pool, &ss_hdr->reason_param, reason); 
    685     pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)ss_hdr); 
    686  
    687     /* Add Allow-Events header. */ 
    688     pjsip_msg_add_hdr( tdata->msg,  
    689                        pjsip_hdr_shallow_clone(tdata->pool, mgr.allow_events)); 
    690  
    691     /* Add authentication */ 
    692     pjsip_auth_init_req( sub->pool, tdata, &sub->auth_sess, 
    693                          sub->cred_cnt, sub->cred_info); 
    694  
    695     /* Route set. */ 
    696     route = sub->route_set.next; 
    697     while (route != &sub->route_set) { 
    698         pj_list_insert_before( &tdata->msg->hdr, 
    699                                pjsip_hdr_shallow_clone(tdata->pool, route)); 
    700         route = route->next; 
    701     } 
    702  
    703     /* Attach body. */ 
    704     tdata->msg->body = body; 
    705  
    706     /* That's it, send! */ 
    707     status = pjsip_endpt_send_request( sub->endpt, tdata, -1, sub, &on_notify_response); 
    708     if (status == 0) 
    709         sub->pending_tsx++; 
    710  
    711     /* If terminated notify application. */ 
    712     if (new_state!=old_state && new_state==PJSIP_EVENT_SUB_STATE_TERMINATED) { 
    713         if (sub->cb.on_sub_terminated) { 
    714             sub->pending_tsx++; 
    715             (*sub->cb.on_sub_terminated)(sub, reason); 
    716             sub->pending_tsx--; 
    717         } 
    718     } 
    719  
    720     /* Unlock subscription. */ 
    721     pj_mutex_unlock(sub->mutex); 
    722  
    723     if (status != 0) { 
    724         PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): failed to send NOTIFY",  
    725                              sub, state[sub->state].ptr)); 
    726     } 
    727  
    728     if (sub->delete_flag && sub->pending_tsx <= 0) { 
    729         pjsip_event_sub_destroy(sub); 
    730     } 
    731     return status; 
    732 } 
    733  
    734  
    735 /* If this timer callback is called, it means subscriber hasn't refreshed its 
    736  * subscription on-time. Set the state to terminated. This will also send 
    737  * NOTIFY with Subscription-State set to terminated. 
    738  */ 
    739 static void uas_expire_timer_cb( pj_timer_heap_t *timer_heap, pj_timer_entry *entry) 
    740 { 
    741     pjsip_event_sub *sub = entry->user_data; 
    742     pj_str_t reason = { "timeout", 7 }; 
    743  
    744     PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): UAS subscription expired!",  
    745                          sub, state[sub->state].ptr)); 
    746  
    747     pj_mutex_lock(sub->mutex); 
    748     sub->timer.id = 0; 
    749  
    750     if (sub->cb.on_sub_terminated && sub->state!=PJSIP_EVENT_SUB_STATE_TERMINATED) { 
    751         /* Notify application, but prevent app from destroying the sub. */ 
    752         ++sub->pending_tsx; 
    753         (*sub->cb.on_sub_terminated)(sub, &reason); 
    754         --sub->pending_tsx; 
    755     } 
    756     //pjsip_event_sub_notify( sub, PJSIP_EVENT_SUB_STATE_TERMINATED,  
    757     //                      &reason, NULL); 
    758     pj_mutex_unlock(sub->mutex); 
    759  
    760 } 
    761  
    762 /* Schedule notifier expiration. */ 
    763 static void sub_schedule_uas_expire( pjsip_event_sub *sub, int sec_delay) 
    764 { 
    765     pj_time_val delay = { 0, 0 }; 
    766     pj_parsed_time pt; 
    767  
    768     if (sub->timer.id != 0) 
    769         pjsip_endpt_cancel_timer(sub->endpt, &sub->timer); 
    770  
    771     pj_gettimeofday(&sub->expiry_time); 
    772     sub->expiry_time.sec += sec_delay; 
    773  
    774     sub->timer.id = TIMER_ID_UAS_EXPIRY; 
    775     sub->timer.user_data = sub; 
    776     sub->timer.cb = &uas_expire_timer_cb; 
    777     delay.sec = sec_delay; 
    778     pjsip_endpt_schedule_timer( sub->endpt, &sub->timer, &delay); 
    779  
    780     pj_time_decode(&sub->expiry_time, &pt); 
    781     PJ_LOG(4,(THIS_FILE,  
    782               "event_sub%p (%s)(UAS): will expire at %02d:%02d:%02d (in %d secs)", 
    783               sub, state[sub->state].ptr, pt.hour, pt.min, pt.sec, sec_delay)); 
    784 } 
    785  
    786 /* This timer is called for UAC to refresh the subscription. */ 
    787 static void refresh_timer_cb( pj_timer_heap_t *timer_heap, pj_timer_entry *entry) 
    788 { 
    789     pjsip_event_sub *sub = entry->user_data; 
    790  
    791     PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): refresh subscription timer",  
    792                          sub, state[sub->state].ptr)); 
    793  
    794     pj_mutex_lock(sub->mutex); 
    795     sub->timer.id = 0; 
    796     send_sub_refresh(sub); 
    797     pj_mutex_unlock(sub->mutex); 
    798 } 
    799  
    800  
    801 /* This will update the UAC's refresh schedule. */ 
    802 static void update_next_refresh(pjsip_event_sub *sub, int interval) 
    803 { 
    804     pj_time_val delay = {0, 0}; 
    805     pj_parsed_time pt; 
    806  
    807     if (interval < SECONDS_BEFORE_EXPIRY) { 
    808         PJ_LOG(4,(THIS_FILE,  
    809                   "event_sub%p (%s): expiration delay too short (%d sec)! updated.", 
    810                   sub, state[sub->state].ptr, interval)); 
    811         interval = SECONDS_BEFORE_EXPIRY; 
    812     } 
    813  
    814     if (sub->timer.id != 0) 
    815         pjsip_endpt_cancel_timer(sub->endpt, &sub->timer); 
    816  
    817     sub->timer.id = TIMER_ID_REFRESH; 
    818     sub->timer.user_data = sub; 
    819     sub->timer.cb = &refresh_timer_cb; 
    820     pj_gettimeofday(&sub->expiry_time); 
    821     delay.sec = interval - SECONDS_BEFORE_EXPIRY; 
    822     sub->expiry_time.sec += delay.sec; 
    823  
    824     pj_time_decode(&sub->expiry_time, &pt); 
    825     PJ_LOG(4,(THIS_FILE,  
    826               "event_sub%p (%s): will send SUBSCRIBE at %02d:%02d:%02d (in %d secs)", 
    827               sub, state[sub->state].ptr,  
    828               pt.hour, pt.min, pt.sec, 
    829               delay.sec)); 
    830  
    831     pjsip_endpt_schedule_timer( sub->endpt, &sub->timer, &delay ); 
    832 } 
    833  
    834  
    835 /* Find subscription in the hash table.  
    836  * If found, lock the subscription before returning to caller. 
    837  */ 
    838 static pjsip_event_sub *find_sub(pjsip_rx_data *rdata) 
    839 { 
    840     pj_str_t key; 
    841     pjsip_role_e role; 
    842     pjsip_event_sub *sub; 
    843     pjsip_method *method = &rdata->msg->line.req.method; 
    844     pj_str_t *tag; 
    845  
    846     if (rdata->msg->type == PJSIP_REQUEST_MSG) { 
    847         if (pjsip_method_cmp(method, &SUBSCRIBE)==0) { 
    848             role = PJSIP_ROLE_UAS; 
    849             tag = &rdata->to_tag; 
    850         } else { 
    851             pj_assert(pjsip_method_cmp(method, &NOTIFY) == 0); 
    852             role = PJSIP_ROLE_UAC; 
    853             tag = &rdata->to_tag; 
    854         } 
    855     } else { 
    856         if (pjsip_method_cmp(&rdata->cseq->method, &SUBSCRIBE)==0) { 
    857             role = PJSIP_ROLE_UAC; 
    858             tag = &rdata->from_tag; 
    859         } else { 
    860             pj_assert(pjsip_method_cmp(method, &NOTIFY) == 0); 
    861             role = PJSIP_ROLE_UAS; 
    862             tag = &rdata->from_tag; 
    863         } 
    864     } 
    865     create_subscriber_key( &key, rdata->pool, role, &rdata->call_id, tag); 
    866  
    867     pj_mutex_lock(mgr.mutex); 
    868     sub = pj_hash_get(mgr.ht, key.ptr, key.slen); 
    869     if (sub) 
    870         pj_mutex_lock(sub->mutex); 
    871     pj_mutex_unlock(mgr.mutex); 
    872  
    873     return sub; 
    874 } 
    875  
    876  
    877 /* This function is called when we receive SUBSCRIBE request message  
    878  * to refresh existing subscription. 
    879  */ 
    880 static void on_received_sub_refresh( pjsip_event_sub *sub,  
    881                                      pjsip_transaction *tsx, pjsip_rx_data *rdata) 
    882 { 
    883     pjsip_event_hdr *e; 
    884     pjsip_expires_hdr *expires; 
    885     pj_str_t hname; 
    886     int status = 200; 
    887     pj_str_t reason_phrase = { NULL, 0 }; 
    888     int new_state = sub->state; 
    889     int old_state = sub->state; 
    890     int new_interval = 0; 
    891     pjsip_tx_data *tdata; 
    892  
    893     PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): received target refresh",  
    894                          sub, state[sub->state].ptr)); 
    895  
    896     /* Check that the event matches. */ 
    897     hname = pj_str("Event"); 
    898     e = pjsip_msg_find_hdr_by_name( rdata->msg, &hname, NULL); 
    899     if (!e) { 
    900         status = 400; 
    901         reason_phrase = pj_str("Missing Event header"); 
    902         goto send_response; 
    903     } 
    904     if (pj_stricmp(&e->event_type, &sub->event->event_type) != 0 || 
    905         pj_stricmp(&e->id_param, &sub->event->id_param) != 0) 
    906     { 
    907         status = 481; 
    908         reason_phrase = pj_str("Subscription does not exist"); 
    909         goto send_response; 
    910     } 
    911  
    912     /* Check server state. */ 
    913     if (sub->state == PJSIP_EVENT_SUB_STATE_TERMINATED) { 
    914         status = 481; 
    915         reason_phrase = pj_str("Subscription does not exist"); 
    916         goto send_response; 
    917     } 
    918  
    919     /* Check expires header. */ 
    920     expires = pjsip_msg_find_hdr(rdata->msg, PJSIP_H_EXPIRES, NULL); 
    921     if (!expires) { 
    922         /* 
    923         status = 400; 
    924         reason_phrase = pj_str("Missing Expires header"); 
    925         goto send_response; 
    926         */ 
    927         new_interval = sub->default_interval; 
    928     } else { 
    929         /* Check that interval is not too short.  
    930          * Note that expires time may be zero (for unsubscription). 
     1297 
     1298        *state = PJSIP_EVSUB_STATE_UNKNOWN; 
     1299        *state_str = &sub_state->sub_state; 
     1300 
     1301    } 
     1302} 
     1303 
     1304/* 
     1305 * Transaction event processing by UAC, after subscription is sent. 
     1306 */ 
     1307static void on_tsx_state_uac( pjsip_evsub *sub, pjsip_transaction *tsx, 
     1308                              pjsip_event *event ) 
     1309{ 
     1310 
     1311    if (pjsip_method_cmp(&tsx->method, &sub->method)==0) { 
     1312 
     1313        /* Received response to outgoing request that establishes/refresh 
     1314         * subscription.  
    9311315         */ 
    932         new_interval = expires->ivalue; 
    933         if (new_interval != 0 && new_interval < SECONDS_BEFORE_EXPIRY) { 
    934             status = PJSIP_SC_INTERVAL_TOO_BRIEF; 
    935             goto send_response; 
    936         } 
    937     } 
    938  
    939     /* Update interval. */ 
    940     sub->default_interval = new_interval; 
    941     pj_gettimeofday(&sub->expiry_time); 
    942     sub->expiry_time.sec += new_interval; 
    943  
    944     /* Update timer only if this is not unsubscription. */ 
    945     if (new_interval > 0) { 
    946         sub->default_interval = new_interval; 
    947         sub_schedule_uas_expire( sub, new_interval ); 
    948  
    949         /* Call callback. */ 
    950         if (sub->cb.on_received_refresh) { 
    951             sub->pending_tsx++; 
    952             (*sub->cb.on_received_refresh)(sub, rdata); 
    953             sub->pending_tsx--; 
    954         } 
    955     } 
    956  
    957 send_response: 
    958     tdata = pjsip_endpt_create_response( sub->endpt, rdata, status); 
    959     if (tdata) { 
    960         if (reason_phrase.slen) 
    961             tdata->msg->line.status.reason = reason_phrase; 
    962  
    963         /* Add Expires header. */ 
    964         expires = pjsip_expires_hdr_create(tdata->pool); 
    965         expires->ivalue = sub->default_interval; 
    966         pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)expires); 
    967  
    968         if (PJSIP_IS_STATUS_IN_CLASS(status,200)) { 
    969             pjsip_msg_add_hdr(tdata->msg,  
    970                               pjsip_hdr_shallow_clone(tdata->pool, mgr.allow_events)); 
    971         } 
    972         /* Send down to transaction. */ 
    973         pjsip_tsx_on_tx_msg(tsx, tdata); 
    974     } 
    975  
    976     if (sub->default_interval==0 || !PJSIP_IS_STATUS_IN_CLASS(status,200)) { 
    977         /* Notify application if sub is terminated. */ 
    978         new_state = PJSIP_EVENT_SUB_STATE_TERMINATED; 
    979         sub_set_state(sub, new_state); 
    980         if (new_state!=old_state && sub->cb.on_sub_terminated) { 
    981             pj_str_t reason = {"", 0}; 
    982             if (reason_phrase.slen) reason = reason_phrase; 
    983             else reason = *pjsip_get_status_text(status); 
    984  
    985             sub->pending_tsx++; 
    986             (*sub->cb.on_sub_terminated)(sub, &reason); 
    987             sub->pending_tsx--; 
    988         } 
    989     } 
    990  
    991     pj_mutex_unlock(sub->mutex); 
    992  
    993     /* Prefer to call log when we're not holding the mutex. */ 
    994     PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): sent refresh response %s, status=%d",  
    995                          sub, state[sub->state].ptr, 
    996                          (tdata ? tdata->obj_name : "null"), status)); 
    997  
    998     /* Check if application has requested deletion. */ 
    999     if (sub->delete_flag && sub->pending_tsx <= 0) { 
    1000         pjsip_event_sub_destroy(sub); 
    1001     } 
    1002  
    1003 } 
    1004  
    1005  
    1006 /* This function is called when we receive SUBSCRIBE request message for  
    1007  * a new subscription. 
    1008  */ 
    1009 static void on_new_subscription( pjsip_transaction *tsx, pjsip_rx_data *rdata ) 
    1010 { 
    1011     package *pkg; 
    1012     pj_pool_t *pool; 
    1013     pjsip_event_sub *sub = NULL; 
    1014     pj_str_t hname; 
    1015     int status = 200; 
    1016     pj_str_t reason = { NULL, 0 }; 
    1017     pjsip_tx_data *tdata; 
    1018     pjsip_expires_hdr *expires; 
    1019     pjsip_accept_hdr *accept; 
    1020     pjsip_event_hdr *evhdr; 
    1021  
    1022     /* Get the Event header. */ 
    1023     hname = pj_str("Event"); 
    1024     evhdr = pjsip_msg_find_hdr_by_name(rdata->msg, &hname, NULL); 
    1025     if (!evhdr) { 
    1026         status = 400; 
    1027         reason = pj_str("No Event header in request"); 
    1028         goto send_response; 
    1029     } 
    1030  
    1031     /* Find corresponding package.  
    1032      * We don't lock the manager's mutex since we assume the package list 
    1033      * won't change once the application is running! 
    1034      */ 
    1035     pkg = mgr.pkg_list.next; 
    1036     while (pkg != &mgr.pkg_list) { 
    1037         if (pj_stricmp(&pkg->event, &evhdr->event_type) == 0) 
    1038             break; 
    1039         pkg = pkg->next; 
    1040     } 
    1041  
    1042     if (pkg == &mgr.pkg_list) { 
    1043         /* Event type is not supported by any packages! */ 
    1044         status = 489; 
    1045         reason = pj_str("Bad Event"); 
    1046         goto send_response; 
    1047     } 
    1048  
    1049     /* First check that the Accept specification matches the  
    1050      * package's Accept types. 
    1051      */ 
    1052     accept = pjsip_msg_find_hdr(rdata->msg, PJSIP_H_ACCEPT, NULL); 
    1053     if (accept) { 
    1054         unsigned i; 
    1055         pj_str_t *content_type = NULL; 
    1056  
    1057         for (i=0; i<accept->count && !content_type; ++i) { 
    1058             int j; 
    1059             for (j=0; j<pkg->accept_cnt; ++j) { 
    1060                 if (pj_stricmp(&accept->values[i], &pkg->accept[j])==0) { 
    1061                     content_type = &pkg->accept[j]; 
    1062                     break; 
     1316 
     1317        /* First time initial request is sent. */ 
     1318        if (sub->state == PJSIP_EVSUB_STATE_NULL && 
     1319            tsx->state == PJSIP_TSX_STATE_CALLING) 
     1320        { 
     1321            set_state(sub, PJSIP_EVSUB_STATE_SENT, NULL, event); 
     1322            return; 
     1323        } 
     1324 
     1325        /* Only interested in final response */ 
     1326        if (tsx->state != PJSIP_TSX_STATE_COMPLETED && 
     1327            tsx->state != PJSIP_TSX_STATE_TERMINATED) 
     1328        { 
     1329            return; 
     1330        } 
     1331 
     1332        /* Handle authentication. */ 
     1333        if (tsx->status_code==401 || tsx->status_code==407) { 
     1334            pjsip_tx_data *tdata; 
     1335            pj_status_t status; 
     1336 
     1337            if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { 
     1338                /* Previously failed transaction has terminated */ 
     1339                return; 
     1340            } 
     1341 
     1342            status = pjsip_auth_clt_reinit_req(&sub->dlg->auth_sess, 
     1343                                               event->body.tsx_state.src.rdata, 
     1344                                               tsx->last_tx, &tdata); 
     1345            if (status == PJ_SUCCESS)  
     1346                status = pjsip_dlg_send_request(sub->dlg, tdata, NULL); 
     1347             
     1348            if (status != PJ_SUCCESS) { 
     1349                /* Authentication failed! */ 
     1350                set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, 
     1351                               NULL, 
     1352                               event); 
     1353                return; 
     1354            } 
     1355 
     1356            return; 
     1357        } 
     1358 
     1359        if (tsx->status_code/100 == 2) { 
     1360 
     1361            /* Successfull SUBSCRIBE request!  
     1362             * This could be: 
     1363             *  - response to initial SUBSCRIBE request 
     1364             *  - response to subsequent refresh 
     1365             *  - response to unsubscription 
     1366             */ 
     1367 
     1368            if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { 
     1369                /* Ignore; this transaction has been processed before */ 
     1370                return; 
     1371            } 
     1372 
     1373            /* Update UAC refresh time, if response contains Expires header, 
     1374             * only when we're not unsubscribing.  
     1375             */ 
     1376            if (sub->expires->ivalue != 0) { 
     1377                pjsip_msg *msg; 
     1378                pjsip_expires_hdr *expires; 
     1379 
     1380                msg = event->body.tsx_state.src.rdata->msg_info.msg; 
     1381                expires = pjsip_msg_find_hdr(msg, PJSIP_H_EXPIRES, NULL); 
     1382                if (expires) { 
     1383                    sub->expires->ivalue = expires->ivalue; 
    10631384                } 
    10641385            } 
    1065         } 
    1066  
    1067         if (!content_type) { 
    1068             status = PJSIP_SC_NOT_ACCEPTABLE_HERE; 
    1069             goto send_response; 
    1070         } 
    1071     } 
    1072  
    1073     /* Check whether the package wants to accept the subscription. */ 
    1074     pj_assert(pkg->cb.on_query_subscribe != NULL); 
    1075     (*pkg->cb.on_query_subscribe)(rdata, &status); 
    1076     if (!PJSIP_IS_STATUS_IN_CLASS(status,200)) 
    1077         goto send_response; 
    1078  
    1079     /* Create new subscription record. */ 
    1080     pool = pjsip_endpt_create_pool(tsx->endpt, "esub",  
    1081                                    SUB_POOL_SIZE, SUB_POOL_INC); 
    1082     if (!pool) { 
    1083         status = 500; 
    1084         goto send_response; 
    1085     } 
    1086     sub = pj_pool_calloc(pool, 1, sizeof(*sub)); 
    1087     sub->pool = pool; 
    1088     sub->mutex = pj_mutex_create(pool, "esub", PJ_MUTEX_RECURSE); 
    1089     if (!sub->mutex) { 
    1090         status = 500; 
    1091         goto send_response; 
    1092     } 
    1093  
    1094     PJ_LOG(4,(THIS_FILE, "event_sub%p: notifier is created.", sub)); 
    1095  
    1096     /* Start locking mutex. */ 
    1097     pj_mutex_lock(sub->mutex); 
    1098  
    1099     /* Init UAS subscription */ 
    1100     sub->endpt = tsx->endpt; 
    1101     sub->role = PJSIP_ROLE_UAS; 
    1102     sub->state = PJSIP_EVENT_SUB_STATE_PENDING; 
    1103     sub->state_str = state[sub->state]; 
    1104     pj_list_init(&sub->auth_sess); 
    1105     pj_list_init(&sub->route_set); 
    1106     sub->from = pjsip_hdr_clone(pool, rdata->to); 
    1107     pjsip_fromto_set_from(sub->from); 
    1108     if (sub->from->tag.slen == 0) { 
    1109         pj_create_unique_string(pool, &sub->from->tag); 
    1110         rdata->to->tag = sub->from->tag; 
    1111     } 
    1112     sub->to = pjsip_hdr_clone(pool, rdata->from); 
    1113     pjsip_fromto_set_to(sub->to); 
    1114     sub->contact = pjsip_contact_hdr_create(pool); 
    1115     sub->contact->uri = sub->from->uri; 
    1116     sub->call_id = pjsip_cid_hdr_create(pool); 
    1117     pj_strdup(pool, &sub->call_id->id, &rdata->call_id); 
    1118     sub->cseq = pj_rand() % 0xFFFF; 
    1119      
    1120     expires = pjsip_msg_find_hdr( rdata->msg, PJSIP_H_EXPIRES, NULL); 
    1121     if (expires) { 
    1122         sub->default_interval = expires->ivalue; 
    1123         if (sub->default_interval > 0 &&  
    1124             sub->default_interval < SECONDS_BEFORE_EXPIRY)  
    1125         { 
    1126             status = 423; /* Interval too short. */ 
    1127             goto send_response; 
    1128         } 
    1129     } else { 
    1130         sub->default_interval = 600; 
    1131     } 
    1132  
    1133     /* Clone Event header. */ 
    1134     sub->event = pjsip_hdr_clone(pool, evhdr); 
    1135  
    1136     /* Register to hash table. */ 
    1137     create_subscriber_key(&sub->key, pool, PJSIP_ROLE_UAS, &sub->call_id->id, 
    1138                           &sub->from->tag); 
    1139     pj_mutex_lock(mgr.mutex); 
    1140     pj_hash_set(pool, mgr.ht, sub->key.ptr, sub->key.slen, sub); 
    1141     pj_mutex_unlock(mgr.mutex); 
    1142  
    1143     /* Set timer where subscription will expire only when expires<>0.  
    1144      * Subscriber may send new subscription with expires==0. 
    1145      */ 
    1146     if (sub->default_interval != 0) { 
    1147         sub_schedule_uas_expire( sub, sub->default_interval-SECONDS_BEFORE_EXPIRY); 
    1148     } 
    1149  
    1150     /* Notify application. */ 
    1151     if (pkg->cb.on_subscribe) { 
    1152         pjsip_event_sub_cb *cb = NULL; 
    1153         sub->pending_tsx++; 
    1154         (*pkg->cb.on_subscribe)(sub, rdata, &cb, &sub->default_interval); 
    1155         sub->pending_tsx--; 
    1156         if (cb == NULL) 
    1157             pj_memset(&sub->cb, 0, sizeof(*cb)); 
    1158         else 
    1159             pj_memcpy(&sub->cb, cb, sizeof(*cb)); 
    1160     } 
    1161  
    1162  
    1163 send_response: 
    1164     PJ_LOG(4,(THIS_FILE, "event_sub%p (%s)(UAS): status=%d",  
    1165                           sub, state[sub->state].ptr, status)); 
    1166  
    1167     tdata = pjsip_endpt_create_response( tsx->endpt, rdata, status); 
    1168     if (tdata) { 
    1169         if (reason.slen) { 
    1170             /* Customize reason text. */ 
    1171             tdata->msg->line.status.reason = reason; 
    1172         } 
    1173         if (PJSIP_IS_STATUS_IN_CLASS(status,200)) { 
    1174             /* Add Expires header. */ 
    1175             pjsip_expires_hdr *hdr; 
    1176  
    1177             hdr = pjsip_expires_hdr_create(tdata->pool); 
    1178             hdr->ivalue = sub->default_interval; 
    1179             pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)hdr ); 
    1180         } 
    1181         if (status == 423) { 
    1182             /* Add Min-Expires header. */ 
    1183             pjsip_min_expires_hdr *hdr; 
    1184  
    1185             hdr = pjsip_min_expires_hdr_create(tdata->pool); 
    1186             hdr->ivalue = SECONDS_BEFORE_EXPIRY; 
    1187             pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)hdr); 
    1188         } 
    1189         if (status == 489 ||  
    1190             status==PJSIP_SC_NOT_ACCEPTABLE_HERE || 
    1191             PJSIP_IS_STATUS_IN_CLASS(status,200))  
    1192         { 
    1193             /* Add Allow-Events header. */ 
    1194             pjsip_hdr *hdr; 
    1195             hdr = pjsip_hdr_shallow_clone(tdata->pool, mgr.allow_events); 
    1196             pjsip_msg_add_hdr(tdata->msg, hdr); 
    1197  
    1198             /* Should add Accept header?. */ 
    1199         } 
    1200  
    1201         pjsip_tsx_on_tx_msg(tsx, tdata); 
    1202     } 
    1203  
    1204     /* If received new subscription with expires=0, terminate. */ 
    1205     if (sub && sub->default_interval == 0) { 
    1206         pj_assert(sub->state == PJSIP_EVENT_SUB_STATE_TERMINATED); 
    1207         if (sub->cb.on_sub_terminated) { 
    1208             pj_str_t reason = { "timeout", 7 }; 
    1209             (*sub->cb.on_sub_terminated)(sub, &reason); 
    1210         } 
    1211     } 
    1212  
    1213     if (!PJSIP_IS_STATUS_IN_CLASS(status,200) || (sub && sub->delete_flag)) { 
    1214         if (sub && sub->mutex) { 
    1215             pjsip_event_sub_destroy(sub); 
    1216         } else if (sub) { 
    1217             pjsip_endpt_destroy_pool(tsx->endpt, sub->pool); 
    1218         } 
    1219     } else { 
    1220         pj_assert(status >= 200); 
    1221         pj_mutex_unlock(sub->mutex); 
    1222     } 
    1223 } 
    1224  
    1225 /* This is the main callback when SUBSCRIBE request is received. */ 
    1226 static void on_subscribe_request(pjsip_transaction *tsx, pjsip_rx_data *rdata) 
    1227 { 
    1228     pjsip_event_sub *sub = find_sub(rdata); 
    1229  
    1230     if (sub) 
    1231         on_received_sub_refresh(sub, tsx, rdata); 
    1232     else 
    1233         on_new_subscription(tsx, rdata); 
    1234 } 
    1235  
    1236  
    1237 /* This callback is called when response to SUBSCRIBE is received. */ 
    1238 static void on_subscribe_response(void *token, pjsip_event *event) 
    1239 { 
    1240     pjsip_event_sub *sub = token; 
    1241     pjsip_transaction *tsx = event->obj.tsx; 
    1242     int new_state, old_state = sub->state; 
    1243  
    1244     pj_assert(tsx->status_code >= 200); 
    1245     if (tsx->status_code < 200) 
    1246         return; 
    1247  
    1248     pj_assert(sub->role == PJSIP_ROLE_UAC); 
    1249  
    1250     /* Lock mutex. */ 
    1251     pj_mutex_lock(sub->mutex); 
    1252  
    1253     /* If request failed with 401/407 error, silently retry the request. */ 
    1254     if (tsx->status_code==401 || tsx->status_code==407) { 
    1255         pjsip_tx_data *tdata; 
    1256         tdata = pjsip_auth_reinit_req(sub->endpt, 
    1257                                       sub->pool, &sub->auth_sess, 
    1258                                       sub->cred_cnt, sub->cred_info, 
    1259                                       tsx->last_tx, event->src.rdata ); 
    1260         if (tdata) { 
    1261             int status; 
    1262             pjsip_cseq_hdr *cseq; 
    1263             cseq = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL); 
    1264             cseq->cseq = sub->cseq++; 
    1265             status = pjsip_endpt_send_request( sub->endpt, tdata,  
    1266                                                -1, sub,  
    1267                                                &on_subscribe_response); 
    1268             if (status == 0) { 
    1269                 pj_mutex_unlock(sub->mutex); 
     1386 
     1387            /* Update time */ 
     1388            update_expires(sub, sub->expires->ivalue); 
     1389 
     1390            /* Start UAC refresh timer, only when we're not unsubscribing */ 
     1391            if (sub->expires->ivalue != 0) { 
     1392                unsigned timeout = (sub->expires->ivalue > TIME_UAC_REFRESH) ? 
     1393                    sub->expires->ivalue - TIME_UAC_REFRESH : sub->expires->ivalue; 
     1394 
     1395                PJ_LOG(5,(sub->obj_name, "Will refresh in %d seconds",  
     1396                          timeout)); 
     1397                set_timer(sub, TIMER_TYPE_UAC_REFRESH, timeout); 
     1398 
     1399            } else { 
     1400                /* Otherwise set timer to terminate client subscription when 
     1401                 * NOTIFY to end subscription is not received. 
     1402                 */ 
     1403                set_timer(sub, TIMER_TYPE_UAC_TERMINATE, TIME_UAC_TERMINATE); 
     1404            } 
     1405             
     1406            /* Set state, if necessary */ 
     1407            pj_assert(sub->state != PJSIP_EVSUB_STATE_NULL); 
     1408            if (sub->state == PJSIP_EVSUB_STATE_SENT) { 
     1409                set_state(sub, PJSIP_EVSUB_STATE_ACCEPTED, NULL, event); 
     1410            } 
     1411 
     1412        } else { 
     1413 
     1414            /* Failed SUBSCRIBE request!  
     1415             * 
     1416             * The RFC 3265 says that if outgoing SUBSCRIBE fails with status 
     1417             * other than 481, the subscription is still considered valid for 
     1418             * the duration of the last Expires. 
     1419             * 
     1420             * Since we send refresh about 5 seconds (TIME_UAC_REFRESH) before  
     1421             * expiration, theoritically the expiration is still valid for the  
     1422             * next 5 seconds even when we receive non-481 failed response. 
     1423             * 
     1424             * Ah, what the heck! 
     1425             * 
     1426             * Just terminate now! 
     1427             * 
     1428             */ 
     1429 
     1430            if (sub->state == PJSIP_EVSUB_STATE_TERMINATED) { 
     1431                /* Ignore, has been handled before */ 
    12701432                return; 
    12711433            } 
    1272         } 
    1273     } 
    1274  
    1275     if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code,200)) { 
    1276         /* Update To tag. */ 
    1277         if (sub->to->tag.slen == 0) 
    1278             pj_strdup(sub->pool, &sub->to->tag, &event->src.rdata->to_tag); 
    1279  
    1280         new_state = sub->state; 
    1281  
    1282     } else if (tsx->status_code == 481) { 
    1283         new_state = PJSIP_EVENT_SUB_STATE_TERMINATED; 
    1284  
    1285     } else if (tsx->status_code >= 300) { 
    1286         /* RFC 3265 Section 3.1.4.2: 
    1287          * If a SUBSCRIBE request to refresh a subscription fails  
    1288          * with a non-481 response, the original subscription is still  
    1289          * considered valid for the duration of original exires. 
     1434 
     1435            /* Kill any timer. */ 
     1436            set_timer(sub, TIMER_TYPE_NONE, 0); 
     1437 
     1438            /* Set state to TERMINATED */ 
     1439            set_state(sub, PJSIP_EVSUB_STATE_TERMINATED,  
     1440                      NULL, event); 
     1441 
     1442        } 
     1443 
     1444    } else if (pjsip_method_cmp(&tsx->method, &pjsip_notify_method) == 0) { 
     1445 
     1446        /* Incoming NOTIFY.  
     1447         * This can be the result of: 
     1448         *  - Initial subscription response 
     1449         *  - UAS updating the resource info. 
     1450         *  - Unsubscription response. 
     1451         */ 
     1452        int st_code = 200; 
     1453        pj_str_t *st_text = NULL; 
     1454        pjsip_hdr res_hdr; 
     1455        pjsip_msg_body *body = NULL; 
     1456 
     1457        pjsip_rx_data *rdata; 
     1458        pjsip_msg *msg; 
     1459        pjsip_sub_state_hdr *sub_state; 
     1460 
     1461        pjsip_evsub_state new_state; 
     1462        pj_str_t *new_state_str; 
     1463 
     1464        pjsip_tx_data *tdata; 
     1465        pj_status_t status; 
     1466        int next_refresh; 
     1467 
     1468        /* Only want to handle initial NOTIFY receive event. */ 
     1469        if (tsx->state != PJSIP_TSX_STATE_TRYING) 
     1470            return; 
     1471 
     1472 
     1473        rdata = event->body.tsx_state.src.rdata; 
     1474        msg = rdata->msg_info.msg; 
     1475 
     1476        pj_list_init(&res_hdr); 
     1477 
     1478        /* Get subscription state header. */ 
     1479        sub_state = pjsip_msg_find_hdr_by_name(msg, &STR_SUB_STATE, NULL); 
     1480        if (sub_state == NULL) { 
     1481 
     1482            pjsip_warning_hdr *warn_hdr; 
     1483            pj_str_t warn_text = { "Missing Subscription-State header", 33}; 
     1484 
     1485            /* Bad request! Add warning header. */ 
     1486            st_code = PJSIP_SC_BAD_REQUEST; 
     1487            warn_hdr = pjsip_warning_hdr_create(rdata->tp_info.pool, 399, 
     1488                                                pjsip_endpt_name(sub->endpt), 
     1489                                                &warn_text); 
     1490            pj_list_push_back(&res_hdr, warn_hdr); 
     1491        } 
     1492 
     1493        /* Call application registered callback to handle incoming NOTIFY, 
     1494         * if any. 
     1495         */ 
     1496        if (st_code==200 && sub->user.on_rx_notify) { 
     1497            (*sub->user.on_rx_notify)(sub, rdata, &st_code, &st_text,  
     1498                                      &res_hdr, &body); 
     1499 
     1500            /* Application MUST specify final response! */ 
     1501            PJ_ASSERT_ON_FAIL(st_code >= 200, {st_code=200; }); 
     1502 
     1503            /* Must be a valid status code */ 
     1504            PJ_ASSERT_ON_FAIL(st_code <= 699, {st_code=500; }); 
     1505        } 
     1506 
     1507 
     1508        /* If non-2xx should be returned, then send the response. 
     1509         * No need to update server subscription state. 
     1510         */ 
     1511        if (st_code >= 300) { 
     1512            status = create_response(sub, rdata, st_code, st_text, &res_hdr, 
     1513                                     body, &tdata); 
     1514            if (status == PJ_SUCCESS) { 
     1515                status = pjsip_dlg_send_response(sub->dlg, tsx, tdata); 
     1516            } 
     1517 
     1518            /* Start timer to terminate subscription, just in case server 
     1519             * is not able to generate NOTIFY to our response. 
     1520             */ 
     1521            if (status == PJ_SUCCESS) { 
     1522                unsigned timeout = TIME_UAC_WAIT_NOTIFY; 
     1523                set_timer(sub, TIMER_TYPE_UAC_WAIT_NOTIFY, timeout); 
     1524            } else { 
     1525                set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, NULL); 
     1526            } 
     1527 
     1528            return; 
     1529        } 
     1530 
     1531        /* Update expiration from the value of expires param in 
     1532         * Subscription-State header, but ONLY when subscription state  
     1533         * is "active" or "pending", AND the header contains expires param. 
     1534         */ 
     1535        if (sub->expires->ivalue != 0 && 
     1536            sub_state->expires_param >= 0 && 
     1537            (pj_stricmp(&sub_state->sub_state, &STR_ACTIVE)==0 || 
     1538             pj_stricmp(&sub_state->sub_state, &STR_PENDING)==0)) 
     1539        { 
     1540            next_refresh = sub_state->expires_param; 
     1541 
     1542        } else { 
     1543            next_refresh = sub->expires->ivalue; 
     1544        } 
     1545 
     1546        /* Update time */ 
     1547        update_expires(sub, next_refresh); 
     1548 
     1549        /* Start UAC refresh timer, only when we're not unsubscribing */ 
     1550        if (sub->expires->ivalue != 0) { 
     1551            unsigned timeout = (next_refresh > TIME_UAC_REFRESH) ? 
     1552                next_refresh - TIME_UAC_REFRESH : next_refresh; 
     1553 
     1554            PJ_LOG(5,(sub->obj_name, "Will refresh in %d seconds", timeout)); 
     1555            set_timer(sub, TIMER_TYPE_UAC_REFRESH, timeout); 
     1556        } 
     1557         
     1558        /* Find out the state */ 
     1559        get_hdr_state(sub_state, &new_state, &new_state_str); 
     1560 
     1561        /* Send response. */ 
     1562        status = create_response(sub, rdata, st_code, st_text, &res_hdr, 
     1563                                 body, &tdata); 
     1564        if (status == PJ_SUCCESS) 
     1565            status = pjsip_dlg_send_response(sub->dlg, tsx, tdata); 
     1566 
     1567        /* Set the state */ 
     1568        if (status == PJ_SUCCESS) { 
     1569            set_state(sub, new_state, new_state_str, event); 
     1570        } else { 
     1571            set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, event); 
     1572        } 
     1573 
     1574 
     1575    } else { 
     1576 
     1577        /* 
     1578         * Unexpected method! 
     1579         */ 
     1580        PJ_LOG(4,(sub->obj_name, "Unexpected transaction method %.*s", 
     1581                 (int)tsx->method.name.slen, tsx->method.name.ptr)); 
     1582    } 
     1583} 
     1584 
     1585 
     1586/* 
     1587 * Transaction event processing by UAS, after subscription is accepted. 
     1588 */ 
     1589static void on_tsx_state_uas( pjsip_evsub *sub, pjsip_transaction *tsx, 
     1590                              pjsip_event *event) 
     1591{ 
     1592 
     1593    if (pjsip_method_cmp(&tsx->method, &sub->method) == 0) { 
     1594         
     1595        /* 
     1596         * Incoming request (e.g. SUBSCRIBE or REFER) to refresh subsciption. 
    12901597         * 
    1291          * Note: 
    1292          * Since we normally send SUBSCRIBE for refreshing the subscription, 
    1293          * it means the subscription already expired anyway. So we terminate 
    1294          * the subscription now. 
    12951598         */ 
    1296         if (sub->state != PJSIP_EVENT_SUB_STATE_ACTIVE) { 
    1297             new_state = PJSIP_EVENT_SUB_STATE_TERMINATED; 
    1298         } else { 
    1299             /* Use this to be compliant with Section 3.1.4.2 
    1300               new_state = sub->state; 
    1301              */ 
    1302             new_state = PJSIP_EVENT_SUB_STATE_TERMINATED; 
    1303         } 
     1599        pjsip_rx_data *rdata; 
     1600        pjsip_event_hdr *event_hdr; 
     1601        pjsip_expires_hdr *expires; 
     1602        pjsip_msg *msg; 
     1603        pjsip_tx_data *tdata; 
     1604        int st_code = 200; 
     1605        pj_str_t *st_text = NULL; 
     1606        pjsip_hdr res_hdr; 
     1607        pjsip_msg_body *body = NULL; 
     1608        pjsip_evsub_state old_state; 
     1609        pj_str_t old_state_str; 
     1610        pj_status_t status; 
     1611 
     1612 
     1613        /* Only wants to handle the first event when the request is  
     1614         * received. 
     1615         */ 
     1616        if (tsx->state != PJSIP_TSX_STATE_TRYING) 
     1617            return; 
     1618 
     1619        rdata = event->body.tsx_state.src.rdata; 
     1620        msg = rdata->msg_info.msg; 
     1621 
     1622        /* Set expiration time based on client request (in Expires header), 
     1623         * or package default expiration time. 
     1624         */ 
     1625        event_hdr = pjsip_msg_find_hdr_by_name(msg, &STR_EVENT, NULL); 
     1626        expires = pjsip_msg_find_hdr(msg, PJSIP_H_EXPIRES, NULL); 
     1627        if (event_hdr && expires) { 
     1628            struct evpkg *evpkg; 
     1629 
     1630            evpkg = find_pkg(&event_hdr->event_type); 
     1631            if (evpkg) { 
     1632                if (expires->ivalue < (pj_int32_t)evpkg->pkg_expires) 
     1633                    sub->expires->ivalue = expires->ivalue; 
     1634                else 
     1635                    sub->expires->ivalue = evpkg->pkg_expires; 
     1636            } 
     1637        } 
     1638         
     1639        /* Update time (before calling on_rx_refresh, since application 
     1640         * will send NOTIFY. 
     1641         */ 
     1642        update_expires(sub, sub->expires->ivalue); 
     1643 
     1644 
     1645        /* Save old state. 
     1646         * If application respond with non-2xx, revert to old state. 
     1647         */ 
     1648        old_state = sub->state; 
     1649        old_state_str = sub->state_str; 
     1650 
     1651        if (sub->expires->ivalue == 0) { 
     1652            sub->state = PJSIP_EVSUB_STATE_TERMINATED; 
     1653            sub->state_str = evsub_state_names[sub->state]; 
     1654        } else  if (sub->state == PJSIP_EVSUB_STATE_NULL) { 
     1655            sub->state = PJSIP_EVSUB_STATE_ACCEPTED; 
     1656            sub->state_str = evsub_state_names[sub->state]; 
     1657        } 
     1658 
     1659        /* Call application's on_rx_refresh, just in case it wants to send 
     1660         * response other than 200 (OK) 
     1661         */ 
     1662        pj_list_init(&res_hdr); 
     1663 
     1664        (*sub->user.on_rx_refresh)(sub, rdata, &st_code, &st_text,  
     1665                                   &res_hdr, &body); 
     1666 
     1667        /* Application MUST specify final response! */ 
     1668        PJ_ASSERT_ON_FAIL(st_code >= 200, {st_code=200; }); 
     1669 
     1670        /* Must be a valid status code */ 
     1671        PJ_ASSERT_ON_FAIL(st_code <= 699, {st_code=500; }); 
     1672 
     1673 
     1674        /* Create and send response */ 
     1675        status = create_response(sub, rdata, st_code, st_text, &res_hdr, 
     1676                                 body, &tdata); 
     1677        if (status == PJ_SUCCESS) { 
     1678            /* Add expires header: */ 
     1679            pjsip_msg_add_hdr( tdata->msg, 
     1680                               pjsip_hdr_shallow_clone(tdata->pool,  
     1681                                                       sub->expires)); 
     1682 
     1683            /* Send */ 
     1684            status = pjsip_dlg_send_response(sub->dlg, tsx, tdata); 
     1685        } 
     1686 
     1687        /* Update state or revert state */ 
     1688        if (st_code/100==2) { 
     1689             
     1690            if (sub->expires->ivalue == 0) { 
     1691                set_state(sub, sub->state, NULL, event); 
     1692            } else  if (sub->state == PJSIP_EVSUB_STATE_NULL) { 
     1693                set_state(sub, sub->state, NULL, event); 
     1694            } 
     1695 
     1696            /* Set UAS timeout timer, when state is not terminated. */ 
     1697            if (sub->state != PJSIP_EVSUB_STATE_TERMINATED) { 
     1698                PJ_LOG(5,(sub->obj_name, "UAS timeout in %d seconds", 
     1699                          sub->expires->ivalue)); 
     1700                set_timer(sub, TIMER_TYPE_UAS_TIMEOUT,  
     1701                          sub->expires->ivalue); 
     1702            } 
     1703 
     1704        }  else { 
     1705            sub->state = old_state; 
     1706            sub->state_str = old_state_str; 
     1707        } 
     1708 
     1709 
     1710    } else if (pjsip_method_cmp(&tsx->method, &pjsip_notify_method)==0) { 
     1711 
     1712        /* Handle authentication */  
     1713        if (tsx->state == PJSIP_TSX_STATE_COMPLETED && 
     1714            (tsx->status_code==401 || tsx->status_code==407)) 
     1715        { 
     1716            pjsip_rx_data *rdata = event->body.tsx_state.src.rdata; 
     1717            pjsip_tx_data *tdata; 
     1718            pj_status_t status; 
     1719 
     1720            status = pjsip_auth_clt_reinit_req( &sub->dlg->auth_sess, rdata,  
     1721                                                tsx->last_tx, &tdata); 
     1722            if (status == PJ_SUCCESS) 
     1723                status = pjsip_dlg_send_request( sub->dlg, tdata, NULL ); 
     1724 
     1725            if (status != PJ_SUCCESS) { 
     1726                /* Can't authenticate. Terminate session (?) */ 
     1727                set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, NULL); 
     1728            } 
     1729        }  
     1730 
    13041731    } else { 
    1305         pj_assert(0); 
    1306         new_state = sub->state; 
    1307     } 
    1308  
    1309     if (new_state != sub->state && sub->state != PJSIP_EVENT_SUB_STATE_TERMINATED) { 
    1310         sub_set_state(sub, new_state); 
    1311     } 
    1312  
    1313     if (sub->state == PJSIP_EVENT_SUB_STATE_ACTIVE || 
    1314         sub->state == PJSIP_EVENT_SUB_STATE_PENDING) 
    1315     { 
     1732 
    13161733        /* 
    1317          * Register timer for next subscription refresh, but only when 
    1318          * we're not unsubscribing. Also update default_interval and Expires 
    1319          * header. 
     1734         * Unexpected method! 
    13201735         */ 
    1321         if (sub->default_interval > 0 && !sub->delete_flag) { 
    1322             pjsip_expires_hdr *exp = NULL; 
    1323              
    1324             /* Could be transaction timeout. */ 
    1325             if (event->src_type == PJSIP_EVENT_RX_MSG) { 
    1326                 exp = pjsip_msg_find_hdr(event->src.rdata->msg, 
    1327                                          PJSIP_H_EXPIRES, NULL); 
    1328             } 
    1329  
    1330             if (exp) { 
    1331                 int delay = exp->ivalue; 
    1332                 if (delay > 0) { 
    1333                     pj_time_val new_expiry; 
    1334                     pj_gettimeofday(&new_expiry); 
    1335                     new_expiry.sec += delay; 
    1336                     if (sub->timer.id==0 ||  
    1337                         new_expiry.sec < sub->expiry_time.sec-SECONDS_BEFORE_EXPIRY/2)  
    1338                     { 
    1339                     //if (delay > 0 && delay < sub->default_interval) { 
    1340                         sub->default_interval = delay; 
    1341                         sub->uac_expires->ivalue = delay; 
    1342                         update_next_refresh(sub, delay); 
    1343                     } 
    1344                 } 
    1345             } 
    1346         } 
    1347     } 
    1348  
    1349     /* Call callback. */ 
    1350     if (!sub->delete_flag) { 
    1351         if (sub->cb.on_received_sub_response) { 
    1352             (*sub->cb.on_received_sub_response)(sub, event); 
    1353         } 
    1354     } 
    1355  
    1356     /* Notify application if we're terminated. */ 
    1357     if (new_state!=old_state && new_state==PJSIP_EVENT_SUB_STATE_TERMINATED) { 
    1358         if (sub->cb.on_sub_terminated) { 
    1359             pj_str_t reason; 
    1360             if (event->src_type == PJSIP_EVENT_RX_MSG) 
    1361                 reason = event->src.rdata->msg->line.status.reason; 
    1362             else 
    1363                 reason = *pjsip_get_status_text(tsx->status_code); 
    1364  
    1365             (*sub->cb.on_sub_terminated)(sub, &reason); 
    1366         } 
    1367     } 
    1368  
    1369     /* Decrement pending tsx count. */ 
    1370     --sub->pending_tsx; 
    1371     pj_assert(sub->pending_tsx >= 0); 
    1372  
    1373     if (sub->delete_flag && sub->pending_tsx <= 0) { 
    1374         pjsip_event_sub_destroy(sub); 
     1736        PJ_LOG(4,(sub->obj_name, "Unexpected transaction method %.*s", 
     1737                 (int)tsx->method.name.slen, tsx->method.name.ptr)); 
     1738     
     1739    } 
     1740} 
     1741 
     1742 
     1743/* 
     1744 * Notification when transaction state has changed! 
     1745 */ 
     1746static void mod_evsub_on_tsx_state(pjsip_transaction *tsx, pjsip_event *event) 
     1747{ 
     1748    pjsip_evsub *sub = pjsip_tsx_get_evsub(tsx); 
     1749 
     1750    if (sub == NULL) { 
     1751        sub = on_new_transaction(tsx, event); 
     1752        if (sub == NULL) 
     1753            return; 
     1754    } 
     1755 
     1756 
     1757    /* Call on_tsx_state callback, if any. */ 
     1758    if (sub->user.on_tsx_state) 
     1759        (*sub->user.on_tsx_state)(sub, tsx, event); 
     1760 
     1761 
     1762    /* Process the event: */ 
     1763 
     1764    if (sub->role == PJSIP_ROLE_UAC) { 
     1765        on_tsx_state_uac(sub, tsx, event); 
    13751766    } else { 
    1376         pj_mutex_unlock(sub->mutex); 
    1377     } 
    1378  
    1379     /* DO NOT ACCESS sub FROM NOW ON! IT MIGHT HAVE BEEN DELETED */ 
    1380 } 
    1381  
    1382 /* 
    1383  * This callback called when we receive incoming NOTIFY request. 
    1384  */ 
    1385 static void on_notify_request(pjsip_transaction *tsx, pjsip_rx_data *rdata) 
    1386 { 
    1387     pjsip_event_sub *sub; 
    1388     pjsip_tx_data *tdata; 
    1389     int status = 200; 
    1390     int old_state; 
    1391     pj_str_t reason = { NULL, 0 }; 
    1392     pj_str_t reason_phrase = { NULL, 0 }; 
    1393     int new_state = PJSIP_EVENT_SUB_STATE_NULL; 
    1394  
    1395     /* Find subscription based on Call-ID and From tag.  
    1396      * This will also automatically lock the subscription, if it's found. 
    1397      */ 
    1398     sub = find_sub(rdata); 
    1399     if (!sub) { 
    1400         /* RFC 3265: Section 3.2 Description of NOTIFY Behavior: 
    1401          * Answer with 481 Subscription does not exist. 
    1402          */ 
    1403         PJ_LOG(4,(THIS_FILE, "Unable to find subscription for incoming NOTIFY!")); 
    1404         status = 481; 
    1405         reason_phrase = pj_str("Subscription does not exist"); 
    1406  
    1407     } else { 
    1408         pj_assert(sub->role == PJSIP_ROLE_UAC); 
    1409         PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): received NOTIFY",  
    1410                              sub, state[sub->state].ptr)); 
    1411  
    1412     } 
    1413  
    1414     new_state = old_state = sub->state; 
    1415  
    1416     /* RFC 3265: Section 3.2.1 
    1417      * Check that the Event header match the subscription.  
    1418      */ 
    1419     if (status == 200) { 
    1420         pjsip_event_hdr *hdr; 
    1421         pj_str_t hname = { "Event", 5 }; 
    1422  
    1423         hdr = pjsip_msg_find_hdr_by_name(rdata->msg, &hname, NULL); 
    1424         if (!hdr) { 
    1425             status = PJSIP_SC_BAD_REQUEST; 
    1426             reason_phrase = pj_str("No Event header found"); 
    1427         } else if (pj_stricmp(&hdr->event_type, &sub->event->event_type) != 0 || 
    1428                    pj_stricmp(&hdr->id_param, &sub->event->id_param) != 0)  
     1767        on_tsx_state_uas(sub, tsx, event); 
     1768    } 
     1769 
     1770 
     1771    /* Check transaction TERMINATE event */ 
     1772    if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { 
     1773 
     1774        --sub->pending_tsx; 
     1775 
     1776        if (sub->state == PJSIP_EVSUB_STATE_TERMINATED && 
     1777            sub->pending_tsx == 0) 
    14291778        { 
    1430             status = 481; 
    1431             reason_phrase = pj_str("Subscription does not exist"); 
    1432         } 
    1433     } 
    1434  
    1435     /* Update subscription state and timer. */ 
    1436     if (status == 200) { 
    1437         pjsip_sub_state_hdr *hdr; 
    1438         const pj_str_t hname = { "Subscription-State", 18 }; 
    1439         const pj_str_t state_active = { "active", 6 }, 
    1440                        state_pending = { "pending", 7}, 
    1441                        state_terminated = { "terminated", 10 }; 
    1442  
    1443         hdr = pjsip_msg_find_hdr_by_name( rdata->msg, &hname, NULL); 
    1444         if (!hdr) { 
    1445             status = PJSIP_SC_BAD_REQUEST; 
    1446             reason_phrase = pj_str("No Subscription-State header found"); 
    1447             goto process; 
    1448         }  
    1449  
    1450         /* 
    1451          * Update subscription state. 
    1452          */ 
    1453         if (pj_stricmp(&hdr->sub_state, &state_active) == 0) { 
    1454             if (sub->state != PJSIP_EVENT_SUB_STATE_TERMINATED) 
    1455                 new_state = PJSIP_EVENT_SUB_STATE_ACTIVE; 
    1456         } else if (pj_stricmp(&hdr->sub_state, &state_pending) == 0) { 
    1457             if (sub->state != PJSIP_EVENT_SUB_STATE_TERMINATED) 
    1458                 new_state = PJSIP_EVENT_SUB_STATE_PENDING; 
    1459         } else if (pj_stricmp(&hdr->sub_state, &state_terminated) == 0) { 
    1460             new_state = PJSIP_EVENT_SUB_STATE_TERMINATED; 
    1461         } else { 
    1462             new_state = PJSIP_EVENT_SUB_STATE_UNKNOWN; 
    1463         } 
    1464  
    1465         reason = hdr->reason_param; 
    1466  
    1467         if (new_state != sub->state && new_state != PJSIP_EVENT_SUB_STATE_NULL && 
    1468             sub->state != PJSIP_EVENT_SUB_STATE_TERMINATED)  
    1469         { 
    1470             sub_set_state(sub, new_state); 
    1471             if (new_state == PJSIP_EVENT_SUB_STATE_UNKNOWN) { 
    1472                 pj_strdup_with_null(sub->pool, &sub->state_str, &hdr->sub_state); 
    1473             } else { 
    1474                 sub->state_str = state[new_state]; 
    1475             } 
    1476         } 
    1477  
    1478         /* 
    1479          * Update timeout timer in required, just in case notifier changed the  
    1480          * expiration to shorter time. 
    1481          * Section 3.2.2: the expires param can only shorten the interval. 
    1482          */ 
    1483         if ((sub->state==PJSIP_EVENT_SUB_STATE_ACTIVE ||  
    1484              sub->state==PJSIP_EVENT_SUB_STATE_PENDING) && hdr->expires_param > 0)  
    1485         { 
    1486             pj_time_val now, new_expiry; 
    1487  
    1488             pj_gettimeofday(&now); 
    1489             new_expiry.sec = now.sec + hdr->expires_param; 
    1490             if (sub->timer.id==0 ||  
    1491                 new_expiry.sec < sub->expiry_time.sec-SECONDS_BEFORE_EXPIRY/2)  
    1492             { 
    1493                 update_next_refresh(sub, hdr->expires_param); 
    1494             } 
    1495         } 
    1496     } 
    1497  
    1498 process: 
    1499     /* Note: here we sub MAY BE NULL! */ 
    1500  
    1501     /* Send response to NOTIFY */ 
    1502     tdata = pjsip_endpt_create_response( tsx->endpt, rdata, status ); 
    1503     if (tdata) { 
    1504         if (reason_phrase.slen) 
    1505             tdata->msg->line.status.reason = reason_phrase; 
    1506  
    1507         if (PJSIP_IS_STATUS_IN_CLASS(status,200)) { 
    1508             pjsip_hdr *hdr; 
    1509             hdr = pjsip_hdr_shallow_clone(tdata->pool, mgr.allow_events); 
    1510             pjsip_msg_add_hdr( tdata->msg, hdr); 
    1511         } 
    1512  
    1513         pjsip_tsx_on_tx_msg(tsx, tdata); 
    1514     } 
    1515  
    1516     /* Call NOTIFY callback, if any. */ 
    1517     if (sub && PJSIP_IS_STATUS_IN_CLASS(status,200) && sub->cb.on_received_notify) { 
    1518         sub->pending_tsx++; 
    1519         (*sub->cb.on_received_notify)(sub, rdata); 
    1520         sub->pending_tsx--; 
    1521     } 
    1522  
    1523     /* Check if subscription is terminated and call callback. */ 
    1524     if (sub && new_state!=old_state && new_state==PJSIP_EVENT_SUB_STATE_TERMINATED) { 
    1525         if (sub->cb.on_sub_terminated) { 
    1526             sub->pending_tsx++; 
    1527             (*sub->cb.on_sub_terminated)(sub, &reason); 
    1528             sub->pending_tsx--; 
    1529         } 
    1530     } 
    1531  
    1532     /* Check if application has requested deletion. */ 
    1533     if (sub && sub->delete_flag && sub->pending_tsx <= 0) { 
    1534         pjsip_event_sub_destroy(sub); 
    1535     } else if (sub) { 
    1536         pj_mutex_unlock(sub->mutex); 
    1537     } 
    1538 } 
    1539  
    1540 /* This callback is called when we received NOTIFY response. */ 
    1541 static void on_notify_response(void *token, pjsip_event *event) 
    1542 { 
    1543     pjsip_event_sub *sub = token; 
    1544     pjsip_event_sub_state old_state = sub->state; 
    1545     pjsip_transaction *tsx = event->obj.tsx; 
    1546  
    1547     /* Lock the subscription. */ 
    1548     pj_mutex_lock(sub->mutex); 
    1549  
    1550     pj_assert(sub->role == PJSIP_ROLE_UAS); 
    1551  
    1552     /* If request failed with authorization failure, silently retry. */ 
    1553     if (tsx->status_code==401 || tsx->status_code==407) { 
    1554         pjsip_tx_data *tdata; 
    1555         tdata = pjsip_auth_reinit_req(sub->endpt, 
    1556                                       sub->pool, &sub->auth_sess, 
    1557                                       sub->cred_cnt, sub->cred_info, 
    1558                                       tsx->last_tx, event->src.rdata ); 
    1559         if (tdata) { 
    1560             int status; 
    1561             pjsip_cseq_hdr *cseq; 
    1562             cseq = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL); 
    1563             cseq->cseq = sub->cseq++; 
    1564             status = pjsip_endpt_send_request( sub->endpt, tdata,  
    1565                                                -1, sub,  
    1566                                                &on_notify_response); 
    1567             if (status == 0) { 
    1568                 pj_mutex_unlock(sub->mutex); 
    1569                 return; 
    1570             } 
    1571         } 
    1572     } 
    1573  
    1574     /* Notify application. */ 
    1575     if (sub->cb.on_received_notify_response) 
    1576         (*sub->cb.on_received_notify_response)(sub, event); 
    1577  
    1578     /* Check for response 481. */ 
    1579     if (event->obj.tsx->status_code == 481) { 
    1580         /* Remote says that the subscription does not exist!  
    1581          * Terminate subscription! 
    1582          */ 
    1583         sub_set_state(sub, PJSIP_EVENT_SUB_STATE_TERMINATED); 
    1584         if (sub->timer.id) { 
    1585             pjsip_endpt_cancel_timer(sub->endpt, &sub->timer); 
    1586             sub->timer.id = 0; 
    1587         } 
    1588  
    1589         PJ_LOG(4, (THIS_FILE,  
    1590                    "event_sub%p (%s): got 481 response to NOTIFY. Terminating...", 
    1591                    sub, state[sub->state].ptr)); 
    1592  
    1593         /* Notify app. */ 
    1594         if (sub->state!=old_state && sub->cb.on_sub_terminated)  
    1595             (*sub->cb.on_sub_terminated)(sub, &event->src.rdata->msg->line.status.reason); 
    1596     } 
    1597  
    1598     /* Decrement pending transaction count. */ 
    1599     --sub->pending_tsx; 
    1600     pj_assert(sub->pending_tsx >= 0); 
    1601  
    1602     /* Check that the subscription is marked for deletion. */ 
    1603     if (sub->delete_flag && sub->pending_tsx <= 0) { 
    1604         pjsip_event_sub_destroy(sub); 
    1605     } else { 
    1606         pj_mutex_unlock(sub->mutex); 
    1607     } 
    1608  
    1609     /* DO NOT ACCESS sub, IT MIGHT HAVE BEEN DESTROYED! */ 
    1610 } 
    1611  
    1612  
    1613 /* This is the transaction handler for incoming SUBSCRIBE and NOTIFY  
    1614  * requests.  
    1615  */ 
    1616 static void tsx_handler( struct pjsip_module *mod, pjsip_event *event ) 
    1617 { 
    1618     pjsip_msg *msg; 
    1619     pjsip_rx_data *rdata; 
    1620  
    1621     /* Only want incoming message events. */ 
    1622     if (event->src_type != PJSIP_EVENT_RX_MSG) 
    1623         return; 
    1624  
    1625     rdata = event->src.rdata; 
    1626     msg = rdata->msg; 
    1627  
    1628     /* Only want to process request messages. */ 
    1629     if (msg->type != PJSIP_REQUEST_MSG) 
    1630         return; 
    1631  
    1632     /* Only want the first notification. */ 
    1633     if (event->obj.tsx && event->obj.tsx->status_code >= 100) 
    1634         return; 
    1635  
    1636     if (pjsip_method_cmp(&msg->line.req.method, &SUBSCRIBE)==0) { 
    1637         /* Process incoming SUBSCRIBE request. */ 
    1638         on_subscribe_request( event->obj.tsx, rdata ); 
    1639     } else if (pjsip_method_cmp(&msg->line.req.method, &NOTIFY)==0) { 
    1640         /* Process incoming NOTIFY request. */ 
    1641         on_notify_request( event->obj.tsx, rdata ); 
    1642     } 
    1643 } 
    1644  
     1779            evsub_destroy(sub); 
     1780        } 
     1781 
     1782    } 
     1783} 
     1784 
     1785 
Note: See TracChangeset for help on using the changeset viewer.