Changeset 197 for pjproject/trunk/pjsip/src/pjsip-simple/evsub.c
- Timestamp:
- Feb 19, 2006 1:38:06 AM (18 years ago)
- File:
-
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjsip/src/pjsip-simple/evsub.c
- Property svn:keywords set to id
r187 r197 17 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 18 */ 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> 22 24 #include <pjsip/sip_endpoint.h> 23 #include <pjsip/sip_module.h> 25 #include <pjsip/sip_dialog.h> 26 #include <pjsip/sip_auth.h> 24 27 #include <pjsip/sip_transaction.h> 25 28 #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> 26 33 #include <pj/pool.h> 27 #include <pj/timer.h>28 34 #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 */ 46 enum 47 { 48 PJSIP_SUBSCRIBE_METHOD = PJSIP_OTHER_METHOD, 49 PJSIP_NOTIFY_METHOD = PJSIP_OTHER_METHOD 46 50 }; 47 51 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 52 const pjsip_method pjsip_subscribe_method = 53 { 54 PJSIP_SUBSCRIBE_METHOD, 55 { "SUBSCRIBE", 9 } 56 }; 57 58 const pjsip_method pjsip_notify_method = 59 { 60 PJSIP_NOTIFY_METHOD, 61 { "NOTIFY", 6 } 62 }; 63 64 /* 65 * Static prototypes. 66 */ 67 static void mod_evsub_on_tsx_state(pjsip_transaction*, pjsip_event*); 68 static pj_status_t mod_evsub_unload(void); 69 70 71 /* 72 * State names. 73 */ 74 static 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 */ 105 enum 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 132 static 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 */ 144 struct 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 */ 158 static 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 */ 190 struct 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 */ 220 struct dlgsub 221 { 222 PJ_DECL_LIST_MEMBER(struct dlgsub); 223 pjsip_evsub *sub; 224 }; 225 59 226 60 227 /* 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)); 228 static const pj_str_t STR_EVENT = { "Event", 5 }; 229 static const pj_str_t STR_SUB_STATE = { "Subscription-State", 18 }; 230 static const pj_str_t STR_TERMINATED = { "terminated", 10 }; 231 static const pj_str_t STR_ACTIVE = { "active", 6 }; 232 static const pj_str_t STR_PENDING = { "pending", 7 }; 233 static const pj_str_t STR_TIMEOUT = { "timeout", 7}; 234 235 /* 236 * On unload module. 237 */ 238 static 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 */ 249 PJ_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 280 on_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 */ 293 PJ_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 */ 304 PJ_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 */ 313 PJ_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 */ 324 PJ_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 */ 334 static 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 */ 354 PJ_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; 195 381 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 */ 414 static 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 */ 424 static 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 */ 455 static 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 */ 484 static 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 */ 518 static 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 */ 607 static 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; 408 616 pj_status_t status; 409 617 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 */ 687 PJ_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 711 on_return: 712 pjsip_dlg_dec_lock(dlg); 414 713 return status; 415 714 } 416 715 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 */ 720 PJ_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 805 on_return: 806 pjsip_dlg_dec_lock(dlg); 807 return status; 808 } 809 810 811 /* 812 * Get subscription state. 813 */ 814 PJ_DEF(pjsip_evsub_state) pjsip_evsub_get_state(pjsip_evsub *sub) 815 { 816 return sub->state; 817 } 818 819 /* 820 * Get state name. 821 */ 822 PJ_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 */ 831 PJ_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) 481 835 { 482 836 pjsip_tx_data *tdata; 483 837 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 880 on_return: 881 882 pjsip_dlg_dec_lock(sub->dlg); 883 return status; 884 } 885 886 887 /* 888 * Accept incoming subscription request. 889 */ 890 PJ_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 937 on_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 */ 948 static 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 */ 1000 PJ_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 1050 on_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 */ 1060 PJ_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 */ 1071 PJ_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) 490 1095 { 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 1109 on_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 */ 1119 static 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 */ 1230 static 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 */ 1277 static 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 538 1296 } 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 */ 1307 static 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. 931 1315 */ 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; 1063 1384 } 1064 1385 } 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 */ 1270 1432 return; 1271 1433 } 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 */ 1589 static 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. 1290 1597 * 1291 * Note:1292 * Since we normally send SUBSCRIBE for refreshing the subscription,1293 * it means the subscription already expired anyway. So we terminate1294 * the subscription now.1295 1598 */ 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 1304 1731 } 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 1316 1733 /* 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! 1320 1735 */ 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 */ 1746 static 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); 1375 1766 } 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) 1429 1778 { 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.