summaryrefslogtreecommitdiff
path: root/pjsip/src/pjsip-ua/sip_inv.c
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2006-03-05 11:53:36 +0000
committerBenny Prijono <bennylp@teluu.com>2006-03-05 11:53:36 +0000
commitcb88a08734906fe0e47fef54752d5928ae9d45ac (patch)
treefd67bf0c001d6193bec0feb4d6e41cba6432ccda /pjsip/src/pjsip-ua/sip_inv.c
parent84ba2655e4a972faf9b763001579b4d5d616cc4b (diff)
Added API to terminate dialog prematurely. Affect: dialog, invite sessions, evsub, and presence
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@283 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjsip/src/pjsip-ua/sip_inv.c')
-rw-r--r--pjsip/src/pjsip-ua/sip_inv.c104
1 files changed, 92 insertions, 12 deletions
diff --git a/pjsip/src/pjsip-ua/sip_inv.c b/pjsip/src/pjsip-ua/sip_inv.c
index 9b55f25b..c1142501 100644
--- a/pjsip/src/pjsip-ua/sip_inv.c
+++ b/pjsip/src/pjsip-ua/sip_inv.c
@@ -124,12 +124,25 @@ static pj_status_t mod_inv_unload(void)
void inv_set_state(pjsip_inv_session *inv, pjsip_inv_state state,
pjsip_event *e)
{
+ pjsip_inv_state prev_state = inv->state;
+
+ /* Set state. */
inv->state = state;
- if (mod_inv.cb.on_state_changed)
+
+ /* If state is DISCONNECTED, cause code MUST have been set. */
+ pj_assert(inv->state != PJSIP_INV_STATE_DISCONNECTED ||
+ inv->cause != 0);
+
+ /* Call on_state_changed() callback. */
+ if (mod_inv.cb.on_state_changed && inv->notify)
(*mod_inv.cb.on_state_changed)(inv, e);
- if (inv->state == PJSIP_INV_STATE_DISCONNECTED)
+ /* Only decrement when previous state is not already DISCONNECTED */
+ if (inv->state == PJSIP_INV_STATE_DISCONNECTED &&
+ prev_state != PJSIP_INV_STATE_DISCONNECTED)
+ {
pjsip_dlg_dec_session(inv->dlg, &mod_inv.mod);
+ }
}
@@ -290,7 +303,7 @@ static void mod_inv_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e)
(*inv_state_handler[inv->state])(inv, e);
/* Call on_tsx_state */
- if (mod_inv.cb.on_tsx_state_changed)
+ if (mod_inv.cb.on_tsx_state_changed && inv->notify)
(*mod_inv.cb.on_tsx_state_changed)(inv, tsx, e);
/* Clear invite transaction when tsx is terminated. */
@@ -378,6 +391,8 @@ PJ_DEF(pj_status_t) pjsip_inv_create_uac( pjsip_dialog *dlg,
inv->state = PJSIP_INV_STATE_NULL;
inv->dlg = dlg;
inv->options = options;
+ inv->notify = PJ_TRUE;
+ inv->cause = 0;
/* Object name will use the same dialog pointer. */
pj_snprintf(inv->obj_name, PJ_MAX_OBJ_NAME, "inv%p", dlg);
@@ -774,6 +789,8 @@ PJ_DEF(pj_status_t) pjsip_inv_create_uas( pjsip_dialog *dlg,
inv->state = PJSIP_INV_STATE_NULL;
inv->dlg = dlg;
inv->options = options;
+ inv->notify = PJ_TRUE;
+ inv->cause = 0;
/* Object name will use the same dialog pointer. */
pj_snprintf(inv->obj_name, PJ_MAX_OBJ_NAME, "inv%p", dlg);
@@ -833,6 +850,50 @@ PJ_DEF(pj_status_t) pjsip_inv_create_uas( pjsip_dialog *dlg,
return PJ_SUCCESS;
}
+/*
+ * Forcefully terminate the session.
+ */
+PJ_DEF(pj_status_t) pjsip_inv_terminate( pjsip_inv_session *inv,
+ int st_code,
+ pj_bool_t notify)
+{
+ PJ_ASSERT_RETURN(inv, PJ_EINVAL);
+
+ /* Lock dialog. */
+ pjsip_dlg_inc_lock(inv->dlg);
+
+ /* Set callback notify flag. */
+ inv->notify = notify;
+
+ /* If there's pending transaction, terminate the transaction.
+ * This may subsequently set the INVITE session state to
+ * disconnected.
+ */
+ if (inv->invite_tsx &&
+ inv->invite_tsx->state <= PJSIP_TSX_STATE_COMPLETED)
+ {
+ pjsip_tsx_terminate(inv->invite_tsx, st_code);
+
+ }
+
+ /* Set cause. */
+ inv->cause = st_code;
+
+ /* Forcefully terminate the session if state is not DISCONNECTED */
+ if (inv->state != PJSIP_INV_STATE_DISCONNECTED) {
+ inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, NULL);
+ }
+
+ /* Done.
+ * The dec_lock() below will actually destroys the dialog if it
+ * has no other session.
+ */
+ pjsip_dlg_dec_lock(inv->dlg);
+
+ return PJ_SUCCESS;
+}
+
+
static void *clone_sdp(pj_pool_t *pool, const void *data, unsigned len)
{
PJ_UNUSED_ARG(len);
@@ -974,7 +1035,7 @@ static pj_status_t inv_negotiate_sdp( pjsip_inv_session *inv )
PJ_LOG(5,(inv->obj_name, "SDP negotiation done, status=%d", status));
- if (mod_inv.cb.on_media_update)
+ if (mod_inv.cb.on_media_update && inv->notify)
(*mod_inv.cb.on_media_update)(inv, status);
return status;
@@ -1063,7 +1124,7 @@ static pj_status_t inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv,
/* Inform application about remote offer. */
- if (mod_inv.cb.on_rx_offer) {
+ if (mod_inv.cb.on_rx_offer && inv->notify) {
(*mod_inv.cb.on_rx_offer)(inv, sdp);
@@ -1304,6 +1365,9 @@ PJ_DEF(pj_status_t) pjsip_inv_end_session( pjsip_inv_session *inv,
/* Verify arguments. */
PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
+ /* Set cause code. */
+ if (inv->cause==0) inv->cause = st_code;
+
/* Create appropriate message. */
switch (inv->state) {
case PJSIP_INV_STATE_CALLING:
@@ -1358,8 +1422,7 @@ PJ_DEF(pj_status_t) pjsip_inv_end_session( pjsip_inv_session *inv,
case PJSIP_INV_STATE_DISCONNECTED:
/* No need to do anything. */
- PJ_TODO(RETURN_A_PROPER_STATUS_CODE_HERE);
- return PJ_EINVALIDOP;
+ return PJSIP_ESESSIONTERMINATED;
default:
pj_assert("!Invalid operation!");
@@ -1612,8 +1675,10 @@ static void inv_respond_incoming_bye( pjsip_inv_session *inv,
/* Terminate session: */
- if (inv->state != PJSIP_INV_STATE_DISCONNECTED)
+ if (inv->state != PJSIP_INV_STATE_DISCONNECTED) {
+ if (inv->cause==0) inv->cause=PJSIP_SC_OK;
inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
+ }
}
/*
@@ -1627,6 +1692,7 @@ static void inv_handle_bye_response( pjsip_inv_session *inv,
pj_status_t status;
if (e->body.tsx_state.type != PJSIP_EVENT_RX_MSG) {
+ if (inv->cause==0) inv->cause=PJSIP_SC_OK;
inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
return;
}
@@ -1646,6 +1712,7 @@ static void inv_handle_bye_response( pjsip_inv_session *inv,
/* Does not have proper credentials.
* End the session anyway.
*/
+ if (inv->cause==0) inv->cause=PJSIP_SC_OK;
inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
} else {
@@ -1656,7 +1723,7 @@ static void inv_handle_bye_response( pjsip_inv_session *inv,
} else {
/* End the session. */
-
+ if (inv->cause==0) inv->cause=PJSIP_SC_OK;
inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
}
@@ -1774,6 +1841,7 @@ static void inv_on_state_calling( pjsip_inv_session *inv, pjsip_event *e)
/* Does not have proper credentials.
* End the session.
*/
+ if (inv->cause==0) inv->cause = tsx->status_code;
inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
} else {
@@ -1788,6 +1856,7 @@ static void inv_on_state_calling( pjsip_inv_session *inv, pjsip_event *e)
} else {
+ if (inv->cause==0) inv->cause = tsx->status_code;
inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
}
@@ -1815,6 +1884,7 @@ static void inv_on_state_calling( pjsip_inv_session *inv, pjsip_event *e)
} else {
+ if (inv->cause==0) inv->cause = tsx->status_code;
inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
}
break;
@@ -1837,6 +1907,7 @@ static void inv_on_state_calling( pjsip_inv_session *inv, pjsip_event *e)
tsx->status_code == PJSIP_SC_TSX_TIMEOUT ||
PJSIP_SC_TSX_TRANSPORT_ERROR)
{
+ if (inv->cause==0) inv->cause = tsx->status_code;
inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
}
}
@@ -1877,10 +1948,12 @@ static void inv_on_state_incoming( pjsip_inv_session *inv, pjsip_event *e)
/*
* Transaction sent final response.
*/
- if (tsx->status_code/100 == 2)
+ if (tsx->status_code/100 == 2) {
inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
- else
+ } else {
+ if (inv->cause==0) inv->cause = tsx->status_code;
inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
+ }
break;
case PJSIP_TSX_STATE_TERMINATED:
@@ -1888,6 +1961,7 @@ static void inv_on_state_incoming( pjsip_inv_session *inv, pjsip_event *e)
* This happens on transport error (e.g. failed to send
* response)
*/
+ if (inv->cause==0) inv->cause = tsx->status_code;
inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
break;
@@ -1948,8 +2022,10 @@ static void inv_on_state_early( pjsip_inv_session *inv, pjsip_event *e)
e->body.tsx_state.src.rdata);
}
- } else
+ } else {
+ if (inv->cause==0) inv->cause = tsx->status_code;
inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
+ }
break;
case PJSIP_TSX_STATE_CONFIRMED:
@@ -1981,6 +2057,7 @@ static void inv_on_state_early( pjsip_inv_session *inv, pjsip_event *e)
}
} else {
+ if (inv->cause==0) inv->cause = tsx->status_code;
inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
}
break;
@@ -2016,6 +2093,7 @@ static void inv_on_state_early( pjsip_inv_session *inv, pjsip_event *e)
tsx->status_code == PJSIP_SC_TSX_TIMEOUT ||
PJSIP_SC_TSX_TRANSPORT_ERROR)
{
+ if (inv->cause==0) inv->cause = tsx->status_code;
inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
}
}
@@ -2049,6 +2127,7 @@ static void inv_on_state_connecting( pjsip_inv_session *inv, pjsip_event *e)
* error.
*/
if (tsx->status_code/100 != 2) {
+ if (inv->cause==0) inv->cause = tsx->status_code;
inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
}
break;
@@ -2240,6 +2319,7 @@ static void inv_on_state_confirmed( pjsip_inv_session *inv, pjsip_event *e)
/*
* Handle responses that terminates dialog.
*/
+ if (inv->cause==0) inv->cause = tsx->status_code;
inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
}
}