Commit ba22680b authored by Pekka Pessi's avatar Pekka Pessi

nua: dialog termination code did not always destroy nta_leg_t

Stack crashed if an another request was sent using same dialog as the
initial request rejected by stack. Reported by Michael Jerris.

darcs-hash:20070223111055-55b16-87a055f868fb3c27a1f28aeb7146d3a4f41985f1.gz
parent 05dd9730
......@@ -380,12 +380,11 @@ void nua_dialog_usage_remove_at(nua_owner_t *own,
}
/* Zap dialog if there are no more usages */
if (ds->ds_terminated)
if (ds->ds_terminating)
;
else if (ds->ds_usage == NULL) {
nua_dialog_remove(own, ds, NULL);
ds->ds_has_events = 0;
ds->ds_terminated = 0;
return;
}
else {
......@@ -432,35 +431,19 @@ void nua_dialog_log_usage(nua_owner_t *own, nua_dialog_state_t *ds)
void nua_dialog_deinit(nua_owner_t *own,
nua_dialog_state_t *ds)
{
while (ds->ds_usage) {
nua_dialog_usage_remove_at(own, ds, &ds->ds_usage);
}
}
/** @internal Dialog has been terminated. Remove all usages. */
void nua_dialog_remove_usages(nua_owner_t *own,
struct nua_dialog_state *ds,
int status,
char const *phrase)
{
ds->ds_terminated = 1;
ds->ds_terminating = 1;
while (ds->ds_usage) {
#if 0
int call = 0;
if (ds->ds_usage->du_kind == nua_session_usage)
call = 1; /* Delay sending the event */
else
/* XXX */;
#endif
nua_dialog_usage_remove_at(own, ds, &ds->ds_usage);
}
nua_dialog_remove(own, ds, NULL);
ds->ds_has_events = 0;
ds->ds_terminating = 0;
}
/**@internal
* Set expiration time.
*/
......@@ -564,7 +547,7 @@ int nua_dialog_shutdown(nua_owner_t *owner, nua_dialog_state_t *ds)
{
nua_dialog_usage_t *du;
ds->ds_terminated = 1;
ds->ds_terminating = 1;
do {
for (du = ds->ds_usage; du; du = du->du_next) {
......
......@@ -317,7 +317,7 @@ struct nua_dialog_state
/* Dialog and subscription state */
unsigned ds_route:1; /**< We have route */
unsigned ds_terminated:1; /**< Being terminated */
unsigned ds_terminating:1; /**< Being terminated */
unsigned ds_has_session:1; /**< We have session */
unsigned ds_has_register:1; /**< We have registration */
......@@ -425,11 +425,6 @@ void nua_dialog_deinit(nua_owner_t *own,
int nua_dialog_shutdown(nua_owner_t *owner, nua_dialog_state_t *ds);
void nua_dialog_remove_usages(nua_owner_t *,
struct nua_dialog_state *ds,
int status,
char const *phrase);
void nua_dialog_usage_set_expires(nua_dialog_usage_t *du, unsigned delta);
void nua_dialog_usage_set_refresh(nua_dialog_usage_t *du, unsigned delta);
......@@ -607,6 +602,12 @@ int nua_server_request_is_pending(nua_server_request_t const *sr)
return sr && sr->sr_response.msg;
}
static inline
int nua_server_request_status(nua_server_request_t const *sr)
{
return sr ? nta_incoming_status(sr->sr_irq) : 500;
}
void nua_server_request_destroy(nua_server_request_t *sr);
int nua_base_server_init(nua_server_request_t *sr);
......
......@@ -1602,7 +1602,7 @@ int nua_base_server_report(nua_server_request_t *sr, tagi_t const *tags)
return 2;
/* Remove all usages of the dialog */
nua_dialog_remove_usages(nh, nh->nh_ds, status, phrase);
nua_dialog_deinit(nh, nh->nh_ds);
return 3;
}
......@@ -2341,12 +2341,10 @@ int nua_client_response(nua_client_request_t *cr,
if (terminated < 0)
cr->cr_terminated = terminated;
else if (cr->cr_terminating)
else if (cr->cr_terminating || terminated)
cr->cr_terminated = 1;
else if (terminated && graceful)
else if (graceful)
cr->cr_graceful = graceful;
else if (terminated)
cr->cr_terminated = 1;
}
if (status < 200) {
......@@ -2553,6 +2551,7 @@ int nua_base_client_response(nua_client_request_t *cr,
{
nua_handle_t *nh = cr->cr_owner;
sip_method_t method = cr->cr_method;
nua_dialog_usage_t *du;
cr->cr_reporting = 1;
......@@ -2573,12 +2572,13 @@ int nua_base_client_response(nua_client_request_t *cr,
if (cr->cr_orq)
nta_outgoing_destroy(cr->cr_orq), cr->cr_orq = NULL;
if (cr->cr_usage) {
nua_dialog_usage_t *du = cr->cr_usage;
if (cr->cr_terminated < 0)
/* XXX - dialog has been terminated */;
du = cr->cr_usage;
if (cr->cr_terminated < 0) {
/* XXX - dialog has been terminated */;
nua_dialog_deinit(nh, nh->nh_ds);
}
else if (du) {
if (cr->cr_terminated ||
(!du->du_ready && status >= 300 && nua_client_is_bound(cr))) {
/* Usage has been destroyed */
......@@ -2589,6 +2589,10 @@ int nua_base_client_response(nua_client_request_t *cr,
nua_dialog_usage_shutdown(nh, nh->nh_ds, du);
}
}
else if (cr->cr_terminated) {
if (nh->nh_ds->ds_usage == NULL)
nua_dialog_remove(nh, nh->nh_ds, NULL);
}
cr->cr_reporting = 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