Wed Sep 3 14:20:29 EDT 2008 Pekka Pessi <first.last@nokia.com>
* nua: added reference counting for client-side transactions git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@9421 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
parent
a2740a96c8
commit
ef020e6016
|
@ -1 +1 @@
|
||||||
Wed Sep 3 14:29:03 EDT 2008
|
Wed Sep 3 14:29:36 EDT 2008
|
||||||
|
|
|
@ -354,8 +354,8 @@ void nua_dialog_usage_remove(nua_owner_t *own,
|
||||||
*
|
*
|
||||||
* Zap dialog state (leg, tag and route) if no usages remain.
|
* Zap dialog state (leg, tag and route) if no usages remain.
|
||||||
*/
|
*/
|
||||||
static
|
static void
|
||||||
void nua_dialog_usage_remove_at(nua_owner_t *own,
|
nua_dialog_usage_remove_at(nua_owner_t *own,
|
||||||
nua_dialog_state_t *ds,
|
nua_dialog_state_t *ds,
|
||||||
nua_dialog_usage_t **at,
|
nua_dialog_usage_t **at,
|
||||||
nua_client_request_t *cr0,
|
nua_client_request_t *cr0,
|
||||||
|
@ -376,17 +376,9 @@ void nua_dialog_usage_remove_at(nua_owner_t *own,
|
||||||
o ? " with event " : "", o ? o->o_type :""));
|
o ? " with event " : "", o ? o->o_type :""));
|
||||||
du->du_class->usage_remove(own, ds, du, cr0, sr0);
|
du->du_class->usage_remove(own, ds, du, cr0, sr0);
|
||||||
|
|
||||||
/* Destroy saved client request */
|
/* Clean reference to saved client request */
|
||||||
if (cr0 != du->du_cr && nua_client_is_bound(du->du_cr)) {
|
if (du->du_cr)
|
||||||
nua_client_bind(cr = du->du_cr, NULL);
|
nua_client_bind(du->du_cr, NULL);
|
||||||
|
|
||||||
if (nua_client_is_queued(cr))
|
|
||||||
nua_client_request_complete(cr);
|
|
||||||
else if (nua_client_is_reporting(cr))
|
|
||||||
;
|
|
||||||
else
|
|
||||||
nua_client_request_destroy(cr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Clean references from queued client requests */
|
/* Clean references from queued client requests */
|
||||||
for (cr = ds->ds_cr; cr; cr = cr_next) {
|
for (cr = ds->ds_cr; cr; cr = cr_next) {
|
||||||
|
@ -395,6 +387,7 @@ void nua_dialog_usage_remove_at(nua_owner_t *own,
|
||||||
cr->cr_usage = NULL;
|
cr->cr_usage = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Clean references from queued server requests */
|
||||||
for (sr = ds->ds_sr; sr; sr = sr_next) {
|
for (sr = ds->ds_sr; sr; sr = sr_next) {
|
||||||
sr_next = sr->sr_next;
|
sr_next = sr->sr_next;
|
||||||
if (sr->sr_usage == du) {
|
if (sr->sr_usage == du) {
|
||||||
|
|
|
@ -277,6 +277,8 @@ struct nua_client_request
|
||||||
|
|
||||||
uint32_t cr_seq;
|
uint32_t cr_seq;
|
||||||
|
|
||||||
|
unsigned cr_refs; /**< References to client request */
|
||||||
|
|
||||||
/* Flags used with offer-answer */
|
/* Flags used with offer-answer */
|
||||||
unsigned short cr_answer_recv; /**< Recv answer in response
|
unsigned short cr_answer_recv; /**< Recv answer in response
|
||||||
* with this status.
|
* with this status.
|
||||||
|
@ -300,7 +302,6 @@ struct nua_client_request
|
||||||
unsigned cr_waiting:1; /**< Request is waiting */
|
unsigned cr_waiting:1; /**< Request is waiting */
|
||||||
unsigned cr_challenged:1; /**< Request was challenged */
|
unsigned cr_challenged:1; /**< Request was challenged */
|
||||||
unsigned cr_wait_for_cred:1; /**< Request is pending authentication */
|
unsigned cr_wait_for_cred:1; /**< Request is pending authentication */
|
||||||
unsigned cr_wait_for_timer:1; /**< Request is waiting for a timer to expire */
|
|
||||||
unsigned cr_restarting:1; /**< Request is being restarted */
|
unsigned cr_restarting:1; /**< Request is being restarted */
|
||||||
unsigned cr_reporting:1; /**< Reporting in progress */
|
unsigned cr_reporting:1; /**< Reporting in progress */
|
||||||
unsigned cr_terminating:1; /**< Request terminates the usage */
|
unsigned cr_terminating:1; /**< Request terminates the usage */
|
||||||
|
@ -523,8 +524,23 @@ void *nua_private_client_request(nua_client_request_t const *cr)
|
||||||
return (void *)(cr + 1);
|
return (void *)(cr + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nua_client_request_complete(nua_client_request_t *);
|
nua_client_request_t *nua_client_request_ref(nua_client_request_t *);
|
||||||
void nua_client_request_destroy(nua_client_request_t *);
|
int nua_client_request_unref(nua_client_request_t *);
|
||||||
|
|
||||||
|
#if HAVE_MEMLEAK_LOG
|
||||||
|
|
||||||
|
#define nua_client_request_ref(cr) \
|
||||||
|
nua_client_request_ref_by((cr), __FILE__, __LINE__, __func__)
|
||||||
|
#define nua_client_request_unref(cr) \
|
||||||
|
nua_client_request_unref_by((cr), __FILE__, __LINE__, __func__)
|
||||||
|
|
||||||
|
nua_client_request_t *nua_client_request_ref_by(nua_client_request_t *,
|
||||||
|
char const *file, unsigned line,
|
||||||
|
char const *who);
|
||||||
|
int nua_client_request_unref_by(nua_client_request_t *,
|
||||||
|
char const *file, unsigned line, char const *who);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
int nua_client_request_queue(nua_client_request_t *cr);
|
int nua_client_request_queue(nua_client_request_t *cr);
|
||||||
|
|
||||||
|
@ -533,8 +549,8 @@ su_inline int nua_client_is_queued(nua_client_request_t const *cr)
|
||||||
return cr && cr->cr_prev;
|
return cr && cr->cr_prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nua_client_request_remove(nua_client_request_t *cr);
|
int nua_client_request_remove(nua_client_request_t *cr);
|
||||||
void nua_client_request_clean(nua_client_request_t *cr);
|
int nua_client_request_clean(nua_client_request_t *cr);
|
||||||
int nua_client_bind(nua_client_request_t *cr, nua_dialog_usage_t *du);
|
int nua_client_bind(nua_client_request_t *cr, nua_dialog_usage_t *du);
|
||||||
|
|
||||||
su_inline int nua_client_is_bound(nua_client_request_t const *cr)
|
su_inline int nua_client_is_bound(nua_client_request_t const *cr)
|
||||||
|
|
|
@ -276,7 +276,7 @@ void nua_session_usage_remove(nua_handle_t *nh,
|
||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
nua_client_request_destroy(cr);
|
nua_client_request_remove(cr);
|
||||||
|
|
||||||
cr_next = ds->ds_cr;
|
cr_next = ds->ds_cr;
|
||||||
}
|
}
|
||||||
|
@ -1177,9 +1177,9 @@ int nua_stack_ack(nua_t *nua, nua_handle_t *nh, nua_event_t e,
|
||||||
soa_set_params(nh->nh_soa, TAG_NEXT(tags));
|
soa_set_params(nh->nh_soa, TAG_NEXT(tags));
|
||||||
}
|
}
|
||||||
|
|
||||||
error = nua_invite_client_ack(cr, tags);
|
nua_client_request_ref(cr);
|
||||||
|
|
||||||
nua_client_request_clean(cr);
|
error = nua_invite_client_ack(cr, tags);
|
||||||
|
|
||||||
if (error < 0) {
|
if (error < 0) {
|
||||||
if (ss->ss_reason == NULL)
|
if (ss->ss_reason == NULL)
|
||||||
|
@ -1195,8 +1195,7 @@ int nua_stack_ack(nua_t *nua, nua_handle_t *nh, nua_event_t e,
|
||||||
else if (ss)
|
else if (ss)
|
||||||
signal_call_state_change(nh, ss, 200, "ACK sent", nua_callstate_ready);
|
signal_call_state_change(nh, ss, 200, "ACK sent", nua_callstate_ready);
|
||||||
|
|
||||||
if (!nua_client_is_queued(cr) && !nua_client_is_bound(cr))
|
nua_client_request_unref(cr);
|
||||||
nua_client_request_destroy(cr);
|
|
||||||
|
|
||||||
nua_client_next_request(nh->nh_ds->ds_cr, 1);
|
nua_client_next_request(nh->nh_ds->ds_cr, 1);
|
||||||
|
|
||||||
|
@ -1233,7 +1232,8 @@ int nua_invite_client_ack(nua_client_request_t *cr, tagi_t const *tags)
|
||||||
|
|
||||||
if (!ds->ds_leg) {
|
if (!ds->ds_leg) {
|
||||||
/* XXX - fix nua_dialog_usage_remove_at() instead! */
|
/* XXX - fix nua_dialog_usage_remove_at() instead! */
|
||||||
nta_outgoing_destroy(cr->cr_orq);
|
nua_client_request_clean(cr);
|
||||||
|
nua_client_request_remove(cr);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1366,9 +1366,11 @@ int nua_invite_client_ack(nua_client_request_t *cr, tagi_t const *tags)
|
||||||
if (error == -1)
|
if (error == -1)
|
||||||
msg_destroy(msg);
|
msg_destroy(msg);
|
||||||
|
|
||||||
nua_client_request_remove(cr);
|
|
||||||
cr->cr_acked = 1; /* ... or we have at least tried */
|
cr->cr_acked = 1; /* ... or we have at least tried */
|
||||||
|
|
||||||
|
nua_client_request_clean(cr);
|
||||||
|
nua_client_request_remove(cr);
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1452,11 +1454,19 @@ static int nua_cancel_client_request(nua_client_request_t *cr,
|
||||||
return nua_client_return(cr, 481, "No transaction to CANCEL", msg);
|
return nua_client_return(cr, 481, "No transaction to CANCEL", msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(cr->cr_orq == NULL);
|
||||||
|
|
||||||
cr->cr_orq = nta_outgoing_tcancel(du->du_cr->cr_orq,
|
cr->cr_orq = nta_outgoing_tcancel(du->du_cr->cr_orq,
|
||||||
nua_client_orq_response, cr,
|
nua_client_orq_response,
|
||||||
|
nua_client_request_ref(cr),
|
||||||
TAG_NEXT(tags));
|
TAG_NEXT(tags));
|
||||||
|
|
||||||
return cr->cr_orq ? 0 : -1;
|
if (cr->cr_orq == NULL) {
|
||||||
|
nua_client_request_unref(cr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @NUA_EVENT nua_r_cancel
|
/** @NUA_EVENT nua_r_cancel
|
||||||
|
@ -3630,7 +3640,6 @@ static int nua_bye_client_init(nua_client_request_t *cr,
|
||||||
if (nh->nh_soa)
|
if (nh->nh_soa)
|
||||||
soa_terminate(nh->nh_soa, 0);
|
soa_terminate(nh->nh_soa, 0);
|
||||||
|
|
||||||
du->du_cr = NULL;
|
|
||||||
nua_client_bind(cr, du);
|
nua_client_bind(cr, du);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -114,6 +114,8 @@ static int nh_authorize(nua_handle_t *nh,
|
||||||
|
|
||||||
static void nua_stack_timer(nua_t *nua, su_timer_t *t, su_timer_arg_t *a);
|
static void nua_stack_timer(nua_t *nua, su_timer_t *t, su_timer_arg_t *a);
|
||||||
|
|
||||||
|
static int nua_client_request_complete(nua_client_request_t *cr);
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
/* ---------------------------------------------------------------------- */
|
||||||
/* Constant data */
|
/* Constant data */
|
||||||
|
|
||||||
|
@ -963,7 +965,7 @@ void nh_destroy(nua_t *nua, nua_handle_t *nh)
|
||||||
nea_server_destroy(nh->nh_notifier), nh->nh_notifier = NULL;
|
nea_server_destroy(nh->nh_notifier), nh->nh_notifier = NULL;
|
||||||
|
|
||||||
while (nh->nh_ds->ds_cr)
|
while (nh->nh_ds->ds_cr)
|
||||||
nua_client_request_destroy(nh->nh_ds->ds_cr);
|
nua_client_request_complete(nh->nh_ds->ds_cr);
|
||||||
|
|
||||||
while (nh->nh_ds->ds_sr)
|
while (nh->nh_ds->ds_sr)
|
||||||
nua_server_request_destroy(nh->nh_ds->ds_sr);
|
nua_server_request_destroy(nh->nh_ds->ds_sr);
|
||||||
|
@ -1956,8 +1958,8 @@ int nua_base_server_report(nua_server_request_t *sr, tagi_t const *tags)
|
||||||
* crm_report().
|
* crm_report().
|
||||||
*
|
*
|
||||||
* The final responses are processed by crm_recv() and and preliminary ones
|
* The final responses are processed by crm_recv() and and preliminary ones
|
||||||
* by crm_preliminary(). Both functions call nua_base_client_response() after
|
* by crm_preliminary(). All virtual functions should call
|
||||||
* method-specific processing.
|
* nua_base_client_response() beside method-specific processing.
|
||||||
*
|
*
|
||||||
* The nua_base_client_response() relays the response to the application with
|
* The nua_base_client_response() relays the response to the application with
|
||||||
* nua_client_restart() and crm_report().
|
* nua_client_restart() and crm_report().
|
||||||
|
@ -1968,6 +1970,8 @@ int nua_base_server_report(nua_server_request_t *sr, tagi_t const *tags)
|
||||||
* When a terminating request completes the dialog usage is removed and the
|
* When a terminating request completes the dialog usage is removed and the
|
||||||
* dialog is destroyed (unless there is an another active usage).
|
* dialog is destroyed (unless there is an another active usage).
|
||||||
*/
|
*/
|
||||||
|
static void nua_client_request_destroy(nua_client_request_t *cr);
|
||||||
|
static int nua_client_init_request0(nua_client_request_t *cr);
|
||||||
static int nua_client_request_try(nua_client_request_t *cr);
|
static int nua_client_request_try(nua_client_request_t *cr);
|
||||||
static int nua_client_request_sendmsg(nua_client_request_t *cr,
|
static int nua_client_request_sendmsg(nua_client_request_t *cr,
|
||||||
msg_t *msg, sip_t *sip);
|
msg_t *msg, sip_t *sip);
|
||||||
|
@ -2038,6 +2042,10 @@ int nua_client_create(nua_handle_t *nh,
|
||||||
if (tags && cr->cr_tags == NULL)
|
if (tags && cr->cr_tags == NULL)
|
||||||
cr->cr_tags = tl_tlist(nh->nh_home, TAG_NEXT(tags));
|
cr->cr_tags = tl_tlist(nh->nh_home, TAG_NEXT(tags));
|
||||||
|
|
||||||
|
#if HAVE_MEMLEAK_LOG
|
||||||
|
SU_DEBUG_0(("%p %s() for %s\n", cr, __func__, cr->cr_methods->crm_method_name));
|
||||||
|
#endif
|
||||||
|
|
||||||
if (nua_client_request_queue(cr))
|
if (nua_client_request_queue(cr))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -2057,6 +2065,55 @@ int nua_client_tcreate(nua_handle_t *nh,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if HAVE_MEMLEAK_LOG
|
||||||
|
nua_client_request_t *
|
||||||
|
nua_client_request_ref_by(nua_client_request_t *cr,
|
||||||
|
char const *where, unsigned line, char const *who)
|
||||||
|
{
|
||||||
|
SU_DEBUG_0(("%p ref %s to %u by %s:%u: %s()\n",
|
||||||
|
cr, cr->cr_methods->crm_method_name,
|
||||||
|
++(cr->cr_refs), where, line, who));
|
||||||
|
return cr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nua_client_request_unref_by(nua_client_request_t *cr,
|
||||||
|
char const *where, unsigned line, char const *who)
|
||||||
|
{
|
||||||
|
SU_DEBUG_0(("%p unref %s to %u by %s:%u: %s()\n",
|
||||||
|
cr, cr->cr_methods->crm_method_name,
|
||||||
|
cr->cr_refs - 1, where, line, who));
|
||||||
|
|
||||||
|
if (cr->cr_refs > 1) {
|
||||||
|
cr->cr_refs--;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cr->cr_refs = 0;
|
||||||
|
nua_client_request_destroy(cr);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
nua_client_request_t *nua_client_request_ref(nua_client_request_t *cr)
|
||||||
|
{
|
||||||
|
cr->cr_refs++;
|
||||||
|
return cr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nua_client_request_unref(nua_client_request_t *cr)
|
||||||
|
{
|
||||||
|
if (cr->cr_refs > 1) {
|
||||||
|
cr->cr_refs--;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cr->cr_refs = 0;
|
||||||
|
nua_client_request_destroy(cr);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int nua_client_request_queue(nua_client_request_t *cr)
|
int nua_client_request_queue(nua_client_request_t *cr)
|
||||||
{
|
{
|
||||||
int queued = 0;
|
int queued = 0;
|
||||||
|
@ -2066,6 +2123,8 @@ int nua_client_request_queue(nua_client_request_t *cr)
|
||||||
|
|
||||||
cr->cr_status = 0;
|
cr->cr_status = 0;
|
||||||
|
|
||||||
|
nua_client_request_ref(cr);
|
||||||
|
|
||||||
if (cr->cr_method != sip_method_invite &&
|
if (cr->cr_method != sip_method_invite &&
|
||||||
cr->cr_method != sip_method_cancel) {
|
cr->cr_method != sip_method_cancel) {
|
||||||
while (*queue) {
|
while (*queue) {
|
||||||
|
@ -2092,34 +2151,57 @@ int nua_client_request_queue(nua_client_request_t *cr)
|
||||||
return queued;
|
return queued;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nua_client_request_remove(nua_client_request_t *cr)
|
int
|
||||||
|
nua_client_request_remove(nua_client_request_t *cr)
|
||||||
{
|
{
|
||||||
if (cr->cr_prev)
|
if (cr->cr_prev)
|
||||||
if ((*cr->cr_prev = cr->cr_next))
|
if ((*cr->cr_prev = cr->cr_next))
|
||||||
cr->cr_next->cr_prev = cr->cr_prev;
|
cr->cr_next->cr_prev = cr->cr_prev;
|
||||||
cr->cr_prev = NULL, cr->cr_next = NULL;
|
cr->cr_prev = NULL, cr->cr_next = NULL;
|
||||||
|
|
||||||
|
if (cr->cr_timer) {
|
||||||
|
su_timer_destroy(cr->cr_timer), cr->cr_timer = NULL;
|
||||||
|
nua_client_request_unref(cr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nua_client_request_clean(nua_client_request_t *cr)
|
return nua_client_request_unref(cr);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
nua_client_request_clean(nua_client_request_t *cr)
|
||||||
{
|
{
|
||||||
|
if (cr->cr_orq) {
|
||||||
nta_outgoing_destroy(cr->cr_orq), cr->cr_orq = NULL, cr->cr_acked = 0;
|
nta_outgoing_destroy(cr->cr_orq), cr->cr_orq = NULL, cr->cr_acked = 0;
|
||||||
|
return nua_client_request_unref(cr);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nua_client_request_complete(nua_client_request_t *cr)
|
static int
|
||||||
|
nua_client_request_complete(nua_client_request_t *cr)
|
||||||
{
|
{
|
||||||
nua_client_request_remove(cr);
|
if (cr->cr_orq) {
|
||||||
if (cr && cr->cr_methods->crm_complete)
|
if (cr && cr->cr_methods->crm_complete)
|
||||||
cr->cr_methods->crm_complete(cr);
|
cr->cr_methods->crm_complete(cr);
|
||||||
|
nta_outgoing_destroy(cr->cr_orq), cr->cr_orq = NULL, cr->cr_acked = 0;
|
||||||
|
nua_client_request_unref(cr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nua_client_request_destroy(nua_client_request_t *cr)
|
return nua_client_request_remove(cr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nua_client_request_destroy(nua_client_request_t *cr)
|
||||||
{
|
{
|
||||||
nua_handle_t *nh;
|
nua_handle_t *nh;
|
||||||
|
|
||||||
if (cr == NULL)
|
if (cr == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
nua_client_request_complete(cr);
|
/* Possible references: */
|
||||||
|
assert(cr->cr_prev == NULL); /* queue */
|
||||||
|
assert(cr->cr_orq == NULL); /* transaction callback */
|
||||||
|
assert(cr->cr_timer == NULL); /* timer callback */
|
||||||
|
|
||||||
nh = cr->cr_owner;
|
nh = cr->cr_owner;
|
||||||
|
|
||||||
|
@ -2127,6 +2209,10 @@ void nua_client_request_destroy(nua_client_request_t *cr)
|
||||||
|
|
||||||
nua_client_bind(cr, NULL);
|
nua_client_bind(cr, NULL);
|
||||||
|
|
||||||
|
#if HAVE_MEMLEAK_LOG
|
||||||
|
SU_DEBUG_0(("%p %s for %s\n", cr, __func__, cr->cr_methods->crm_method_name));
|
||||||
|
#endif
|
||||||
|
|
||||||
if (cr->cr_msg)
|
if (cr->cr_msg)
|
||||||
msg_destroy(cr->cr_msg);
|
msg_destroy(cr->cr_msg);
|
||||||
cr->cr_msg = NULL, cr->cr_sip = NULL;
|
cr->cr_msg = NULL, cr->cr_sip = NULL;
|
||||||
|
@ -2135,9 +2221,6 @@ void nua_client_request_destroy(nua_client_request_t *cr)
|
||||||
nta_outgoing_destroy(cr->cr_orq);
|
nta_outgoing_destroy(cr->cr_orq);
|
||||||
cr->cr_orq = NULL;
|
cr->cr_orq = NULL;
|
||||||
|
|
||||||
if (cr->cr_timer)
|
|
||||||
su_timer_destroy(cr->cr_timer), cr->cr_timer = NULL;
|
|
||||||
|
|
||||||
if (cr->cr_target)
|
if (cr->cr_target)
|
||||||
su_free(nh->nh_home, cr->cr_target);
|
su_free(nh->nh_home, cr->cr_target);
|
||||||
|
|
||||||
|
@ -2154,39 +2237,52 @@ int nua_client_bind(nua_client_request_t *cr, nua_dialog_usage_t *du)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (du == NULL) {
|
if (du == NULL) {
|
||||||
if (cr->cr_usage && cr->cr_usage->du_cr == cr)
|
du = cr->cr_usage;
|
||||||
cr->cr_usage->du_cr = NULL;
|
|
||||||
cr->cr_usage = NULL;
|
cr->cr_usage = NULL;
|
||||||
|
if (du && du->du_cr == cr) {
|
||||||
|
du->du_cr = NULL;
|
||||||
|
nua_client_request_unref(cr);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (du->du_cr && cr != du->du_cr) {
|
if (du->du_cr && cr == du->du_cr)
|
||||||
/* This should never happen (but it does):
|
return 0;
|
||||||
assert(!nua_client_is_queued(du->du_cr));
|
|
||||||
*/
|
if (du->du_cr) {
|
||||||
if (nua_client_is_queued(du->du_cr))
|
nua_client_bind(du->du_cr, NULL);
|
||||||
return -1;
|
|
||||||
if (nua_client_is_reporting(du->du_cr)) {
|
|
||||||
du->du_cr->cr_usage = NULL;
|
|
||||||
du->du_cr = NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
nua_client_request_destroy(du->du_cr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
du->du_cr = cr, cr->cr_usage = du;
|
du->du_cr = nua_client_request_ref(cr), cr->cr_usage = du;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Initialize client request for sending.
|
/**Initialize client request for sending.
|
||||||
*
|
*
|
||||||
* This function is called only first time the request is sent.
|
* This function is called when the request is taken from queue and sent.
|
||||||
*
|
*
|
||||||
* @retval 0 if request is pending
|
* @retval 0 if request is pending
|
||||||
* @retval >=1 if error event has been sent
|
* @retval >=1 if error event has been sent
|
||||||
*/
|
*/
|
||||||
int nua_client_init_request(nua_client_request_t *cr)
|
int nua_client_init_request(nua_client_request_t *cr)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
nua_client_request_ref(cr);
|
||||||
|
retval = nua_client_init_request0(cr);
|
||||||
|
nua_client_request_unref(cr);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**Initialize client request for sending.
|
||||||
|
*
|
||||||
|
* This function is called when the request is taken from queue and sent.
|
||||||
|
*
|
||||||
|
* @retval 0 if request is pending
|
||||||
|
* @retval >=1 if error event has been sent
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
int nua_client_init_request0(nua_client_request_t *cr)
|
||||||
{
|
{
|
||||||
nua_handle_t *nh = cr->cr_owner;
|
nua_handle_t *nh = cr->cr_owner;
|
||||||
nua_t *nua = nh->nh_nua;
|
nua_t *nua = nh->nh_nua;
|
||||||
|
@ -2354,7 +2450,6 @@ int nua_client_init_request(nua_client_request_t *cr)
|
||||||
cr->cr_sip = sip;
|
cr->cr_sip = sip;
|
||||||
|
|
||||||
return nua_client_request_try(cr);
|
return nua_client_request_try(cr);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
msg_t *nua_client_request_template(nua_client_request_t *cr)
|
msg_t *nua_client_request_template(nua_client_request_t *cr)
|
||||||
|
@ -2373,7 +2468,7 @@ msg_t *nua_client_request_template(nua_client_request_t *cr)
|
||||||
tagi_t const *t = nh->nh_tags;
|
tagi_t const *t = nh->nh_tags;
|
||||||
|
|
||||||
/* Use the From header from the dialog.
|
/* Use the From header from the dialog.
|
||||||
From is always first tag in the handle */
|
If From is set, it is always first tag in the handle */
|
||||||
if (ds->ds_leg && t->t_tag == siptag_from)
|
if (ds->ds_leg && t->t_tag == siptag_from)
|
||||||
t++;
|
t++;
|
||||||
|
|
||||||
|
@ -2670,15 +2765,23 @@ int nua_base_client_request(nua_client_request_t *cr, msg_t *msg, sip_t *sip,
|
||||||
|
|
||||||
cr->cr_seq = sip->sip_cseq->cs_seq; /* Save last sequence number */
|
cr->cr_seq = sip->sip_cseq->cs_seq; /* Save last sequence number */
|
||||||
|
|
||||||
|
assert(cr->cr_orq == NULL);
|
||||||
|
|
||||||
cr->cr_orq = nta_outgoing_mcreate(nh->nh_nua->nua_nta,
|
cr->cr_orq = nta_outgoing_mcreate(nh->nh_nua->nua_nta,
|
||||||
nua_client_orq_response, cr,
|
nua_client_orq_response,
|
||||||
|
nua_client_request_ref(cr),
|
||||||
NULL,
|
NULL,
|
||||||
msg,
|
msg,
|
||||||
TAG_IF(proxy_is_set,
|
TAG_IF(proxy_is_set,
|
||||||
NTATAG_DEFAULT_PROXY(proxy)),
|
NTATAG_DEFAULT_PROXY(proxy)),
|
||||||
TAG_NEXT(tags));
|
TAG_NEXT(tags));
|
||||||
|
|
||||||
return cr->cr_orq ? 0 : -1;
|
if (cr->cr_orq == NULL) {
|
||||||
|
nua_client_request_unref(cr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Callback for nta client transaction */
|
/** Callback for nta client transaction */
|
||||||
|
@ -2741,10 +2844,13 @@ int nua_client_response(nua_client_request_t *cr,
|
||||||
{
|
{
|
||||||
nua_handle_t *nh = cr->cr_owner;
|
nua_handle_t *nh = cr->cr_owner;
|
||||||
nua_dialog_usage_t *du = cr->cr_usage;
|
nua_dialog_usage_t *du = cr->cr_usage;
|
||||||
|
int retval = 0;
|
||||||
|
|
||||||
if (cr->cr_restarting)
|
if (cr->cr_restarting)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
nua_client_request_ref(cr);
|
||||||
|
|
||||||
cr->cr_status = status;
|
cr->cr_status = status;
|
||||||
cr->cr_phrase = phrase;
|
cr->cr_phrase = phrase;
|
||||||
|
|
||||||
|
@ -2752,6 +2858,7 @@ int nua_client_response(nua_client_request_t *cr,
|
||||||
/* Xyzzy */
|
/* Xyzzy */
|
||||||
}
|
}
|
||||||
else if (sip && nua_client_check_restart(cr, status, phrase, sip)) {
|
else if (sip && nua_client_check_restart(cr, status, phrase, sip)) {
|
||||||
|
nua_client_request_unref(cr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else if (status < 300) {
|
else if (status < 300) {
|
||||||
|
@ -2793,13 +2900,17 @@ int nua_client_response(nua_client_request_t *cr,
|
||||||
else
|
else
|
||||||
nua_base_client_response(cr, status, phrase, sip, NULL);
|
nua_base_client_response(cr, status, phrase, sip, NULL);
|
||||||
cr->cr_phrase = NULL;
|
cr->cr_phrase = NULL;
|
||||||
return 0;
|
}
|
||||||
|
else {
|
||||||
|
if (cr->cr_methods->crm_recv)
|
||||||
|
retval = cr->cr_methods->crm_recv(cr, status, phrase, sip);
|
||||||
|
else
|
||||||
|
retval = nua_base_client_response(cr, status, phrase, sip, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cr->cr_methods->crm_recv)
|
nua_client_request_unref(cr);
|
||||||
return cr->cr_methods->crm_recv(cr, status, phrase, sip);
|
|
||||||
else
|
return retval;
|
||||||
return nua_base_client_response(cr, status, phrase, sip, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Check if request should be restarted.
|
/** Check if request should be restarted.
|
||||||
|
@ -2914,6 +3025,7 @@ int nua_base_client_check_restart(nua_client_request_t *cr,
|
||||||
nua_client_report(cr, status, phrase, NULL, orq, NULL);
|
nua_client_report(cr, status, phrase, NULL, orq, NULL);
|
||||||
nta_outgoing_destroy(orq);
|
nta_outgoing_destroy(orq);
|
||||||
cr->cr_status = 0, cr->cr_phrase = NULL;
|
cr->cr_status = 0, cr->cr_phrase = NULL;
|
||||||
|
nua_client_request_unref(cr);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -2922,20 +3034,24 @@ int nua_base_client_check_restart(nua_client_request_t *cr,
|
||||||
if (500 <= status && status < 600 &&
|
if (500 <= status && status < 600 &&
|
||||||
sip->sip_retry_after &&
|
sip->sip_retry_after &&
|
||||||
sip->sip_retry_after->af_delta < 32) {
|
sip->sip_retry_after->af_delta < 32) {
|
||||||
|
su_timer_t *timer;
|
||||||
char phrase[18]; /* Retry After XXXX\0 */
|
char phrase[18]; /* Retry After XXXX\0 */
|
||||||
|
|
||||||
if (cr->cr_timer == NULL)
|
timer = su_timer_create(su_root_task(nh->nh_nua->nua_root), 0);
|
||||||
cr->cr_timer = su_timer_create(su_root_task(nh->nh_nua->nua_root), 0);
|
|
||||||
|
|
||||||
if (su_timer_set_interval(cr->cr_timer, nua_client_restart_after, cr,
|
if (su_timer_set_interval(timer, nua_client_restart_after, cr,
|
||||||
sip->sip_retry_after->af_delta * 1000) < 0)
|
sip->sip_retry_after->af_delta * 1000) < 0) {
|
||||||
|
su_timer_destroy(timer);
|
||||||
return 0; /* Too bad */
|
return 0; /* Too bad */
|
||||||
|
}
|
||||||
|
|
||||||
|
cr->cr_timer = timer; /* This takes over reference from orq */
|
||||||
|
|
||||||
snprintf(phrase, sizeof phrase, "Retry After %u",
|
snprintf(phrase, sizeof phrase, "Retry After %u",
|
||||||
(unsigned)sip->sip_retry_after->af_delta);
|
(unsigned)sip->sip_retry_after->af_delta);
|
||||||
|
|
||||||
orq = cr->cr_orq, cr->cr_orq = NULL;
|
orq = cr->cr_orq, cr->cr_orq = NULL;
|
||||||
cr->cr_waiting = cr->cr_wait_for_timer = 1;
|
cr->cr_waiting = 1;
|
||||||
nua_client_report(cr, 100, phrase, NULL, orq, NULL);
|
nua_client_report(cr, 100, phrase, NULL, orq, NULL);
|
||||||
nta_outgoing_destroy(orq);
|
nta_outgoing_destroy(orq);
|
||||||
cr->cr_status = 0, cr->cr_phrase = NULL;
|
cr->cr_status = 0, cr->cr_phrase = NULL;
|
||||||
|
@ -2951,11 +3067,10 @@ void nua_client_restart_after(su_root_magic_t *magic,
|
||||||
su_timer_t *timer,
|
su_timer_t *timer,
|
||||||
nua_client_request_t *cr)
|
nua_client_request_t *cr)
|
||||||
{
|
{
|
||||||
if (!cr->cr_wait_for_timer)
|
cr->cr_waiting = 0;
|
||||||
return;
|
su_timer_destroy(cr->cr_timer), cr->cr_timer = NULL;
|
||||||
|
|
||||||
cr->cr_waiting = cr->cr_wait_for_timer = 0;
|
|
||||||
nua_client_restart_request(cr, cr->cr_terminating, NULL);
|
nua_client_restart_request(cr, cr->cr_terminating, NULL);
|
||||||
|
nua_client_request_unref(cr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Restart request.
|
/** Restart request.
|
||||||
|
@ -3017,6 +3132,7 @@ int nua_client_restart(nua_client_request_t *cr,
|
||||||
nua_client_report(cr, status, phrase, NULL, orq, NULL);
|
nua_client_report(cr, status, phrase, NULL, orq, NULL);
|
||||||
|
|
||||||
nta_outgoing_destroy(orq);
|
nta_outgoing_destroy(orq);
|
||||||
|
nua_client_request_unref(cr); /* ... reference used by old orq */
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -3086,7 +3202,6 @@ int nua_base_client_response(nua_client_request_t *cr,
|
||||||
nua_handle_t *nh = cr->cr_owner;
|
nua_handle_t *nh = cr->cr_owner;
|
||||||
sip_method_t method = cr->cr_method;
|
sip_method_t method = cr->cr_method;
|
||||||
nua_dialog_usage_t *du;
|
nua_dialog_usage_t *du;
|
||||||
nua_client_request_t *cr_next;
|
|
||||||
|
|
||||||
cr->cr_reporting = 1, nh->nh_ds->ds_reporting = 1;
|
cr->cr_reporting = 1, nh->nh_ds->ds_reporting = 1;
|
||||||
|
|
||||||
|
@ -3115,8 +3230,7 @@ int nua_base_client_response(nua_client_request_t *cr,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cr->cr_orq)
|
nua_client_request_clean(cr);
|
||||||
nta_outgoing_destroy(cr->cr_orq), cr->cr_orq = NULL, cr->cr_acked = 0;
|
|
||||||
|
|
||||||
du = cr->cr_usage;
|
du = cr->cr_usage;
|
||||||
|
|
||||||
|
@ -3144,15 +3258,10 @@ int nua_base_client_response(nua_client_request_t *cr,
|
||||||
cr->cr_phrase = NULL;
|
cr->cr_phrase = NULL;
|
||||||
cr->cr_reporting = 0, nh->nh_ds->ds_reporting = 0;
|
cr->cr_reporting = 0, nh->nh_ds->ds_reporting = 0;
|
||||||
|
|
||||||
cr_next = nh->nh_ds->ds_cr;
|
|
||||||
|
|
||||||
if (!nua_client_is_queued(cr) && !nua_client_is_bound(cr))
|
|
||||||
nua_client_request_destroy(cr);
|
|
||||||
|
|
||||||
if (method == sip_method_cancel)
|
if (method == sip_method_cancel)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
return nua_client_next_request(cr_next, method == sip_method_invite);
|
return nua_client_next_request(nh->nh_ds->ds_cr, method == sip_method_invite);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Send event, zap transaction but leave cr in list */
|
/** Send event, zap transaction but leave cr in list */
|
||||||
|
@ -3206,8 +3315,9 @@ int nua_client_next_request(nua_client_request_t *cr, int invite)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cr && cr->cr_orq == NULL)
|
if (cr && cr->cr_orq == NULL) {
|
||||||
nua_client_init_request(cr);
|
nua_client_init_request(cr);
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue