Commit 91a161c3 authored by Pekka Pessi's avatar Pekka Pessi

Fixed nua handle reference counting problems in nua module.

Problem reported by Colin Whittaker.

darcs-hash:20060427204258-65a35-3f483661eac2aa1f5c092dc420a5129a861ad6e4.gz
parent aabf5a18
...@@ -1133,7 +1133,7 @@ void nua_handle_destroy(nua_handle_t *nh) ...@@ -1133,7 +1133,7 @@ void nua_handle_destroy(nua_handle_t *nh)
{ {
enter; enter;
if (NH_IS_VALID(nh)) { if (NH_IS_VALID(nh) && !NH_IS_DEFAULT(nh)) {
nh->nh_valid = NULL; /* Events are no more delivered to appl. */ nh->nh_valid = NULL; /* Events are no more delivered to appl. */
nua_signal(nh->nh_nua, nh, NULL, 1, nua_r_destroy, 0, NULL, TAG_END()); nua_signal(nh->nh_nua, nh, NULL, 1, nua_r_destroy, 0, NULL, TAG_END());
} }
...@@ -1175,7 +1175,7 @@ void nua_signal(nua_t *nua, nua_handle_t *nh, msg_t *msg, int always, ...@@ -1175,7 +1175,7 @@ void nua_signal(nua_t *nua, nua_handle_t *nh, msg_t *msg, int always,
e->e_always = always; e->e_always = always;
e->e_event = event; e->e_event = event;
e->e_nh = nua_handle_ref(nh); e->e_nh = event == nua_r_destroy ? nh : nua_handle_ref(nh);
e->e_status = status; e->e_status = status;
e->e_phrase = phrase; e->e_phrase = phrase;
...@@ -1197,8 +1197,7 @@ void nua_event(nua_t *root_magic, su_msg_r sumsg, event_t *e) ...@@ -1197,8 +1197,7 @@ void nua_event(nua_t *root_magic, su_msg_r sumsg, event_t *e)
enter; enter;
if (nh) {
if (nh && !NH_IS_DEFAULT(nh)) {
if (!nh->nh_ref_by_user && nh->nh_valid) { if (!nh->nh_ref_by_user && nh->nh_valid) {
nh->nh_ref_by_user = 1; nh->nh_ref_by_user = 1;
nua_handle_ref(nh); nua_handle_ref(nh);
...@@ -1222,7 +1221,7 @@ void nua_event(nua_t *root_magic, su_msg_r sumsg, event_t *e) ...@@ -1222,7 +1221,7 @@ void nua_event(nua_t *root_magic, su_msg_r sumsg, event_t *e)
if (!nua->nua_callback) if (!nua->nua_callback)
return; return;
if (nh == nua->nua_handles) if (NH_IS_DEFAULT(nh))
nh = NULL; nh = NULL;
su_msg_save(nua->nua_current, sumsg); su_msg_save(nua->nua_current, sumsg);
...@@ -1235,16 +1234,16 @@ void nua_event(nua_t *root_magic, su_msg_r sumsg, event_t *e) ...@@ -1235,16 +1234,16 @@ void nua_event(nua_t *root_magic, su_msg_r sumsg, event_t *e)
e->e_msg ? sip_object(e->e_msg) : NULL, e->e_msg ? sip_object(e->e_msg) : NULL,
e->e_tags); e->e_tags);
if (nh && !NH_IS_DEFAULT(nh) && nua_handle_unref(nh)) {
SU_DEBUG_9(("nua(%p): freed by application\n", nh));
}
if (!su_msg_is_non_null(nua->nua_current)) if (!su_msg_is_non_null(nua->nua_current))
return; return;
if (e->e_msg) if (e->e_msg)
msg_destroy(e->e_msg); msg_destroy(e->e_msg);
if (nh && !NH_IS_DEFAULT(nh) && nua_handle_unref(nh)) {
SU_DEBUG_9(("nua(%p): freed by application\n", nh));
}
su_msg_destroy(nua->nua_current); su_msg_destroy(nua->nua_current);
} }
......
...@@ -99,6 +99,7 @@ nua_handle_t *nh_create_handle(nua_t *nua, nua_hmagic_t *hmagic, ...@@ -99,6 +99,7 @@ nua_handle_t *nh_create_handle(nua_t *nua, nua_hmagic_t *hmagic,
tagi_t *tags) tagi_t *tags)
{ {
nua_handle_t *nh; nua_handle_t *nh;
static int8_t _handle_lifetime = 1;
enter; enter;
...@@ -160,30 +161,48 @@ nua_handle_t *nh_create_handle(nua_t *nua, nua_hmagic_t *hmagic, ...@@ -160,30 +161,48 @@ nua_handle_t *nh_create_handle(nua_t *nua, nua_hmagic_t *hmagic,
SIPTAG_TO_REF(nh->nh_ds->ds_remote), SIPTAG_TO_REF(nh->nh_ds->ds_remote),
TAG_END()); TAG_END());
/* This far, we have nothing to destruct */
/* su_home_desctructor(nh, nh_destructor); */
if (su_home_is_threadsafe(nua->nua_home)) { if (su_home_is_threadsafe(nua->nua_home)) {
if (su_home_threadsafe(nh->nh_home) < 0) { if (su_home_threadsafe(nh->nh_home) < 0) {
su_home_unref(nh->nh_home); su_home_unref(nh->nh_home);
nh = NULL; nh = NULL;
} }
} }
if (nh && _handle_lifetime) {
/* This far, we have nothing real to destruct */
static void nh_destructor(void *arg);
if (_handle_lifetime == 1 && !getenv("_NUA_HANDLE_DEBUG")) {
_handle_lifetime = 0;
}
else {
_handle_lifetime = 2;
SU_DEBUG_0(("nh_handle_create(%p)\n", nh));
su_home_desctructor(nh->nh_home, nh_destructor);
}
}
} }
return nh; return nh;
} }
#if 0 /**@var _NUA_HANDLE_DEBUG
*
* If this environment variable is set, nua stack logs a message whenever a
* handle is created and when it is destroyed. This is mainly useful when
* debugging #nua_handle_t leaks.
*
* @sa nua_handle(), nua_handle_destroy()
*/
extern char const NUA_DEBUG[];
/* nua handle destructor. It does nothing. */ /* nua handle destructor. It does nothing. */
static void nh_destructor(void *arg) static void nh_destructor(void *arg)
{ {
nua_handle_t *nh = arg; nua_handle_t *nh = arg;
/* Xyzzy */ SU_DEBUG_0(("nh_destructor(%p)\n", nh));
(void)nh;
} }
#endif
/** Make a new reference to handle. /** Make a new reference to handle.
* *
......
...@@ -499,6 +499,7 @@ nua_stack_register(nua_t *nua, nua_handle_t *nh, nua_event_t e, ...@@ -499,6 +499,7 @@ nua_stack_register(nua_t *nua, nua_handle_t *nh, nua_event_t e,
if (!cr->cr_orq) { if (!cr->cr_orq) {
msg_destroy(msg); msg_destroy(msg);
msg_destroy(cr->cr_msg), cr->cr_msg = NULL; msg_destroy(cr->cr_msg), cr->cr_msg = NULL;
nua_dialog_usage_remove(nh, nh->nh_ds, du);
return UA_EVENT1(e, NUA_INTERNAL_ERROR); return UA_EVENT1(e, NUA_INTERNAL_ERROR);
} }
...@@ -574,9 +575,10 @@ int process_response_to_register(nua_handle_t *nh, ...@@ -574,9 +575,10 @@ int process_response_to_register(nua_handle_t *nh,
if (status < 200 || !du) if (status < 200 || !du)
return nua_stack_process_response(nh, cr, orq, sip, TAG_END()); return nua_stack_process_response(nh, cr, orq, sip, TAG_END());
nua_dialog_store_peer_info(nh, nh->nh_ds, sip); if (!du->du_terminating)
nua_dialog_store_peer_info(nh, nh->nh_ds, sip);
if (oc->oc_prefs.natify && status >= 200) { if (!du->du_terminating && oc->oc_prefs.natify && status >= 200) {
int reregister; int reregister;
reregister = outbound_connect_check_for_nat(oc, orq, sip); reregister = outbound_connect_check_for_nat(oc, orq, sip);
...@@ -718,12 +720,14 @@ int process_response_to_register(nua_handle_t *nh, ...@@ -718,12 +720,14 @@ int process_response_to_register(nua_handle_t *nh,
outbound_connect_gruuize(oc, sip); outbound_connect_gruuize(oc, sip);
} }
if (!du->du_terminating && status < 300 && oc->oc_nat_detected) if (!du->du_terminating && status < 300 && oc->oc_nat_detected)
outbound_connect_start_keepalive(oc, 15, orq); outbound_connect_start_keepalive(oc, 15, orq);
else else
outbound_connect_stop_keepalive(oc); outbound_connect_stop_keepalive(oc);
if (du->du_terminating || status >= 300)
nua_dialog_usage_remove(nh, nh->nh_ds, du);
return nua_stack_process_response(nh, cr, orq, sip, TAG_END()); return nua_stack_process_response(nh, cr, orq, sip, TAG_END());
} }
...@@ -1896,8 +1900,8 @@ char const *nua_outbound_connect_name(nua_dialog_usage_t const *du) ...@@ -1896,8 +1900,8 @@ char const *nua_outbound_connect_name(nua_dialog_usage_t const *du)
static static
int nua_outbound_connect_add(nua_handle_t *nh, int nua_outbound_connect_add(nua_handle_t *nh,
nua_dialog_state_t *ds, nua_dialog_state_t *ds,
nua_dialog_usage_t *du) nua_dialog_usage_t *du)
{ {
struct outbound_connect *oc = nua_dialog_usage_private(du); struct outbound_connect *oc = nua_dialog_usage_private(du);
...@@ -1931,7 +1935,6 @@ void nua_outbound_connect_remove(nua_handle_t *nh, ...@@ -1931,7 +1935,6 @@ void nua_outbound_connect_remove(nua_handle_t *nh,
#endif #endif
/* XXX - free headers, too */ /* XXX - free headers, too */
if (oc->oc_kalt) if (oc->oc_kalt)
su_timer_destroy(oc->oc_kalt), oc->oc_kalt = NULL; su_timer_destroy(oc->oc_kalt), oc->oc_kalt = NULL;
......
...@@ -483,9 +483,11 @@ int nh_call_pending(nua_handle_t *nh, sip_time_t now) ...@@ -483,9 +483,11 @@ int nh_call_pending(nua_handle_t *nh, sip_time_t now)
sip_time_t next = now + NUA_STACK_TIMER_INTERVAL / 1000; sip_time_t next = now + NUA_STACK_TIMER_INTERVAL / 1000;
for (du = nh->nh_ds->ds_usage; du; du = du->du_next) { for (du = nh->nh_ds->ds_usage; du; du = du->du_next) {
if (now == 0)
break;
if (!du->du_pending) if (!du->du_pending)
continue; continue;
if (now == 0 || (du->du_refresh && du->du_refresh < next)) if (du->du_refresh && du->du_refresh < next)
break; break;
} }
...@@ -500,7 +502,10 @@ int nh_call_pending(nua_handle_t *nh, sip_time_t now) ...@@ -500,7 +502,10 @@ int nh_call_pending(nua_handle_t *nh, sip_time_t now)
du->du_pending = NULL; du->du_pending = NULL;
pending(nh, du, now); if (pending)
pending(nh, du, now);
else
nua_dialog_usage_remove(nh, nh->nh_ds, du);
if (du_next == NULL) if (du_next == NULL)
break; break;
...@@ -510,9 +515,11 @@ int nh_call_pending(nua_handle_t *nh, sip_time_t now) ...@@ -510,9 +515,11 @@ int nh_call_pending(nua_handle_t *nh, sip_time_t now)
break; break;
for (; du; du = du->du_next) { for (; du; du = du->du_next) {
if (now == 0)
break;
if (!du->du_pending) if (!du->du_pending)
continue; continue;
if (now == 0 || (du->du_refresh && du->du_refresh < next)) if (du->du_refresh && du->du_refresh < next)
break; break;
} }
} }
......
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