diff options
author | Benny Prijono <bennylp@teluu.com> | 2006-02-19 01:37:35 +0000 |
---|---|---|
committer | Benny Prijono <bennylp@teluu.com> | 2006-02-19 01:37:35 +0000 |
commit | 4e0f563feccb847c57739e48c91b0f5190938e9d (patch) | |
tree | ac26a241075ecee42dbf7142a5ea3ca3896d90d4 /pjsip/src | |
parent | d0a140b588b68d113e5444e711b44e3775b14faa (diff) |
Fixed premature dialog deletion, causing crash
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@196 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjsip/src')
-rw-r--r-- | pjsip/src/pjsip/sip_dialog.c | 168 |
1 files changed, 110 insertions, 58 deletions
diff --git a/pjsip/src/pjsip/sip_dialog.c b/pjsip/src/pjsip/sip_dialog.c index 6afbb2ab..3056469c 100644 --- a/pjsip/src/pjsip/sip_dialog.c +++ b/pjsip/src/pjsip/sip_dialog.c @@ -41,12 +41,14 @@ long pjsip_dlg_lock_tls_id; PJ_DEF(pj_bool_t) pjsip_method_creates_dialog(const pjsip_method *m) { - pjsip_method subscribe = { PJSIP_OTHER_METHOD, {"SUBSCRIBE", 10}}; - pjsip_method refer = { PJSIP_OTHER_METHOD, {"REFER", 5}}; + const pjsip_method subscribe = { PJSIP_OTHER_METHOD, {"SUBSCRIBE", 9}}; + const pjsip_method refer = { PJSIP_OTHER_METHOD, {"REFER", 5}}; + const pjsip_method notify = { PJSIP_OTHER_METHOD, {"NOTIFY", 6}}; return m->id == PJSIP_INVITE_METHOD || (pjsip_method_cmp(m, &subscribe)==0) || - (pjsip_method_cmp(m, &refer)==0); + (pjsip_method_cmp(m, &refer)==0) || + (pjsip_method_cmp(m, ¬ify)==0); } static pj_status_t create_dialog( pjsip_user_agent *ua, @@ -597,34 +599,51 @@ PJ_DEF(pj_status_t) pjsip_dlg_inc_session( pjsip_dialog *dlg, } /* - * Decrement session counter. + * Lock dialog and increment session counter temporarily + * to prevent it from being deleted. */ -PJ_DEF(pj_status_t) pjsip_dlg_dec_session( pjsip_dialog *dlg, - pjsip_module *mod) +PJ_DEF(void) pjsip_dlg_inc_lock(pjsip_dialog *dlg) { - pj_status_t status; - - PJ_ASSERT_RETURN(dlg, PJ_EINVAL); - - PJ_LOG(5,(dlg->obj_name, "Session count dec to %d by %.*s", - dlg->sess_count-1, (int)mod->name.slen, mod->name.ptr)); - pj_mutex_lock(dlg->mutex); + dlg->sess_count++; +} + +/* + * Unlock dialog and decrement session counter. + * It may delete the dialog! + */ +PJ_DEF(void) pjsip_dlg_dec_lock(pjsip_dialog *dlg) +{ pj_assert(dlg->sess_count > 0); --dlg->sess_count; if (dlg->sess_count==0 && dlg->tsx_count==0) - status = unregister_and_destroy_dialog(dlg); + unregister_and_destroy_dialog(dlg); else { pj_mutex_unlock(dlg->mutex); - status = PJ_SUCCESS; } - - return status; } + +/* + * Decrement session counter. + */ +PJ_DEF(pj_status_t) pjsip_dlg_dec_session( pjsip_dialog *dlg, + pjsip_module *mod) +{ + PJ_ASSERT_RETURN(dlg, PJ_EINVAL); + + PJ_LOG(5,(dlg->obj_name, "Session count dec to %d by %.*s", + dlg->sess_count-1, (int)mod->name.slen, mod->name.ptr)); + + pj_mutex_lock(dlg->mutex); + pjsip_dlg_dec_lock(dlg); + + return PJ_SUCCESS; +} + /* * Add usage. */ @@ -639,8 +658,9 @@ PJ_DEF(pj_status_t) pjsip_dlg_add_usage( pjsip_dialog *dlg, PJ_EINVAL); PJ_ASSERT_RETURN(dlg->usage_cnt < PJSIP_MAX_MODULE, PJ_EBUG); - PJ_LOG(5,(dlg->obj_name, "Module %.*s added as dialog usage", - (int)mod->name.slen, mod->name.ptr)); + PJ_LOG(5,(dlg->obj_name, + "Module %.*s added as dialog usage, data=%p", + (int)mod->name.slen, mod->name.ptr, mod_data)); pj_mutex_lock(dlg->mutex); @@ -678,6 +698,35 @@ PJ_DEF(pj_status_t) pjsip_dlg_add_usage( pjsip_dialog *dlg, /* + * Attach module specific data to the dialog. Application can also set + * the value directly by accessing dlg->mod_data[module_id]. + */ +PJ_DEF(pj_status_t) pjsip_dlg_set_mod_data( pjsip_dialog *dlg, + int mod_id, + void *data ) +{ + PJ_ASSERT_RETURN(dlg, PJ_EINVAL); + PJ_ASSERT_RETURN(mod_id >= 0 && mod_id < PJSIP_MAX_MODULE, + PJ_EINVAL); + dlg->mod_data[mod_id] = data; + return PJ_SUCCESS; +} + +/** + * Get module specific data previously attached to the dialog. Application + * can also get value directly by accessing dlg->mod_data[module_id]. + */ +PJ_DEF(void*) pjsip_dlg_get_mod_data( pjsip_dialog *dlg, + int mod_id) +{ + PJ_ASSERT_RETURN(dlg, NULL); + PJ_ASSERT_RETURN(mod_id >= 0 && mod_id < PJSIP_MAX_MODULE, + NULL); + return dlg->mod_data[mod_id]; +} + + +/* * Create a new request within dialog (i.e. after the dialog session has been * established). The construction of such requests follows the rule in * RFC3261 section 12.2.1. @@ -813,8 +862,8 @@ PJ_DEF(pj_status_t) pjsip_dlg_send_request( pjsip_dialog *dlg, PJ_LOG(5,(dlg->obj_name, "Sending %s", pjsip_tx_data_get_info(tdata))); - /* Update CSeq */ - pj_mutex_lock(dlg->mutex); + /* Lock and increment session */ + pjsip_dlg_inc_lock(dlg); /* Update dialog's CSeq and message's CSeq if request is not * ACK nor CANCEL. @@ -869,14 +918,14 @@ PJ_DEF(pj_status_t) pjsip_dlg_send_request( pjsip_dialog *dlg, *p_tsx = NULL; } - /* Unlock dialog. */ - pj_mutex_unlock(dlg->mutex); + /* Unlock dialog, may destroy dialog. */ + pjsip_dlg_dec_lock(dlg); return PJ_SUCCESS; on_error: - /* Unlock dialog. */ - pj_mutex_unlock(dlg->mutex); + /* Unlock dialog, may destroy dialog. */ + pjsip_dlg_dec_lock(dlg); /* Whatever happen delete the message. */ pjsip_tx_data_dec_ref( tdata ); @@ -1003,7 +1052,8 @@ PJ_DEF(pj_status_t) pjsip_dlg_modify_response( pjsip_dialog *dlg, PJSIP_ENOTRESPONSEMSG); PJ_ASSERT_RETURN(st_code >= 100 && st_code <= 699, PJ_EINVAL); - pj_mutex_lock(dlg->mutex); + /* Lock and increment session */ + pjsip_dlg_inc_lock(dlg); /* Replace status code and reason */ tdata->msg->line.status.code = st_code; @@ -1022,7 +1072,8 @@ PJ_DEF(pj_status_t) pjsip_dlg_modify_response( pjsip_dialog *dlg, /* Force to re-print message. */ pjsip_tx_data_invalidate_msg(tdata); - pj_mutex_unlock(dlg->mutex); + /* Unlock dialog and dec session, may destroy dialog. */ + pjsip_dlg_dec_lock(dlg); return PJ_SUCCESS; } @@ -1103,8 +1154,8 @@ void pjsip_dlg_on_rx_request( pjsip_dialog *dlg, pjsip_rx_data *rdata ) PJ_LOG(5,(dlg->obj_name, "Received %s", pjsip_rx_data_get_info(rdata))); - /* Lock the dialog. */ - pj_mutex_lock(dlg->mutex); + /* Lock dialog and increment session. */ + pjsip_dlg_inc_lock(dlg); /* Check CSeq */ if (rdata->msg_info.cseq->cseq <= dlg->remote.cseq && @@ -1114,16 +1165,31 @@ void pjsip_dlg_on_rx_request( pjsip_dialog *dlg, pjsip_rx_data *rdata ) /* Invalid CSeq. * Respond statelessly with 500 (Internal Server Error) */ - pj_mutex_unlock(dlg->mutex); + pj_str_t warn_text; + + /* Unlock dialog and dec session, may destroy dialog. */ + pjsip_dlg_dec_lock(dlg); + pj_assert(pjsip_rdata_get_tsx(rdata) == NULL); + warn_text = pj_str("Invalid CSeq"); pjsip_endpt_respond_stateless(dlg->endpt, - rdata, 500, NULL, NULL, NULL); + rdata, 500, &warn_text, NULL, NULL); return; } /* Update CSeq. */ dlg->remote.cseq = rdata->msg_info.cseq->cseq; + /* Update To tag if necessary. + * This only happens if UAS sends a new request before answering + * our request (e.g. UAS sends NOTIFY before answering our + * SUBSCRIBE request). + */ + if (dlg->remote.info->tag.slen == 0) { + pj_strdup(dlg->pool, &dlg->remote.info->tag, + &rdata->msg_info.from->tag); + } + /* Create UAS transaction for this request. */ if (pjsip_rdata_get_tsx(rdata) == NULL && rdata->msg_info.msg->line.req.method.id != PJSIP_ACK_METHOD) @@ -1156,8 +1222,8 @@ void pjsip_dlg_on_rx_request( pjsip_dialog *dlg, pjsip_rx_data *rdata ) pjsip_tsx_recv_msg(tsx, rdata); on_return: - /* Unlock dialog. */ - pj_mutex_unlock(dlg->mutex); + /* Unlock dialog and dec session, may destroy dialog. */ + pjsip_dlg_dec_lock(dlg); } /* This function is called by user agent upon receiving incoming response @@ -1171,8 +1237,8 @@ void pjsip_dlg_on_rx_response( pjsip_dialog *dlg, pjsip_rx_data *rdata ) PJ_LOG(5,(dlg->obj_name, "Received %s", pjsip_rx_data_get_info(rdata))); - /* Lock the dialog. */ - pj_mutex_lock(dlg->mutex); + /* Lock the dialog and inc session. */ + pjsip_dlg_inc_lock(dlg); /* Check that rdata already has dialog in mod_data. */ pj_assert(pjsip_rdata_get_dlg(rdata) == dlg); @@ -1264,8 +1330,8 @@ void pjsip_dlg_on_rx_response( pjsip_dialog *dlg, pjsip_rx_data *rdata ) pjsip_rx_data_get_info(rdata))); } - /* Unlock dialog. */ - pj_mutex_unlock(dlg->mutex); + /* Unlock dialog and dec session, may destroy dialog. */ + pjsip_dlg_dec_lock(dlg); } /* This function is called by user agent upon receiving transaction @@ -1280,14 +1346,8 @@ void pjsip_dlg_on_tsx_state( pjsip_dialog *dlg, PJ_LOG(5,(dlg->obj_name, "Transaction %s state changed to %s", tsx->obj_name, pjsip_tsx_state_str(tsx->state))); - /* Lock the dialog. */ - pj_mutex_lock(dlg->mutex); - - if (tsx->state == PJSIP_TSX_STATE_TERMINATED) - --dlg->tsx_count; - - /* Increment session to prevent usages from destroying dialog. */ - ++dlg->sess_count; + /* Lock the dialog and increment session. */ + pjsip_dlg_inc_lock(dlg); /* Pass to dialog usages. */ for (i=0; i<dlg->usage_cnt; ++i) { @@ -1298,21 +1358,13 @@ void pjsip_dlg_on_tsx_state( pjsip_dialog *dlg, (*dlg->usage[i]->on_tsx_state)(tsx, e); } - /* Decrement temporary session. */ - --dlg->sess_count; - if (tsx->state == PJSIP_TSX_STATE_TERMINATED && dlg->tsx_count == 0 && - dlg->sess_count == 0) - { - /* Unregister this dialog from the transaction. */ + if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { + --dlg->tsx_count; tsx->mod_data[dlg->ua->id] = NULL; - - /* Time to destroy dialog. */ - unregister_and_destroy_dialog(dlg); - - } else { - /* Unlock dialog. */ - pj_mutex_unlock(dlg->mutex); } + + /* Unlock dialog and dec session, may destroy dialog. */ + pjsip_dlg_dec_lock(dlg); } |