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)
{
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. */
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,
e->e_always = always;
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_phrase = phrase;
......@@ -1197,8 +1197,7 @@ void nua_event(nua_t *root_magic, su_msg_r sumsg, event_t *e)
enter;
if (nh && !NH_IS_DEFAULT(nh)) {
if (nh) {
if (!nh->nh_ref_by_user && nh->nh_valid) {
nh->nh_ref_by_user = 1;
nua_handle_ref(nh);
......@@ -1222,7 +1221,7 @@ void nua_event(nua_t *root_magic, su_msg_r sumsg, event_t *e)
if (!nua->nua_callback)
return;
if (nh == nua->nua_handles)
if (NH_IS_DEFAULT(nh))
nh = NULL;
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)
e->e_msg ? sip_object(e->e_msg) : NULL,
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))
return;
if (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);
}
......
......@@ -99,6 +99,7 @@ nua_handle_t *nh_create_handle(nua_t *nua, nua_hmagic_t *hmagic,
tagi_t *tags)
{
nua_handle_t *nh;
static int8_t _handle_lifetime = 1;
enter;
......@@ -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),
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_threadsafe(nh->nh_home) < 0) {
su_home_unref(nh->nh_home);
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;
}
#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. */
static void nh_destructor(void *arg)
{
nua_handle_t *nh = arg;
/* Xyzzy */
(void)nh;
SU_DEBUG_0(("nh_destructor(%p)\n", nh));
}
#endif
/** Make a new reference to handle.
*
......
......@@ -499,6 +499,7 @@ nua_stack_register(nua_t *nua, nua_handle_t *nh, nua_event_t e,
if (!cr->cr_orq) {
msg_destroy(msg);
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);
}
......@@ -574,9 +575,10 @@ int process_response_to_register(nua_handle_t *nh,
if (status < 200 || !du)
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;
reregister = outbound_connect_check_for_nat(oc, orq, sip);
......@@ -718,12 +720,14 @@ int process_response_to_register(nua_handle_t *nh,
outbound_connect_gruuize(oc, sip);
}
if (!du->du_terminating && status < 300 && oc->oc_nat_detected)
outbound_connect_start_keepalive(oc, 15, orq);
else
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());
}
......@@ -1896,8 +1900,8 @@ char const *nua_outbound_connect_name(nua_dialog_usage_t const *du)
static
int nua_outbound_connect_add(nua_handle_t *nh,
nua_dialog_state_t *ds,
nua_dialog_usage_t *du)
nua_dialog_state_t *ds,
nua_dialog_usage_t *du)
{
struct outbound_connect *oc = nua_dialog_usage_private(du);
......@@ -1931,7 +1935,6 @@ void nua_outbound_connect_remove(nua_handle_t *nh,
#endif
/* XXX - free headers, too */
if (oc->oc_kalt)
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)
sip_time_t next = now + NUA_STACK_TIMER_INTERVAL / 1000;
for (du = nh->nh_ds->ds_usage; du; du = du->du_next) {
if (now == 0)
break;
if (!du->du_pending)
continue;
if (now == 0 || (du->du_refresh && du->du_refresh < next))
if (du->du_refresh && du->du_refresh < next)
break;
}
......@@ -500,7 +502,10 @@ int nh_call_pending(nua_handle_t *nh, sip_time_t now)
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)
break;
......@@ -510,9 +515,11 @@ int nh_call_pending(nua_handle_t *nh, sip_time_t now)
break;
for (; du; du = du->du_next) {
if (now == 0)
break;
if (!du->du_pending)
continue;
if (now == 0 || (du->du_refresh && du->du_refresh < next))
if (du->du_refresh && du->du_refresh < next)
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