Commit b825fe97 authored by Pekka Pessi's avatar Pekka Pessi

nua: moved message passing into nua_stack.c. Recfactored reference counting.

This seems to fix the memory leak within 1.12.7.

darcs-hash:20071127002305-65a35-43967d305a1403bc0918195f34222143bce915e9.gz
parent da0714a1
......@@ -43,8 +43,6 @@
#include <sofia-sip/su_debug.h>
#define SU_ROOT_MAGIC_T struct nua_s
#define SU_MSG_ARG_T struct event_s
#define NUA_SAVED_EVENT_T su_msg_t *
#include <sofia-sip/sip_status.h>
#include <sofia-sip/sip_header.h>
......@@ -192,16 +190,9 @@ void nua_shutdown(nua_t *nua)
if (nua)
nua->nua_shutdown_started = 1;
nua_signal(nua, NULL, NULL, 1, nua_r_shutdown, 0, NULL, TAG_END());
nua_signal(nua, NULL, NULL, nua_r_shutdown, 0, NULL, TAG_END());
}
/** @internal Linked stack frames from nua event callback */
struct nua_event_frame_s {
nua_event_frame_t *nf_next;
nua_t *nf_nua;
nua_saved_event_t nf_saved[1];
};
/** Destroy the @nua stack.
*
* Before calling nua_destroy() the application
......@@ -227,8 +218,6 @@ void nua_destroy(nua_t *nua)
enter;
if (nua) {
nua_event_frame_t *nf;
if (!nua->nua_shutdown_final) {
SU_DEBUG_0(("nua_destroy(%p): FATAL: nua_shutdown not completed\n",
(void *)nua));
......@@ -238,11 +227,6 @@ void nua_destroy(nua_t *nua)
nua->nua_callback = NULL;
for (nf = nua->nua_current; nf; nf = nf->nf_next) {
nf->nf_nua = NULL;
}
nua->nua_current = NULL;
su_task_deinit(nua->nua_server);
su_task_deinit(nua->nua_client);
......@@ -590,7 +574,7 @@ void nua_set_params(nua_t *nua, tag_type_t tag, tag_value_t value, ...)
enter;
nua_signal(nua, NULL, NULL, 0, nua_r_set_params, 0, NULL, ta_tags(ta));
nua_signal(nua, NULL, NULL, nua_r_set_params, 0, NULL, ta_tags(ta));
ta_end(ta);
}
......@@ -603,7 +587,7 @@ void nua_get_params(nua_t *nua, tag_type_t tag, tag_value_t value, ...)
enter;
nua_signal(nua, NULL, NULL, 0, nua_r_get_params, 0, NULL, ta_tags(ta));
nua_signal(nua, NULL, NULL, nua_r_get_params, 0, NULL, ta_tags(ta));
ta_end(ta);
}
......@@ -613,7 +597,7 @@ void nua_get_params(nua_t *nua, tag_type_t tag, tag_value_t value, ...)
if (NH_IS_VALID((nh))) { \
ta_list ta; \
ta_start(ta, tag, value); \
nua_signal((nh)->nh_nua, nh, NULL, 0, event, 0, NULL, ta_tags(ta)); \
nua_signal((nh)->nh_nua, nh, NULL, event, 0, NULL, ta_tags(ta)); \
ta_end(ta); \
} \
else { \
......@@ -897,7 +881,7 @@ void nua_respond(nua_handle_t *nh,
if (NH_IS_VALID(nh)) {
ta_list ta;
ta_start(ta, tag, value);
nua_signal(nh->nh_nua, nh, NULL, 0, nua_r_respond,
nua_signal(nh->nh_nua, nh, NULL, nua_r_respond,
status, phrase, ta_tags(ta));
ta_end(ta);
}
......@@ -938,201 +922,7 @@ void nua_handle_destroy(nua_handle_t *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());
}
}
/*# Send a request to the protocol thread */
void nua_signal(nua_t *nua, nua_handle_t *nh, msg_t *msg, int always,
nua_event_t event,
int status, char const *phrase,
tag_type_t tag, tag_value_t value, ...)
{
su_msg_r sumsg = SU_MSG_R_INIT;
size_t len, xtra, e_len, l_len = 0, l_xtra = 0;
ta_list ta;
if (nua == NULL || (nua->nua_shutdown_started && event != nua_r_shutdown))
return;
ta_start(ta, tag, value);
e_len = offsetof(event_t, e_tags);
len = tl_len(ta_args(ta));
xtra = tl_xtra(ta_args(ta), len);
if (su_msg_create(sumsg, nua->nua_server, su_task_null,
nua_stack_signal,
e_len + len + l_len + xtra + l_xtra) == 0) {
event_t *e = su_msg_data(sumsg);
tagi_t *t = e->e_tags;
void *b = (char *)t + len + l_len;
tagi_t *tend = (tagi_t *)b;
char *bend = (char *)b + xtra + l_xtra;
t = tl_dup(t, ta_args(ta), &b);
assert(tend == t); (void)tend; assert(b == bend); (void)bend;
e->e_always = always;
e->e_event = event;
e->e_nh = event == nua_r_destroy ? nh : nua_handle_ref(nh);
e->e_status = status;
e->e_phrase = phrase;
SU_DEBUG_7(("nua(%p): signal %s\n", (void *)nh,
nua_event_name(event) + 4));
if (su_msg_send(sumsg) != 0 && event != nua_r_destroy)
nua_handle_unref(nh);
}
else {
/* XXX - we should return error code to application but we just abort() */
assert(ENOMEM == 0);
}
ta_end(ta);
}
/*# Receive event from protocol machine and hand it over to application */
void nua_event(nua_t *root_magic, su_msg_r sumsg, event_t *e)
{
nua_t *nua;
nua_handle_t *nh = e->e_nh;
enter;
e->e_nh = NULL;
if (nh) {
if (!nh->nh_ref_by_user && nh->nh_valid) {
nh->nh_ref_by_user = 1;
nua_handle_ref(nh);
}
}
if (!nh || !nh->nh_valid) { /* Handle has been destroyed */
if (nua_log->log_level >= 7) {
char const *name = nua_event_name(e->e_event) + 4;
SU_DEBUG_7(("nua(%p): event %s dropped\n", (void *)nh, name));
}
if (nh && !NH_IS_DEFAULT(nh) && nua_handle_unref(nh)) {
#if HAVE_NUA_HANDLE_DEBUG
SU_DEBUG_0(("nua(%p): freed by application\n", (void *)nh));
#else
SU_DEBUG_9(("nua(%p): freed by application\n", (void *)nh));
#endif
}
if (e->e_msg)
msg_destroy(e->e_msg), e->e_msg = NULL;
return;
}
nua = nh->nh_nua; assert(nua);
if (NH_IS_DEFAULT(nh))
nh = NULL;
if (e->e_event == nua_r_shutdown && e->e_status >= 200)
nua->nua_shutdown_final = 1;
if (nua->nua_callback) {
nua_event_frame_t frame[1];
su_msg_remove_refs(sumsg); /* Remove references to tasks */
su_msg_save(frame->nf_saved, sumsg);
frame->nf_nua = nua;
frame->nf_next = nua->nua_current, nua->nua_current = frame;
nua->nua_callback(e->e_event, e->e_status, e->e_phrase,
nua, nua->nua_magic,
nh, nh ? nh->nh_magic : NULL,
e->e_msg ? sip_object(e->e_msg) : NULL,
e->e_tags);
su_msg_destroy(frame->nf_saved);
if (frame->nf_nua == NULL)
return;
nua->nua_current = frame->nf_next;
}
if (nh && nua_handle_unref(nh)) {
#if HAVE_NUA_HANDLE_DEBUG
SU_DEBUG_0(("nua(%p): freed by application\n", (void *)nh));
#else
SU_DEBUG_9(("nua(%p): freed by application\n", (void *)nh));
#endif
}
}
/** Get current request message. @NEW_1_12_4.
*
* @note A response message is returned when processing response message.
*
* @sa #nua_event_e, nua_respond(), NUTAG_WITH_CURRENT()
*/
msg_t *nua_current_request(nua_t const *nua)
{
if (nua && nua->nua_current && su_msg_is_non_null(nua->nua_current->nf_saved))
return su_msg_data(nua->nua_current->nf_saved)->e_msg;
return NULL;
}
/** Get request message from saved nua event. @NEW_1_12_4.
*
* @sa nua_save_event(), nua_respond(), NUTAG_WITH_SAVED(),
*/
msg_t *nua_saved_event_request(nua_saved_event_t const *saved)
{
return saved && saved[0] ? su_msg_data(saved)->e_msg : NULL;
}
/** Save nua event and its arguments.
*
* @sa #nua_event_e, nua_event_data() nua_saved_event_request(), nua_destroy_event()
*/
int nua_save_event(nua_t *nua, nua_saved_event_t return_saved[1])
{
if (return_saved) {
if (nua && nua->nua_current) {
su_msg_save(return_saved, nua->nua_current->nf_saved);
return su_msg_is_non_null(return_saved);
}
else
*return_saved = NULL;
}
return 0;
}
/** Get event data.
*
* @sa #nua_event_e, nua_event_save(), nua_saved_event_request(), nua_destroy_event().
*/
nua_event_data_t const *nua_event_data(nua_saved_event_t const saved[1])
{
return saved ? su_msg_data(saved) : NULL;
}
/** Destroy saved event.
*
* @sa #nua_event_e, nua_event_save(), nua_event_data(), nua_saved_event_request().
*/
void nua_destroy_event(nua_saved_event_t saved[1])
{
if (su_msg_is_non_null(saved)) {
event_t *e = su_msg_data(saved);
nua_handle_t *nh = e->e_nh;
if (e->e_msg)
msg_destroy(e->e_msg), e->e_msg = NULL;
if (nh && !NH_IS_DEFAULT(nh) && nua_handle_unref(nh)) {
SU_DEBUG_9(("nua(%p): freed by application\n", (void *)nh));
}
su_msg_destroy(saved);
nua_signal(nh->nh_nua, nh, NULL, nua_r_destroy, 0, NULL, TAG_END());
}
}
......
......@@ -52,7 +52,6 @@
#include <sofia-sip/su_debug.h>
#define SU_ROOT_MAGIC_T struct nua_s
#define SU_MSG_ARG_T struct event_s
#include <sofia-sip/su_wait.h>
......
......@@ -50,7 +50,11 @@ typedef struct nua_server_request nua_server_request_t;
typedef struct nua_client_request nua_client_request_t;
typedef struct nua_dialog_peer_info nua_dialog_peer_info_t;
typedef su_msg_r nua_saved_signal_t;
#ifndef NUA_SAVED_SIGNAL_T
#define NUA_SAVED_SIGNAL_T struct nua_saved_signal *
#endif
typedef NUA_SAVED_SIGNAL_T nua_saved_signal_t;
typedef struct {
sip_method_t sm_method;
......@@ -80,6 +84,7 @@ typedef struct {
} nua_server_methods_t;
/* Server side transaction */
struct nua_server_request {
struct nua_server_request *sr_next, **sr_prev;
......@@ -132,7 +137,7 @@ struct nua_server_request {
size_t sr_sdp_len; /**< SDP length */
/**< Save 200 OK nua_respond() signal until PRACK has been received */
nua_saved_signal_t sr_signal;
nua_saved_signal_t sr_signal[1];
};
#define SR_STATUS(sr, status, phrase) \
......@@ -141,6 +146,8 @@ struct nua_server_request {
#define SR_STATUS1(sr, statusphrase) \
sr_status(sr, statusphrase)
#define SR_HAS_SAVED_SIGNAL(sr) ((sr)->sr_signal[0] != NULL)
su_inline
int sr_status(nua_server_request_t *sr, int status, char const *phrase)
{
......@@ -261,7 +268,7 @@ struct nua_client_request
nua_owner_t *cr_owner;
nua_dialog_usage_t *cr_usage;
nua_saved_signal_t cr_signal;
nua_saved_signal_t cr_signal[1];
tagi_t const *cr_tags;
nua_client_methods_t const *cr_methods;
......
......@@ -890,7 +890,18 @@ int nua_refer_server_respond(nua_server_request_t *sr, tagi_t const *tags)
/** @NUA_EVENT nua_i_refer
*
* Incoming @b REFER request used to transfer calls.
* Incoming @b REFER request used to transfer calls. The tag list will
* contain tag NUTAG_REFER_EVENT() with the @Event header constructed from
* the REFER request. It will also contain the SIPTAG_REFERRED_BY() tag with
* the @ReferredBy header containing the identity of the party sending the
* REFER. The @ReferredBy structure contained in the tag is constructed from
* the @From header if the @ReferredBy header was not present in the REFER
* request.
*
* The application can let the nua to send NOTIFYs from the call it
* initiates with nua_invite() if it includes in the nua_invite() arguments
* both the NUTAG_NOTIFY_REFER() with the handle with which nua_i_refer was
* received and the NUTAG_REFER_EVENT() from #nua_i_refer event tags.
*
* @param status status code of response sent automatically by stack
* @param phrase a short textual description of @a status code
......
......@@ -2611,20 +2611,16 @@ int nua_prack_server_report(nua_server_request_t *sr, tagi_t const *tags)
if (sri == NULL) {
}
else if (su_msg_is_non_null(sri->sr_signal)) {
su_msg_r signal;
event_t *e;
else if (SR_HAS_SAVED_SIGNAL(sri)) {
nua_signal_data_t const *e;
su_msg_save(signal, sri->sr_signal);
e = su_msg_data(signal);
e = nua_signal_data(sri->sr_signal);
sri->sr_application = SR_STATUS(sri, e->e_status, e->e_phrase);
nua_server_params(sri, e->e_tags);
nua_server_respond(sri, e->e_tags);
nua_server_report(sri);
su_msg_destroy(signal);
}
else if (ss->ss_state < nua_callstate_ready
&& !ss->ss_alerting
......
This diff is collapsed.
......@@ -75,7 +75,7 @@ SOFIA_BEGIN_DECLS
#include "nua_params.h"
#endif
typedef struct event_s event_t;
typedef struct event_s event_t, nua_signal_data_t;
#define NONE ((void *)-1)
......@@ -109,7 +109,7 @@ typedef struct register_usage nua_registration_t;
#define nua_handle_unref(nh) nua_handle_unref_by((nh), __func__)
su_inline nua_handle_t *nua_handle_ref_by(nua_handle_t *nh,
char const *by)
char const *by)
{
if (nh)
SU_DEBUG_0(("nua_handle_ref(%p) => "MOD_ZU" by %s\n", nh,
......@@ -120,11 +120,16 @@ su_inline nua_handle_t *nua_handle_ref_by(nua_handle_t *nh,
su_inline int nua_handle_unref_by(nua_handle_t *nh, char const *by)
{
if (nh)
SU_DEBUG_0(("nua_handle_unref(%p) => "MOD_ZU" by %s\n", nh,
su_home_refcount((su_home_t *)nh) - 1,
by));
return su_home_unref((su_home_t *)nh);
if (nh) {
size_t refcount = su_home_refcount((su_home_t *)nh) - 1;
int freed = su_home_unref((su_home_t *)nh);
if (freed) refcount = 0;
SU_DEBUG_0(("nua_handle_unref(%p) => "MOD_ZU" by %s\n",
nh, refcount, by));
return freed;
}
return 0;
}
#endif
......@@ -279,10 +284,19 @@ struct nua_s {
#define __func__ "nua"
#endif
su_inline nua_t *nua_stack_ref(nua_t *nua)
{
return (nua_t *)su_home_ref(nua->nua_home);
}
su_inline void nua_stack_unref(nua_t *nua)
{
su_home_unref(nua->nua_home);
}
/* Internal prototypes */
int nua_stack_init(su_root_t *root, nua_t *nua);
void nua_stack_deinit(su_root_t *root, nua_t *nua);
void nua_stack_signal(nua_t *nua, su_msg_r msg, event_t *e);
int nua_stack_init_transport(nua_t *nua, tagi_t const *tags);
......@@ -307,6 +321,10 @@ typedef int nua_stack_signal_handler(nua_t *,
nua_event_t,
tagi_t const *);
void nua_move_signal(nua_saved_signal_t a[1], nua_saved_signal_t b[1]);
nua_signal_data_t const *nua_signal_data(nua_saved_signal_t const saved[1]);
void nua_destroy_signal(nua_saved_signal_t saved[1]);
nua_stack_signal_handler
nua_stack_set_params, nua_stack_get_params,
nua_stack_register,
......@@ -334,6 +352,8 @@ int nua_stack_event(nua_t *nua, nua_handle_t *nh, msg_t *msg,
nua_event_t event, int status, char const *phrase,
tagi_t const *tags);
void nua_move_event(nua_saved_event_t a[1], nua_saved_event_t b[1]);
nua_handle_t *nh_create_handle(nua_t *nua, nua_hmagic_t *hmagic, tagi_t *tags);
nua_handle_t *nua_stack_incoming_handle(nua_t *nua,
......@@ -433,11 +453,9 @@ typedef unsigned longlong ull;
/* ---------------------------------------------------------------------- */
/* Application side prototypes */
void nua_signal(nua_t *nua, nua_handle_t *nh, msg_t *msg, int always,
nua_event_t event, int status, char const *phrase,
tag_type_t tag, tag_value_t value, ...);
void nua_event(nua_t *root_magic, su_msg_r sumsg, event_t *e);
int nua_signal(nua_t *nua, nua_handle_t *nh, msg_t *msg,
nua_event_t event, int status, char const *phrase,
tag_type_t tag, tag_value_t value, ...);
SOFIA_END_DECLS
......
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