Commit 78a20726 authored by Pekka Pessi's avatar Pekka Pessi

nua: fixed problems in state machines.

These problems are mostly introduced in 1.12.5:
- assert failed if INVITE was received when calling
  (reported by Michael Jerris)
- assert failed if nua_invite() was called second time before receiving
  final response to first INVITE (ditto)
- ACK is now always sent if session was terminated after receiving 2XX
- if nua has a pending incoming INVITE request, return 491 to
  nua_invite()

darcs-hash:20070214201847-55b16-962b2de246eee8100e4dba8d7a28c507b13c376c.gz
parent 61ec41d3
......@@ -345,6 +345,15 @@ void nua_dialog_usage_remove_at(nua_owner_t *own,
nua_client_request_t *cr, *cr_next;
nua_server_request_t *sr, *sr_next;
*at = du->du_next;
o = du->du_event;
SU_DEBUG_5(("nua(%p): removing %s usage%s%s\n",
(void *)own, nua_dialog_usage_name(du),
o ? " with event " : "", o ? o->o_type :""));
du->du_class->usage_remove(own, ds, du);
/* Destroy saved client request */
if (nua_client_is_bound(du->du_cr)) {
nua_client_bind(cr = du->du_cr, NULL);
......@@ -366,26 +375,20 @@ void nua_dialog_usage_remove_at(nua_owner_t *own,
nua_server_request_destroy(sr);
}
*at = du->du_next;
o = du->du_event;
SU_DEBUG_5(("nua(%p): removing %s usage%s%s\n",
(void *)own, nua_dialog_usage_name(du),
o ? " with event " : "", o ? o->o_type :""));
du->du_class->usage_remove(own, ds, du);
su_home_unref(own);
su_free(own, du);
}
/* Zap dialog if there are no more usages */
if (ds->ds_usage == NULL) {
if (ds->ds_terminated)
;
else if (ds->ds_usage == NULL) {
nua_dialog_remove(own, ds, NULL);
ds->ds_has_events = 0;
ds->ds_terminated = 0;
return;
}
else if (!ds->ds_terminated) {
else {
nua_dialog_log_usage(own, ds);
}
}
......@@ -561,6 +564,8 @@ int nua_dialog_shutdown(nua_owner_t *owner, nua_dialog_state_t *ds)
{
nua_dialog_usage_t *du;
ds->ds_terminated = 1;
do {
for (du = ds->ds_usage; du; du = du->du_next) {
if (!du->du_shutdown) {
......@@ -575,8 +580,8 @@ int nua_dialog_shutdown(nua_owner_t *owner, nua_dialog_state_t *ds)
/** (Gracefully) terminate usage */
void nua_dialog_usage_shutdown(nua_owner_t *owner,
nua_dialog_state_t *ds,
nua_dialog_usage_t *du)
nua_dialog_state_t *ds,
nua_dialog_usage_t *du)
{
if (du) {
du->du_refresh = 0;
......
......@@ -115,6 +115,8 @@ struct nua_server_request {
unsigned sr_terminating:1; /**< Terminate usage after final response */
unsigned sr_gracefully:1; /**< Terminate usage gracefully */
unsigned sr_neutral:1; /**< No effect on session or other usage */
/* Flags used with offer-answer */
unsigned sr_offer_recv:1; /**< We have received an offer */
unsigned sr_answer_sent:2; /**< We have answered (reliably, if >1) */
......@@ -284,6 +286,9 @@ struct nua_client_request
unsigned cr_offer_recv:1; /**< Recv offer in a response */
unsigned cr_answer_sent:1; /**< Sent answer in (PR)ACK */
/* Flags with usage */
unsigned cr_neutral:1; /**< No effect on session or other usage */
/* Lifelong flags? */
unsigned cr_auto:1; /**< Request was generated by stack */
unsigned cr_has_contact:1; /**< Request has user Contact */
......@@ -318,6 +323,7 @@ struct nua_dialog_state
unsigned ds_has_register:1; /**< We have registration */
unsigned ds_has_publish:1; /**< We have publish */
unsigned ds_got_session:1; /**< We have (or have had) session */
unsigned ds_got_referrals:1; /**< We have (or have had) referrals */
unsigned :0;
......@@ -573,6 +579,10 @@ int nua_client_report(nua_client_request_t *cr,
nua_client_request_t *nua_client_request_pending(nua_client_request_t const *);
int nua_client_init_requests(nua_client_request_t *cr,
void const *cr0,
int invite);
/* ---------------------------------------------------------------------- */
extern nua_server_methods_t const
......@@ -590,6 +600,7 @@ extern nua_server_methods_t const
nua_refer_server_methods, /**< REFER */
nua_publish_server_methods; /**< PUBLISH */
/** Return true if we have not sent final response to request */
static inline
int nua_server_request_is_pending(nua_server_request_t const *sr)
{
......
This diff is collapsed.
......@@ -743,14 +743,14 @@ void nh_destroy(nua_t *nua, nua_handle_t *nh)
if (nh->nh_notifier)
nea_server_destroy(nh->nh_notifier), nh->nh_notifier = NULL;
nua_dialog_deinit(nh, nh->nh_ds);
while (nh->nh_ds->ds_cr)
nua_client_request_destroy(nh->nh_ds->ds_cr);
while (nh->nh_ds->ds_sr)
nua_server_request_destroy(nh->nh_ds->ds_sr);
nua_dialog_deinit(nh, nh->nh_ds);
if (nh->nh_soa)
soa_destroy(nh->nh_soa), nh->nh_soa = NULL;
......@@ -1090,6 +1090,9 @@ int nua_stack_process_request(nua_handle_t *nh,
nta_incoming_tag(irq, NULL);
if (method == sip_method_cancel)
return 481;
/* Hook to outbound */
if (method == sip_method_options) {
status = nua_registration_process_request(nua->nua_registrations,
......@@ -1485,6 +1488,8 @@ int nua_server_respond(nua_server_request_t *sr, tagi_t const *tags)
else if (next.msg)
msg_destroy(next.msg);
assert(sr->sr_status >= 200 || sr->sr_response.msg);
return retval;
}
......@@ -1521,7 +1526,7 @@ int nua_server_report(nua_server_request_t *sr)
if (sr)
return sr->sr_methods->sm_report(sr, NULL);
else
return 2;
return 1;
}
int nua_base_server_treport(nua_server_request_t *sr,
......@@ -1763,8 +1768,11 @@ inline int nua_client_request_queue(nua_client_request_t *cr)
}
}
else {
while (*queue)
while (*queue) {
queue = &(*queue)->cr_next;
if (cr->cr_method == sip_method_invite)
queued = 1;
}
}
if ((cr->cr_next = *queue))
......@@ -2544,7 +2552,7 @@ int nua_base_client_response(nua_client_request_t *cr,
tagi_t const *tags)
{
nua_handle_t *nh = cr->cr_owner;
int next;
sip_method_t method = cr->cr_method;
cr->cr_reporting = 1;
......@@ -2553,14 +2561,15 @@ int nua_base_client_response(nua_client_request_t *cr,
nua_client_report(cr, status, phrase, sip, cr->cr_orq, tags);
if (status >= 200)
nua_client_request_remove(cr);
if (cr->cr_method == sip_method_invite ? status < 300 : status < 200) {
if (status < 200 ||
/* Un-ACKed 2XX response to INVITE */
(cr->cr_method == sip_method_invite && status < 300 && cr->cr_orq)) {
cr->cr_reporting = 0;
return 1;
}
nua_client_request_remove(cr);
if (cr->cr_orq)
nta_outgoing_destroy(cr->cr_orq), cr->cr_orq = NULL;
......@@ -2586,16 +2595,12 @@ int nua_base_client_response(nua_client_request_t *cr,
if (nua_client_is_queued(cr))
return 1;
next = cr->cr_method != sip_method_invite && cr->cr_method != sip_method_cancel;
if (!nua_client_is_bound(cr))
nua_client_request_destroy(cr);
if (next && nh->nh_ds->ds_cr != NULL && nh->nh_ds->ds_cr != cr) {
cr = nh->nh_ds->ds_cr;
if (cr->cr_method != sip_method_invite && cr->cr_method != sip_method_cancel)
nua_client_init_request(cr);
}
if (method != sip_method_cancel)
return nua_client_init_requests(nh->nh_ds->ds_cr, cr,
method == sip_method_invite);
return 1;
}
......@@ -2639,6 +2644,29 @@ int nua_client_treport(nua_client_request_t *cr,
return retval;
}
int nua_client_init_requests(nua_client_request_t *cr,
void const *cr0,
int invite)
{
if (cr0 == cr) /* already initialized! */
return 1;
for (; cr; cr = cr->cr_next) {
if (cr->cr_method == sip_method_cancel)
continue;
if (invite
? cr->cr_method == sip_method_invite
: cr->cr_method != sip_method_invite)
break;
}
if (cr)
nua_client_init_request(cr);
return 1;
}
nua_client_request_t *
nua_client_request_pending(nua_client_request_t const *cr)
{
......
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