Fri Jan 16 13:37:43 CST 2009 Pekka Pessi <first.last@nokia.com>

* nua: fixed problem handling re-SUBSCRIBE when it creates new dialog



git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@11836 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Michael Jerris 2009-02-11 17:08:41 +00:00
parent 10c67f8219
commit 587408b8ce
8 changed files with 152 additions and 97 deletions

View File

@ -1 +1 @@
Wed Feb 11 11:07:52 CST 2009
Wed Feb 11 11:08:29 CST 2009

View File

@ -43,6 +43,8 @@
#include <fnmatch.h>
#endif
#include "test_s2.h"
static char const * const default_patterns[] = { "*", NULL };
static char const * const *test_patterns = default_patterns;
@ -80,6 +82,10 @@ int main(int argc, char *argv[])
Suite *suite = suite_create("Unit tests for Sofia-SIP UA Engine");
SRunner *runner;
s2_tester = "check_nua";
if (getenv("CHECK_NUA_VERBOSE"))
s2_start_stop = strtoul(getenv("CHECK_NUA_VERBOSE"), NULL, 10);
if (getenv("CHECK_NUA_CASES")) {
size_t i;
char *s, **patterns;

View File

@ -10,6 +10,7 @@ void check_nua_tcase_add_test(TCase *, TFun, char const *name);
void check_session_cases(Suite *suite);
void check_register_cases(Suite *suite);
void check_simple_cases(Suite *suite);
#endif

View File

@ -54,12 +54,13 @@ static nua_t *nua;
static void register_setup(void)
{
nua = s2_nua_setup(TAG_END());
nua = s2_nua_setup("register", TAG_END());
}
static void register_pingpong_setup(void)
{
nua = s2_nua_setup(TPTAG_PINGPONG(20000),
nua = s2_nua_setup("register with pingpong",
TPTAG_PINGPONG(20000),
TPTAG_KEEPALIVE(10000),
TAG_END());
tport_set_params(s2->tcp.tport, TPTAG_PONG2PING(1), TAG_END());
@ -68,6 +69,7 @@ static void register_pingpong_setup(void)
static void register_teardown(void)
{
s2_teardown_started("register");
nua_shutdown(nua);
fail_unless(s2_check_event(nua_r_shutdown, 200));
s2_nua_teardown();

View File

@ -63,9 +63,8 @@ static struct dialog *dialog = NULL;
static void call_setup(void)
{
s2_case("0.1.1", "Setup for Call Tests", "");
nua = s2_nua_setup(SIPTAG_ORGANIZATION_STR("Pussy Galore's Flying Circus"),
nua = s2_nua_setup("call",
SIPTAG_ORGANIZATION_STR("Pussy Galore's Flying Circus"),
NUTAG_OUTBOUND("no-options-keepalive, no-validate"),
TAG_END());
@ -85,7 +84,7 @@ static void call_setup(void)
static void call_teardown(void)
{
s2_case("0.1.2", "Teardown Call Test Setup", "");
s2_teardown_started("call");
mark_point();
@ -3078,6 +3077,7 @@ static void options_setup(void)
static void options_teardown(void)
{
s2_teardown_started("options");
call_teardown();
}

View File

@ -1973,8 +1973,7 @@ int nua_base_server_report(nua_server_request_t *sr, tagi_t const *tags)
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_sendmsg(nua_client_request_t *cr,
msg_t *msg, sip_t *sip);
static int nua_client_request_sendmsg(nua_client_request_t *cr);
static void nua_client_restart_after(su_root_magic_t *magic,
su_timer_t *timer,
nua_client_request_t *cr);
@ -2416,23 +2415,6 @@ int nua_client_init_request0(nua_client_request_t *cr)
(sip_header_t *)sip->sip_from) < 0) {
return nua_client_return(cr, NUA_ERROR_AT(__FILE__, __LINE__), msg);
}
if (cr->cr_dialog) {
ds->ds_leg = nta_leg_tcreate(nua->nua_nta,
nua_stack_process_request, nh,
SIPTAG_CALL_ID(sip->sip_call_id),
SIPTAG_FROM(sip->sip_from),
SIPTAG_TO(sip->sip_to),
SIPTAG_CSEQ(sip->sip_cseq),
TAG_END());
if (!ds->ds_leg)
return nua_client_return(cr, NUA_ERROR_AT(__FILE__, __LINE__), msg);
if (!sip->sip_from->a_tag &&
sip_from_tag(msg_home(msg), sip->sip_from,
nta_leg_tag(ds->ds_leg, NULL)) < 0)
return nua_client_return(cr, NUA_ERROR_AT(__FILE__, __LINE__), msg);
}
}
else {
if (ds->ds_route)
@ -2540,15 +2522,17 @@ int nua_client_resend_request(nua_client_request_t *cr,
if (nua_client_request_queue(cr))
return 0;
if (nua_dialog_is_reporting(cr->cr_owner->nh_ds))
return 0;
return nua_client_request_try(cr);
}
return 0;
}
/** Create a request message and send it.
/** Send a request message.
*
* If an error occurs, send error event to the application.
*
@ -2558,26 +2542,11 @@ int nua_client_resend_request(nua_client_request_t *cr,
static
int nua_client_request_try(nua_client_request_t *cr)
{
int error = -1;
msg_t *msg = msg_copy(cr->cr_msg);
sip_t *sip = sip_object(msg);
cr->cr_answer_recv = 0, cr->cr_offer_sent = 0;
cr->cr_offer_recv = 0, cr->cr_answer_sent = 0;
if (msg && sip) {
error = nua_client_request_sendmsg(cr, msg, sip);
if (!error)
return 0;
if (error == -1)
msg_destroy(msg);
}
int error = nua_client_request_sendmsg(cr);
if (error < 0)
error = nua_client_response(cr, NUA_ERROR_AT(__FILE__, __LINE__), NULL);
assert(error > 0);
return error;
}
@ -2585,13 +2554,10 @@ int nua_client_request_try(nua_client_request_t *cr)
*
* @retval 0 if request is pending
* @retval >=1 if error event has been sent
* @retval -1 if error occurred but event has not been sent,
and @a msg has not been destroyed
* @retval -2 if error occurred, event has not been sent,
* but @a msg has been destroyed
* @retval < 0 if no error event has been sent
*/
static
int nua_client_request_sendmsg(nua_client_request_t *cr, msg_t *msg, sip_t *sip)
int nua_client_request_sendmsg(nua_client_request_t *cr)
{
nua_handle_t *nh = cr->cr_owner;
nua_dialog_state_t *ds = nh->nh_ds;
@ -2599,9 +2565,36 @@ int nua_client_request_sendmsg(nua_client_request_t *cr, msg_t *msg, sip_t *sip)
char const *name = cr->cr_method_name;
url_string_t const *url = (url_string_t *)cr->cr_target;
nta_leg_t *leg;
msg_t *msg;
sip_t *sip;
int error;
assert(cr->cr_orq == NULL);
cr->cr_offer_sent = cr->cr_answer_recv = 0;
cr->cr_offer_recv = cr->cr_answer_sent = 0;
if (!ds->ds_leg && cr->cr_dialog) {
ds->ds_leg = nta_leg_tcreate(nh->nh_nua->nua_nta,
nua_stack_process_request, nh,
SIPTAG_CALL_ID(cr->cr_sip->sip_call_id),
SIPTAG_FROM(cr->cr_sip->sip_from),
SIPTAG_TO(cr->cr_sip->sip_to),
SIPTAG_CSEQ(cr->cr_sip->sip_cseq),
TAG_END());
if (!ds->ds_leg)
return -1;
}
if (cr->cr_sip->sip_from && ds->ds_leg) {
if (cr->cr_sip->sip_from->a_tag == NULL) {
if (sip_from_tag(msg_home(cr->cr_msg), cr->cr_sip->sip_from,
nta_leg_tag(ds->ds_leg, NULL)) < 0) {
return -1;
}
}
}
cr->cr_retry_count++;
if (ds->ds_leg)
@ -2609,6 +2602,11 @@ int nua_client_request_sendmsg(nua_client_request_t *cr, msg_t *msg, sip_t *sip)
else
leg = nh->nh_nua->nua_dhandle->nh_ds->ds_leg; /* Default leg */
msg = msg_copy(cr->cr_msg), sip = sip_object(msg);
if (msg == NULL)
return -1;
if (nua_dialog_is_established(ds)) {
while (sip->sip_route)
sip_route_remove(msg, sip);
@ -2639,8 +2637,10 @@ int nua_client_request_sendmsg(nua_client_request_t *cr, msg_t *msg, sip_t *sip)
* generated based on the dialog information and added to the request.
* If the dialog has a route, it is added to the request, too.
*/
if (nta_msg_request_complete(msg, leg, method, name, url) < 0)
if (nta_msg_request_complete(msg, leg, method, name, url) < 0) {
msg_destroy(msg);
return -1;
}
/**@MaxForwards header (with default value set by NTATAG_MAX_FORWARDS()) is
* also added now, if it does not exist.
@ -2716,16 +2716,23 @@ int nua_client_request_sendmsg(nua_client_request_t *cr, msg_t *msg, sip_t *sip)
cr->cr_contactize &&
!cr->cr_has_contact &&
!ds->ds_ltarget,
!ds->ds_route) < 0)
!ds->ds_route) < 0) {
msg_destroy(msg);
return -1;
}
}
cr->cr_wait_for_cred = 0;
if (cr->cr_methods->crm_send)
return cr->cr_methods->crm_send(cr, msg, sip, NULL);
error = cr->cr_methods->crm_send(cr, msg, sip, NULL);
else
error = nua_base_client_request(cr, msg, sip, NULL);
return nua_base_client_request(cr, msg, sip, NULL);
if (error != 0 && error != -2)
msg_destroy(msg);
return error;
}
/**Add tags to request message and send it,
@ -2793,9 +2800,10 @@ int nua_base_client_request(nua_client_request_t *cr, msg_t *msg, sip_t *sip,
}
/** Callback for nta client transaction */
int nua_client_orq_response(nua_client_request_t *cr,
nta_outgoing_t *orq,
sip_t const *sip)
int
nua_client_orq_response(nua_client_request_t *cr,
nta_outgoing_t *orq,
sip_t const *sip)
{
int status;
char const *phrase;
@ -3090,11 +3098,8 @@ int nua_client_restart(nua_client_request_t *cr,
int status, char const *phrase)
{
nua_handle_t *nh = cr->cr_owner;
nua_dialog_state_t *ds = nh->nh_ds;
nta_outgoing_t *orq;
int error = -1, terminated, graceful;
msg_t *msg = NULL;
sip_t *sip = NULL;
if (cr->cr_retry_count > NH_PGET(nh, retry_count))
return 0;
@ -3102,32 +3107,10 @@ int nua_client_restart(nua_client_request_t *cr,
orq = cr->cr_orq, cr->cr_orq = NULL; assert(orq);
terminated = cr->cr_terminated, cr->cr_terminated = 0;
graceful = cr->cr_graceful, cr->cr_graceful = 0;
cr->cr_offer_sent = cr->cr_answer_recv = 0;
cr->cr_offer_recv = cr->cr_answer_sent = 0;
if (!ds->ds_leg && cr->cr_dialog) {
sip_t const *sip = cr->cr_sip;
ds->ds_leg = nta_leg_tcreate(nh->nh_nua->nua_nta,
nua_stack_process_request, nh,
SIPTAG_CALL_ID(sip->sip_call_id),
SIPTAG_FROM(sip->sip_from),
SIPTAG_TO(sip->sip_to),
SIPTAG_CSEQ(sip->sip_cseq),
TAG_END());
}
if (ds->ds_leg || !cr->cr_dialog) {
msg = msg_copy(cr->cr_msg);
sip = sip_object(msg);
}
if (msg && sip) {
cr->cr_restarting = 1;
error = nua_client_request_sendmsg(cr, msg, sip);
cr->cr_restarting = 0;
if (error !=0 && error != -2)
msg_destroy(msg);
}
cr->cr_restarting = 1;
error = nua_client_request_sendmsg(cr);
cr->cr_restarting = 0;
if (error) {
cr->cr_graceful = graceful;

View File

@ -52,6 +52,9 @@
#include <limits.h>
#include <time.h>
char const *s2_tester = "s2_tester";
int s2_start_stop;
/* -- Module types ------------------------------------------------------ */
struct tp_magic_s
@ -207,6 +210,19 @@ int s2_check_callstate(enum nua_callstate state)
return retval;
}
int s2_check_substate(struct event *e, enum nua_substate state)
{
int retval = 0;
tagi_t const *tagi;
tagi = tl_find(e->data->e_tags, nutag_substate);
if (tagi) {
retval = (tag_value_t)state == tagi->t_value;
}
return retval;
}
static void
s2_nua_callback(nua_event_t event,
int status, char const *phrase,
@ -371,6 +387,22 @@ s2_check_request(sip_method_t method, char const *name)
return m != NULL;
}
void
s2_save_uas_dialog(struct dialog *d, sip_t *sip)
{
if (d && !d->local) {
assert(sip->sip_request);
d->local = sip_from_dup(d->home, sip->sip_to);
if (d->local->a_tag == NULL)
sip_from_tag(d->home, d->local, s2_generate_tag(d->home));
d->remote = sip_to_dup(d->home, sip->sip_from);
d->call_id = sip_call_id_dup(d->home, sip->sip_call_id);
d->rseq = sip->sip_cseq->cs_seq;
/* d->route = sip_route_dup(d->home, sip->sip_record_route); */
d->target = sip_contact_dup(d->home, sip->sip_contact);
}
}
struct message *
s2_respond_to(struct message *m, struct dialog *d,
int status, char const *phrase,
@ -386,6 +418,8 @@ s2_respond_to(struct message *m, struct dialog *d,
assert(m); assert(m->msg); assert(m->tport);
assert(100 <= status && status < 700);
s2_save_uas_dialog(d, m->sip);
ta_start(ta, tag, value);
reply = s2_msg(0); sip = sip_object(reply); home = msg_home(reply);
@ -414,13 +448,7 @@ s2_respond_to(struct message *m, struct dialog *d,
}
}
if (d && !d->local) {
d->local = sip_from_dup(d->home, sip->sip_to);
d->remote = sip_to_dup(d->home, sip->sip_from);
d->call_id = sip_call_id_dup(d->home, sip->sip_call_id);
d->rseq = sip->sip_cseq->cs_seq;
/* d->route = sip_route_dup(d->home, sip->sip_record_route); */
d->target = sip_contact_dup(d->home, m->sip->sip_contact);
if (d && !d->contact) {
d->contact = sip_contact_dup(d->home, sip->sip_contact);
}
@ -806,6 +834,9 @@ void s2_case(char const *number,
char const *description)
{
_s2case = number;
if (s2_start_stop)
printf("%s - starting %s %s\n", s2_tester, number, title);
}
/* ---------------------------------------------------------------------- */
@ -875,10 +906,14 @@ tp_stack_class_t const s2_stack[1] =
}};
/** Basic setup for test cases */
void s2_setup_base(char const *hostname)
void s2_setup_base(char const *label, char const *hostname)
{
assert(s2 == NULL);
if (s2_start_stop > 1) {
printf("%s - setup %s test case\n", s2_tester, label ? label : "next");
}
su_init();
s2 = su_home_new(sizeof *s2);
@ -897,6 +932,7 @@ void s2_setup_base(char const *hostname)
s2->hostname = hostname;
s2->tid = (unsigned long)time(NULL) * 510633671UL;
}
SOFIAPUBVAR su_log_t nua_log[];
@ -1489,22 +1525,43 @@ void s2_dns_domain(char const *domain, int use_naptr,
va_end(va0);
}
static char const *s2_teardown_label = NULL;
void
s2_teardown_started(char const *label)
{
if (!s2_teardown_label) {
s2_teardown_label = label;
if (s2_start_stop > 1) {
printf("%s - tearing down %s test case\n", s2_tester, label);
}
}
}
void
s2_teardown(void)
{
s2 = NULL;
su_deinit();
if (s2_start_stop > 1) {
printf("%s - %s test case tore down\n", s2_tester,
s2_teardown_label ? s2_teardown_label : "previous");
}
s2_teardown_label = NULL;
}
/* ====================================================================== */
#include <sofia-sip/sresolv.h>
nua_t *s2_nua_setup(tag_type_t tag, tag_value_t value, ...)
nua_t *s2_nua_setup(char const *label,
tag_type_t tag, tag_value_t value, ...)
{
ta_list ta;
s2_setup_base(NULL);
s2_setup_base(label, NULL);
s2_setup_dns();
s2_setup_logs(0);
@ -1618,4 +1675,3 @@ void s2_register_teardown(void)
s2->registration->nh = NULL;
}
}

View File

@ -102,6 +102,8 @@ struct dialog
msg_t *invite; /* latest invite sent */
};
extern char const *s2_tester;
extern int s2_start_stop;
extern struct tester *s2;
extern tp_stack_class_t const s2_stack[1];
@ -144,8 +146,12 @@ struct message *s2_next_request(void);
struct message *s2_wait_for_request(sip_method_t method, char const *name);
int s2_check_request(sip_method_t method, char const *name);
int s2_check_substate(struct event *e, enum nua_substate state);
#define SIP_METHOD_UNKNOWN sip_method_unknown, NULL
void s2_save_uas_dialog(struct dialog *d, sip_t *sip);
struct message *s2_respond_to(struct message *m, struct dialog *d,
int status, char const *phrase,
tag_type_t tag, tag_value_t value, ...);
@ -161,15 +167,16 @@ int s2_save_register(struct message *m);
void s2_flush_all(void);
void s2_setup_base(char const *hostname);
void s2_setup_base(char const *label, char const *hostname);
void s2_setup_logs(int level);
void s2_setup_tport(char const * const *protocols,
tag_type_t tag, tag_value_t value, ...);
void s2_teardown(void);
nua_t *s2_nua_setup(tag_type_t tag, tag_value_t value, ...);
void s2_nua_teardown(void);
nua_t *s2_nua_setup(char const *label, tag_type_t tag, tag_value_t value, ...);
void s2_teardown_started(char const *label);
void s2_nua_teardown(void);
void s2_register_setup(void);
void s2_register_teardown(void);