Commit 30e8c039 authored by Pekka Pessi's avatar Pekka Pessi

nua: fixed the graceful dialog termination after error response

The termination request was sent occasionally sent twice, resulting in
assertion failure. Problem reported by Michael Jerris.

darcs-hash:20070226185130-55b16-bd97966b586a3a9a714e8426c2c017f3b4874184.gz
parent 9b68a147
......@@ -322,6 +322,8 @@ struct nua_dialog_state
nua_server_request_t *ds_sr;
/* Dialog and subscription state */
unsigned ds_reporting:1; /**< We are reporting */
unsigned ds_route:1; /**< We have route */
unsigned ds_terminating:1; /**< Being terminated */
......@@ -411,6 +413,11 @@ int nua_dialog_remove(nua_owner_t *own,
nua_dialog_state_t *ds,
nua_dialog_usage_t *usage);
static inline int nua_dialog_is_reporting(nua_dialog_state_t const *ds)
{
return ds && ds->ds_reporting;
}
char const *nua_dialog_usage_name(nua_dialog_usage_t const *du);
nua_dialog_usage_t *nua_dialog_usage_add(nua_owner_t *,
......@@ -521,9 +528,12 @@ static inline void nua_client_terminating(nua_client_request_t *cr)
int nua_client_init_request(nua_client_request_t *cr);
int nua_client_restart_request(nua_client_request_t *cr,
int terminating,
tagi_t const *tags);
int nua_client_resend_request(nua_client_request_t *cr,
int terminating,
tagi_t const *tags);
int terminating);
int nua_base_client_request(nua_client_request_t *cr,
msg_t *msg,
......@@ -580,9 +590,7 @@ int nua_client_report(nua_client_request_t *cr,
nua_client_request_t *nua_client_request_pending(nua_client_request_t const *);
int nua_client_init_requests(nua_client_request_t *cr,
void const *cr0,
int invite);
int nua_client_next_request(nua_client_request_t *cr, int invite);
/* ---------------------------------------------------------------------- */
......
......@@ -690,6 +690,10 @@ static int nua_notify_client_report(nua_client_request_t *cr,
SIPTAG_EVENT(du ? du->du_event : NULL),
TAG_NEXT(tags));
if (nu && nu->nu_requested && du->du_cr == cr)
/* Re-SUBSCRIBEd while NOTIFY was in progress, resend NOTIFY */
nua_client_resend_request(cr, 0);
return 0;
}
......@@ -699,18 +703,19 @@ static void nua_notify_usage_refresh(nua_handle_t *nh,
nua_dialog_usage_t *du,
sip_time_t now)
{
struct notifier_usage *nu = nua_dialog_usage_private(du);
nua_client_request_t *cr = du->du_cr;
nua_event_t e = nua_r_notify;
if (cr) {
int terminating;
int terminating = 0;
if (nua_client_is_queued(cr)) /* Already notifying. */
return;
if (du->du_expires && du->du_expires <= now)
terminating = 1;
else if (nu->nu_requested && nu->nu_requested <= now)
terminating = 1;
terminating = du->du_expires && du->du_expires <= now;
if (nua_client_resend_request(cr, terminating, NULL) >= 0)
if (nua_client_resend_request(cr, terminating) >= 0)
return;
}
else {
......@@ -738,13 +743,10 @@ static int nua_notify_usage_shutdown(nua_handle_t *nh,
struct notifier_usage *nu = nua_dialog_usage_private(du);
nua_client_request_t *cr = du->du_cr;
if (nua_client_is_queued(cr)) /* Already notifying. */
return -1; /* Request in progress */
nu->nu_substate = nua_substate_terminated;
if (cr) {
if (nua_client_resend_request(cr, 1, NULL) >= 0)
if (nua_client_resend_request(cr, 1) >= 0)
return 0;
}
else {
......
......@@ -398,8 +398,7 @@ static void nua_publish_usage_refresh(nua_handle_t *nh,
nua_client_request_t *cr = du->du_cr;
if (cr) {
if (nua_client_is_queued(cr) /* Already publishing. */
|| nua_client_resend_request(cr, 0, NULL) >= 0)
if (nua_client_resend_request(cr, 0) >= 0)
return;
}
......@@ -423,10 +422,7 @@ static int nua_publish_usage_shutdown(nua_handle_t *nh,
nua_client_request_t *cr = du->du_cr;
if (cr) {
if (nua_client_is_queued(cr)) /* Already publishing. */
return -1;
if (nua_client_resend_request(cr, 1, NULL) >= 0)
if (nua_client_resend_request(cr, 1) >= 0)
return 0;
}
......
......@@ -960,8 +960,7 @@ static void nua_register_usage_refresh(nua_handle_t *nh,
nua_client_request_t *cr = du->du_cr;
if (cr) {
if (nua_client_is_queued(cr) /* Already registering. */
|| nua_client_resend_request(cr, 0, NULL) >= 0)
if (nua_client_resend_request(cr, 0) >= 0)
return;
}
......@@ -987,7 +986,7 @@ static int nua_register_usage_shutdown(nua_handle_t *nh,
if (nua_client_is_queued(cr)) /* Already registering. */
return -1;
cr->cr_event = nua_r_unregister;
if (nua_client_resend_request(cr, 1, NULL) >= 0)
if (nua_client_resend_request(cr, 1) >= 0)
return 0;
}
......
......@@ -1012,7 +1012,8 @@ int nua_stack_ack(nua_t *nua, nua_handle_t *nh, nua_event_t e,
if (!nua_client_is_queued(cr) && !nua_client_is_bound(cr))
nua_client_request_destroy(cr);
nua_client_init_requests(nh->nh_ds->ds_cr, cr, 1);
nua_client_next_request(nh->nh_ds->ds_cr, 1);
return 0;
}
......@@ -1286,7 +1287,7 @@ static void nua_session_usage_refresh(nua_handle_t *nh,
if (!ss->ss_refresher) {
if (du->du_expires == 0 || now < du->du_expires)
/* Refresh contact & route set using re-INVITE */
nua_client_resend_request(du->du_cr, 0, NULL);
nua_client_resend_request(du->du_cr, 0);
else {
ss->ss_reason = "SIP;cause=408;text=\"Session timeout\"";
nua_stack_bye(nh->nh_nua, nh, nua_r_bye, NULL);
......@@ -1296,7 +1297,7 @@ static void nua_session_usage_refresh(nua_handle_t *nh,
nua_stack_update(nh->nh_nua, nh, nua_r_update, NULL);
}
else {
nua_client_resend_request(du->du_cr, 0, NULL);
nua_client_resend_request(du->du_cr, 0);
}
}
......
......@@ -1027,7 +1027,7 @@ nua_stack_authenticate(nua_t *nua, nua_handle_t *nh, nua_event_t e,
nua_client_request_t *cr = nh->nh_ds->ds_cr;
if (cr && cr->cr_challenged) {
nua_client_resend_request(cr, cr->cr_terminating, tags);
nua_client_restart_request(cr, cr->cr_terminating, tags);
}
else {
nua_stack_event(nua, nh, NULL, e,
......@@ -2042,16 +2042,18 @@ int nua_client_init_request(nua_client_request_t *cr)
}
/** Resend the request message.
/** Restart the request message.
*
* @retval 0 if request is pending
* @retval >=1 if error event has been sent
*/
int nua_client_resend_request(nua_client_request_t *cr,
int nua_client_restart_request(nua_client_request_t *cr,
int terminating,
tagi_t const *tags)
{
if (cr) {
assert(nua_client_is_queued(cr));
if (tags && cr->cr_msg)
if (sip_add_tagis(cr->cr_msg, NULL, &tags) < 0)
/* XXX */;
......@@ -2059,13 +2061,35 @@ int nua_client_resend_request(nua_client_request_t *cr,
cr->cr_retry_count = 0;
cr->cr_terminating = terminating;
if (!nua_client_is_queued(cr)) {
if (nua_client_request_queue(cr))
return 0;
if (nua_client_is_reporting(cr))
return 0;
return nua_client_request_try(cr);
}
return 0;
}
/** Resend the request message.
*
* @retval 0 if request is pending
* @retval >=1 if error event has been sent
*/
int nua_client_resend_request(nua_client_request_t *cr,
int terminating)
{
if (cr) {
cr->cr_retry_count = 0;
if (nua_client_is_queued(cr)) {
if (terminating)
cr->cr_graceful = 1;
return 0;
}
if (terminating)
cr->cr_terminating = terminating;
if (nua_client_request_queue(cr))
return 0;
if (nua_dialog_is_reporting(cr->cr_owner->nh_ds))
return 0;
return nua_client_request_try(cr);
}
return 0;
......@@ -2088,7 +2112,6 @@ int nua_client_request_try(nua_client_request_t *cr)
cr->cr_answer_recv = 0, cr->cr_offer_sent = 0;
cr->cr_offer_recv = 0, cr->cr_answer_sent = 0;
cr->cr_terminated = 0, cr->cr_graceful = 0;
if (msg && sip) {
error = nua_client_request_sendmsg(cr, msg, sip);
......@@ -2358,7 +2381,7 @@ int nua_client_response(nua_client_request_t *cr,
else if (cr->cr_terminating || terminated)
cr->cr_terminated = 1;
else if (graceful)
cr->cr_graceful = graceful;
cr->cr_graceful = 1;
}
if (status < 200) {
......@@ -2567,22 +2590,23 @@ int nua_base_client_response(nua_client_request_t *cr,
sip_method_t method = cr->cr_method;
nua_dialog_usage_t *du;
cr->cr_reporting = 1;
cr->cr_reporting = 1, nh->nh_ds->ds_reporting = 1;
if (status >= 200 && status < 300)
nh_challenge(nh, sip); /* Collect nextnonce */
if ((method != sip_method_invite && status >= 200) || status >= 300)
nua_client_request_remove(cr);
nua_client_report(cr, status, phrase, sip, cr->cr_orq, tags);
if (status < 200 ||
/* Un-ACKed 2XX response to INVITE */
(cr->cr_method == sip_method_invite && status < 300 && cr->cr_orq)) {
cr->cr_reporting = 0;
(method == sip_method_invite && status < 300 && cr->cr_orq)) {
cr->cr_reporting = 0, nh->nh_ds->ds_reporting = 0;
return 1;
}
nua_client_request_remove(cr);
if (cr->cr_orq)
nta_outgoing_destroy(cr->cr_orq), cr->cr_orq = NULL;
......@@ -2608,19 +2632,16 @@ int nua_base_client_response(nua_client_request_t *cr,
nua_dialog_remove(nh, nh->nh_ds, NULL);
}
cr->cr_reporting = 0;
if (nua_client_is_queued(cr))
return 1;
cr->cr_reporting = 0, nh->nh_ds->ds_reporting = 0;
if (!nua_client_is_bound(cr))
if (!nua_client_is_queued(cr) && !nua_client_is_bound(cr))
nua_client_request_destroy(cr);
if (method != sip_method_cancel)
return nua_client_init_requests(nh->nh_ds->ds_cr, cr,
method == sip_method_invite);
if (method == sip_method_cancel)
return 1;
return 1;
return
nua_client_next_request(nh->nh_ds->ds_cr, method == sip_method_invite);
}
/** Send event, zap transaction but leave cr in list */
......@@ -2662,13 +2683,8 @@ int nua_client_treport(nua_client_request_t *cr,
return retval;
}
int nua_client_init_requests(nua_client_request_t *cr,
void const *cr0,
int invite)
int nua_client_next_request(nua_client_request_t *cr, int invite)
{
if (cr0 == cr) /* already initialized! */
return 1;
for (; cr; cr = cr->cr_next) {
if (cr->cr_method == sip_method_cancel)
continue;
......@@ -2679,7 +2695,7 @@ int nua_client_init_requests(nua_client_request_t *cr,
break;
}
if (cr)
if (cr && cr->cr_orq == NULL)
nua_client_init_request(cr);
return 1;
......
......@@ -433,8 +433,7 @@ static void nua_subscribe_usage_refresh(nua_handle_t *nh,
}
if (cr) {
if (nua_client_is_queued(cr) || /* Already refreshing */
nua_client_resend_request(cr, 0, NULL) >= 0)
if (nua_client_resend_request(cr, 0) >= 0)
return;
}
else if (eu->eu_refer) {
......@@ -469,10 +468,7 @@ static int nua_subscribe_usage_shutdown(nua_handle_t *nh,
assert(eu); (void)eu;
if (cr) {
if (nua_client_is_queued(cr)) /* Subscribing. */
return -1; /* Request in progress */
if (nua_client_resend_request(cr, 1, NULL) >= 0)
if (nua_client_resend_request(cr, 1) >= 0)
return 0;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment