diff options
author | Benny Prijono <bennylp@teluu.com> | 2006-03-05 11:53:36 +0000 |
---|---|---|
committer | Benny Prijono <bennylp@teluu.com> | 2006-03-05 11:53:36 +0000 |
commit | cb88a08734906fe0e47fef54752d5928ae9d45ac (patch) | |
tree | fd67bf0c001d6193bec0feb4d6e41cba6432ccda /pjsip/src | |
parent | 84ba2655e4a972faf9b763001579b4d5d616cc4b (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')
-rw-r--r-- | pjsip/src/pjsip-simple/evsub.c | 47 | ||||
-rw-r--r-- | pjsip/src/pjsip-simple/iscomposing.c | 7 | ||||
-rw-r--r-- | pjsip/src/pjsip-simple/presence.c | 9 | ||||
-rw-r--r-- | pjsip/src/pjsip-ua/sip_inv.c | 104 | ||||
-rw-r--r-- | pjsip/src/pjsip/sip_dialog.c | 15 | ||||
-rw-r--r-- | pjsip/src/pjsip/sip_errno.c | 7 |
6 files changed, 164 insertions, 25 deletions
diff --git a/pjsip/src/pjsip-simple/evsub.c b/pjsip/src/pjsip-simple/evsub.c index 8218c76e..2a95b2cc 100644 --- a/pjsip/src/pjsip-simple/evsub.c +++ b/pjsip/src/pjsip-simple/evsub.c @@ -198,6 +198,7 @@ struct pjsip_evsub struct evpkg *pkg; /**< The event package. */ unsigned option; /**< Options. */ pjsip_evsub_user user; /**< Callback. */ + pj_bool_t call_cb; /**< Notify callback? */ pjsip_role_e role; /**< UAC=subscriber, UAS=notifier */ pjsip_evsub_state state; /**< Subscription state. */ pj_str_t state_str; /**< String describing the state. */ @@ -509,6 +510,7 @@ static void evsub_destroy( pjsip_evsub *sub ) static void set_state( pjsip_evsub *sub, pjsip_evsub_state state, const pj_str_t *state_str, pjsip_event *event) { + pjsip_evsub_state prev_state = sub->state; pj_str_t old_state_str = sub->state_str; sub->state = state; @@ -525,11 +527,12 @@ static void set_state( pjsip_evsub *sub, pjsip_evsub_state state, (int)sub->state_str.slen, sub->state_str.ptr)); - if (sub->user.on_evsub_state) + if (sub->user.on_evsub_state && sub->call_cb) (*sub->user.on_evsub_state)(sub, event); - if (state == PJSIP_EVSUB_STATE_TERMINATED) { - + if (state == PJSIP_EVSUB_STATE_TERMINATED && + prev_state != PJSIP_EVSUB_STATE_TERMINATED) + { if (sub->pending_tsx == 0) { evsub_destroy(sub); } @@ -559,7 +562,7 @@ static void on_timer( pj_timer_heap_t *timer_heap, case TIMER_TYPE_UAC_REFRESH: /* Time for UAC to refresh subscription */ - if (sub->user.on_client_refresh) { + if (sub->user.on_client_refresh && sub->call_cb) { (*sub->user.on_client_refresh)(sub); } else { pjsip_tx_data *tdata; @@ -576,7 +579,7 @@ static void on_timer( pj_timer_heap_t *timer_heap, case TIMER_TYPE_UAS_TIMEOUT: /* Refresh from UAC has not been received */ - if (sub->user.on_server_timeout) { + if (sub->user.on_server_timeout && sub->call_cb) { (*sub->user.on_server_timeout)(sub); } else { pjsip_tx_data *tdata; @@ -652,6 +655,7 @@ static pj_status_t evsub_create( pjsip_dialog *dlg, sub->dlg = dlg; sub->pkg = pkg; sub->role = role; + sub->call_cb = PJ_TRUE; sub->option = option; sub->state = PJSIP_EVSUB_STATE_NULL; sub->state_str = evsub_state_names[sub->state]; @@ -839,6 +843,29 @@ on_return: /* + * Forcefully destroy subscription. + */ +PJ_DEF(pj_status_t) pjsip_evsub_terminate( pjsip_evsub *sub, + pj_bool_t notify ) +{ + PJ_ASSERT_RETURN(sub, PJ_EINVAL); + + pjsip_dlg_inc_lock(sub->dlg); + + if (sub->pending_tsx) { + pj_assert(!"Unable to terminate when there's pending tsx"); + pjsip_dlg_dec_lock(sub->dlg); + return PJ_EINVALIDOP; + } + + sub->call_cb = notify; + set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, NULL); + + pjsip_dlg_dec_lock(sub->dlg); + return PJ_SUCCESS; +} + +/* * Get subscription state. */ PJ_DEF(pjsip_evsub_state) pjsip_evsub_get_state(pjsip_evsub *sub) @@ -1613,7 +1640,7 @@ static void on_tsx_state_uac( pjsip_evsub *sub, pjsip_transaction *tsx, /* Call application registered callback to handle incoming NOTIFY, * if any. */ - if (st_code==200 && sub->user.on_rx_notify) { + if (st_code==200 && sub->user.on_rx_notify && sub->call_cb) { (*sub->user.on_rx_notify)(sub, rdata, &st_code, &st_text, &res_hdr, &body); @@ -1781,8 +1808,10 @@ static void on_tsx_state_uas( pjsip_evsub *sub, pjsip_transaction *tsx, */ pj_list_init(&res_hdr); - (*sub->user.on_rx_refresh)(sub, rdata, &st_code, &st_text, - &res_hdr, &body); + if (sub->user.on_rx_refresh && sub->call_cb) { + (*sub->user.on_rx_refresh)(sub, rdata, &st_code, &st_text, + &res_hdr, &body); + } /* Application MUST specify final response! */ PJ_ASSERT_ON_FAIL(st_code >= 200, {st_code=200; }); @@ -1886,7 +1915,7 @@ static void mod_evsub_on_tsx_state(pjsip_transaction *tsx, pjsip_event *event) /* Call on_tsx_state callback, if any. */ - if (sub->user.on_tsx_state) + if (sub->user.on_tsx_state && sub->call_cb) (*sub->user.on_tsx_state)(sub, tsx, event); diff --git a/pjsip/src/pjsip-simple/iscomposing.c b/pjsip/src/pjsip-simple/iscomposing.c index 369281af..38fa578e 100644 --- a/pjsip/src/pjsip-simple/iscomposing.c +++ b/pjsip/src/pjsip-simple/iscomposing.c @@ -80,9 +80,10 @@ PJ_DEF(pj_xml_node*) pjsip_iscomposing_create_xml( pj_pool_t *pool, pj_xml_add_node(doc, node); /* Add lastactive, if any. */ - if (!is_composing && lst_actv) { - PJ_TODO(IMPLEMENT_LAST_ACTIVE_ATTRIBUTE); - } + PJ_UNUSED_ARG(lst_actv); + //if (!is_composing && lst_actv) { + // PJ_TODO(IMPLEMENT_LAST_ACTIVE_ATTRIBUTE); + //} /* Add contenttype, if any. */ if (content_tp) { diff --git a/pjsip/src/pjsip-simple/presence.c b/pjsip/src/pjsip-simple/presence.c index f8014fce..88e38152 100644 --- a/pjsip/src/pjsip-simple/presence.c +++ b/pjsip/src/pjsip-simple/presence.c @@ -322,6 +322,15 @@ on_return: /* + * Forcefully terminate presence. + */ +PJ_DEF(pj_status_t) pjsip_pres_terminate( pjsip_evsub *sub, + pj_bool_t notify ) +{ + return pjsip_evsub_terminate(sub, notify); +} + +/* * Create SUBSCRIBE */ PJ_DEF(pj_status_t) pjsip_pres_initiate( pjsip_evsub *sub, 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); } } diff --git a/pjsip/src/pjsip/sip_dialog.c b/pjsip/src/pjsip/sip_dialog.c index 4139b221..795e103b 100644 --- a/pjsip/src/pjsip/sip_dialog.c +++ b/pjsip/src/pjsip/sip_dialog.c @@ -613,6 +613,21 @@ static pj_status_t unregister_and_destroy_dialog( pjsip_dialog *dlg ) /* + * Forcefully terminate dialog. + */ +PJ_DEF(pj_status_t) pjsip_dlg_terminate( pjsip_dialog *dlg ) +{ + /* Number of sessions must be zero. */ + PJ_ASSERT_RETURN(dlg->sess_count==0, PJ_EINVALIDOP); + + /* MUST not have pending transactions. */ + PJ_ASSERT_RETURN(dlg->tsx_count==0, PJ_EINVALIDOP); + + return unregister_and_destroy_dialog(dlg); +} + + +/* * Set route_set */ PJ_DEF(pj_status_t) pjsip_dlg_set_route_set( pjsip_dialog *dlg, diff --git a/pjsip/src/pjsip/sip_errno.c b/pjsip/src/pjsip/sip_errno.c index d62d9188..87909e6b 100644 --- a/pjsip/src/pjsip/sip_errno.c +++ b/pjsip/src/pjsip/sip_errno.c @@ -82,7 +82,12 @@ static const struct { PJSIP_EAUTHINVALIDDIGEST, "Invalid authorization digest" }, /* UA/dialog layer. */ - { PJSIP_EMISSINGTAG, "Missing From/To tag parameter" } + { PJSIP_EMISSINGTAG, "Missing From/To tag parameter" }, + { PJSIP_ENOTREFER, "Expecting REFER request"} , + { PJSIP_ENOREFERSESSION, "Not associated with REFER subscription"}, + + /* Invite session. */ + { PJSIP_ESESSIONTERMINATED, "Session already terminated" }, }; |