2009-03-10 19:55:00 +00:00
|
|
|
/*
|
|
|
|
* This file is part of the Sofia-SIP package
|
|
|
|
*
|
|
|
|
* Copyright (C) 2008 Nokia Corporation.
|
|
|
|
*
|
|
|
|
* Contact: Pekka Pessi <pekka.pessi@nokia.com>
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2.1 of
|
|
|
|
* the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
|
|
|
* 02110-1301 USA
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**@CFILE check_nta.c
|
|
|
|
* @brief 2nd test Suite for Sofia SIP Transaction Engine
|
|
|
|
*
|
|
|
|
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
|
|
|
|
*
|
|
|
|
* @date Created: Wed Apr 30 12:48:27 EEST 2008 ppessi
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#undef NDEBUG
|
|
|
|
|
|
|
|
#include "check_nta.h"
|
|
|
|
|
|
|
|
#include "s2dns.h"
|
|
|
|
#include "s2base.h"
|
|
|
|
#include "s2sip.h"
|
|
|
|
|
|
|
|
#include <sofia-sip/sip_header.h>
|
|
|
|
#include <sofia-sip/sip_status.h>
|
|
|
|
#include <sofia-sip/msg_addr.h>
|
|
|
|
#include <sofia-sip/su_log.h>
|
|
|
|
#include <sofia-sip/su_tagarg.h>
|
|
|
|
#include <sofia-sip/su_alloc.h>
|
|
|
|
#include <sofia-sip/su_string.h>
|
|
|
|
#include <sofia-sip/sresolv.h>
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <time.h>
|
|
|
|
|
|
|
|
/* -- Globals -------------------------------------------------------------- */
|
|
|
|
|
|
|
|
struct s2nta *s2;
|
|
|
|
|
|
|
|
/* -- main ----------------------------------------------------------------- */
|
|
|
|
|
|
|
|
static void usage(int exitcode)
|
|
|
|
{
|
|
|
|
fprintf(exitcode ? stderr : stdout,
|
|
|
|
"usage: %s [--xml=logfile] case,...\n", s2_tester);
|
|
|
|
exit(exitcode);
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
int i, failed = 0, selected = 0;
|
|
|
|
char const *xml = NULL;
|
|
|
|
Suite *suite;
|
|
|
|
SRunner *runner;
|
|
|
|
|
|
|
|
s2_tester = "check_nta";
|
|
|
|
s2_suite("NTA");
|
|
|
|
|
|
|
|
if (getenv("CHECK_NTA_VERBOSE"))
|
|
|
|
s2_start_stop = strtoul(getenv("CHECK_NTA_VERBOSE"), NULL, 10);
|
|
|
|
|
|
|
|
for (i = 1; argv[i]; i++) {
|
|
|
|
if (su_strnmatch(argv[i], "--xml=", strlen("--xml="))) {
|
|
|
|
xml = argv[i] + strlen("--xml=");
|
|
|
|
}
|
|
|
|
else if (su_strmatch(argv[i], "--xml")) {
|
|
|
|
if (!(xml = argv[++i]))
|
|
|
|
usage(2);
|
|
|
|
}
|
|
|
|
else if (su_strmatch(argv[i], "-v")) {
|
|
|
|
s2_start_stop = 1;
|
|
|
|
}
|
|
|
|
else if (su_strmatch(argv[i], "-?") ||
|
|
|
|
su_strmatch(argv[i], "-h") ||
|
|
|
|
su_strmatch(argv[i], "--help"))
|
|
|
|
usage(0);
|
|
|
|
else {
|
|
|
|
s2_select_tests(argv[i]);
|
|
|
|
selected = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!selected)
|
|
|
|
s2_select_tests(getenv("CHECK_NTA_CASES"));
|
|
|
|
|
|
|
|
suite = suite_create("Unit tests for nta (Sofia-SIP Transaction Engine)");
|
|
|
|
|
|
|
|
suite_add_tcase(suite, check_nta_api_1_0());
|
|
|
|
suite_add_tcase(suite, check_nta_client_2_0());
|
|
|
|
suite_add_tcase(suite, check_nta_client_2_1());
|
2009-06-23 19:49:44 +00:00
|
|
|
suite_add_tcase(suite, check_nta_client_2_2());
|
2009-03-10 19:55:00 +00:00
|
|
|
|
|
|
|
runner = srunner_create(suite);
|
|
|
|
|
|
|
|
if (xml)
|
|
|
|
srunner_set_xml(runner, argv[1]);
|
|
|
|
|
|
|
|
srunner_run_all(runner, CK_ENV);
|
|
|
|
failed = srunner_ntests_failed(runner);
|
|
|
|
srunner_free(runner);
|
|
|
|
|
|
|
|
exit(failed ? EXIT_FAILURE : EXIT_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* -- NTA callbacks -------------------------------------------------------- */
|
|
|
|
|
|
|
|
struct event *
|
|
|
|
s2_nta_remove_event(struct event *e)
|
|
|
|
{
|
|
|
|
if ((*e->prev = e->next))
|
|
|
|
e->next->prev = e->prev;
|
|
|
|
e->prev = NULL, e->next = NULL;
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
s2_nta_free_event(struct event *e)
|
|
|
|
{
|
|
|
|
if (e) {
|
|
|
|
if (e->prev) {
|
|
|
|
if ((*e->prev = e->next))
|
|
|
|
e->next->prev = e->prev;
|
|
|
|
}
|
|
|
|
if (e->msg)
|
|
|
|
msg_destroy(e->msg);
|
|
|
|
free(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
s2_nta_flush_events(void)
|
|
|
|
{
|
|
|
|
while (s2->events) {
|
|
|
|
s2_nta_free_event(s2->events);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct event *
|
|
|
|
s2_nta_next_event(void)
|
|
|
|
{
|
|
|
|
for (;;) {
|
|
|
|
if (s2->events)
|
|
|
|
return s2_nta_remove_event(s2->events);
|
|
|
|
su_root_step(s2->root, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct event *
|
|
|
|
s2_nta_vwait_for(enum wait_for wait_for0,
|
|
|
|
void const *value0,
|
|
|
|
va_list va0)
|
|
|
|
{
|
|
|
|
struct event *e;
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
for (e = s2->events; e; e = e->next) {
|
|
|
|
va_list va;
|
|
|
|
enum wait_for wait_for;
|
|
|
|
void const *value;
|
|
|
|
|
|
|
|
va_copy(va, va0);
|
|
|
|
|
|
|
|
for (wait_for = wait_for0, value = value0;
|
|
|
|
wait_for;
|
|
|
|
wait_for = va_arg(va, enum wait_for),
|
|
|
|
value = va_arg(va, void const *)) {
|
|
|
|
switch (wait_for) {
|
|
|
|
case wait_for_amagic:
|
|
|
|
if (value != e->amagic)
|
|
|
|
goto next;
|
|
|
|
break;
|
|
|
|
case wait_for_omagic:
|
|
|
|
if (value != e->omagic)
|
|
|
|
goto next;
|
|
|
|
break;
|
|
|
|
case wait_for_orq:
|
|
|
|
if (value != e->orq)
|
|
|
|
goto next;
|
|
|
|
break;
|
|
|
|
case wait_for_lmagic:
|
|
|
|
if (value != e->lmagic)
|
|
|
|
goto next;
|
|
|
|
break;
|
|
|
|
case wait_for_leg:
|
|
|
|
if (value != e->leg)
|
|
|
|
goto next;
|
|
|
|
break;
|
|
|
|
case wait_for_imagic:
|
|
|
|
if (value != e->imagic)
|
|
|
|
goto next;
|
|
|
|
break;
|
|
|
|
case wait_for_irq:
|
|
|
|
if (value != e->irq)
|
|
|
|
goto next;
|
|
|
|
break;
|
|
|
|
case wait_for_method:
|
|
|
|
if ((sip_method_t)value != e->method)
|
|
|
|
goto next;
|
|
|
|
break;
|
|
|
|
case wait_for_method_name:
|
|
|
|
if (!su_strmatch(value, e->method_name))
|
|
|
|
goto next;
|
|
|
|
break;
|
|
|
|
case wait_for_status:
|
|
|
|
if ((int)value != e->status)
|
|
|
|
goto next;
|
|
|
|
break;
|
|
|
|
case wait_for_phrase:
|
|
|
|
if (!su_casematch(value, e->phrase))
|
|
|
|
goto next;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
next:
|
|
|
|
va_end(va);
|
|
|
|
|
|
|
|
if (!wait_for)
|
|
|
|
return s2_nta_remove_event(e);
|
|
|
|
}
|
|
|
|
su_root_step(s2->root, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct event *
|
|
|
|
s2_nta_wait_for(enum wait_for wait_for,
|
|
|
|
void const *value,
|
|
|
|
...)
|
|
|
|
{
|
|
|
|
struct event *e;
|
|
|
|
va_list va;
|
|
|
|
|
|
|
|
va_start(va, value);
|
|
|
|
e = s2_nta_vwait_for(wait_for, value, va);
|
|
|
|
va_end(va);
|
|
|
|
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
s2_nta_check_request(enum wait_for wait_for,
|
|
|
|
void const *value,
|
|
|
|
...)
|
|
|
|
{
|
|
|
|
struct event *e;
|
|
|
|
va_list va;
|
|
|
|
|
|
|
|
va_start(va, value);
|
|
|
|
e = s2_nta_vwait_for(wait_for, value, va);
|
|
|
|
va_end(va);
|
|
|
|
|
|
|
|
s2_nta_free_event(e);
|
|
|
|
return e != NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
s2_nta_msg_callback(nta_agent_magic_t *magic,
|
|
|
|
nta_agent_t *nta,
|
|
|
|
msg_t *msg,
|
|
|
|
sip_t *sip)
|
|
|
|
{
|
|
|
|
struct event *e, **prev;
|
|
|
|
|
|
|
|
e = calloc(1, sizeof *e);
|
|
|
|
|
|
|
|
e->amagic = magic;
|
|
|
|
e->msg = msg;
|
|
|
|
e->sip = sip;
|
|
|
|
|
|
|
|
if (sip->sip_request) {
|
|
|
|
e->method = sip->sip_request->rq_method;
|
|
|
|
e->method_name = sip->sip_request->rq_method_name;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
e->status = sip->sip_status->st_status;
|
|
|
|
e->phrase = sip->sip_status->st_phrase;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (prev = &s2->events; *prev; prev = &(*prev)->next)
|
|
|
|
;
|
|
|
|
*prev = e, e->prev = prev;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
s2_nta_orq_callback(nta_outgoing_magic_t *magic,
|
|
|
|
nta_outgoing_t *orq,
|
|
|
|
sip_t const *sip)
|
|
|
|
{
|
|
|
|
struct event *e, **prev;
|
|
|
|
|
|
|
|
e = calloc(1, sizeof *e);
|
|
|
|
|
|
|
|
e->omagic = magic;
|
|
|
|
e->orq = orq;
|
|
|
|
e->msg = nta_outgoing_getresponse(orq);
|
|
|
|
e->sip = sip_object(e->msg);
|
|
|
|
|
|
|
|
e->status = nta_outgoing_status(orq);
|
|
|
|
e->phrase = sip ? sip->sip_status->st_phrase : "";
|
|
|
|
|
|
|
|
for (prev = &s2->events; *prev; prev = &(*prev)->next)
|
|
|
|
;
|
|
|
|
*prev = e, e->prev = prev;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
s2_nta_leg_callback(nta_leg_magic_t *magic,
|
|
|
|
nta_leg_t *leg,
|
|
|
|
nta_incoming_t *irq,
|
|
|
|
sip_t const *sip)
|
|
|
|
{
|
|
|
|
struct event *e, **prev;
|
|
|
|
|
|
|
|
e = calloc(1, sizeof *e);
|
|
|
|
|
|
|
|
e->lmagic = magic;
|
|
|
|
e->leg = leg;
|
|
|
|
e->irq = irq;
|
|
|
|
|
|
|
|
e->msg = nta_incoming_getrequest(irq);
|
|
|
|
e->sip = sip_object(e->msg);
|
|
|
|
|
|
|
|
e->method = e->sip->sip_request->rq_method;
|
|
|
|
e->method_name = e->sip->sip_request->rq_method_name;
|
|
|
|
|
|
|
|
for (prev = &s2->events; *prev; prev = &(*prev)->next)
|
|
|
|
;
|
|
|
|
*prev = e, e->prev = prev;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
s2_nta_irq_callback(nta_incoming_magic_t *magic,
|
|
|
|
nta_incoming_t *irq,
|
|
|
|
sip_t const *sip)
|
|
|
|
{
|
|
|
|
struct event *e, **prev;
|
|
|
|
|
|
|
|
e = calloc(1, sizeof *e);
|
|
|
|
|
|
|
|
e->imagic = magic;
|
|
|
|
e->irq = irq;
|
|
|
|
e->msg = nta_incoming_getrequest_ackcancel(irq);
|
|
|
|
e->sip = sip_object(e->msg);
|
|
|
|
|
|
|
|
e->method = e->sip ? e->sip->sip_request->rq_method : 0;
|
|
|
|
e->method_name = e->sip ? e->sip->sip_request->rq_method_name : NULL;
|
|
|
|
|
|
|
|
for (prev = &s2->events; *prev; prev = &(*prev)->next)
|
|
|
|
;
|
|
|
|
*prev = e, e->prev = prev;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ====================================================================== */
|
|
|
|
|
|
|
|
SOFIAPUBVAR su_log_t nta_log[];
|
|
|
|
SOFIAPUBVAR su_log_t sresolv_log[];
|
|
|
|
SOFIAPUBVAR su_log_t tport_log[];
|
|
|
|
SOFIAPUBVAR su_log_t su_log_default[];
|
|
|
|
|
|
|
|
void
|
|
|
|
s2_nta_setup_logs(int level)
|
|
|
|
{
|
|
|
|
su_log_soft_set_level(su_log_default, level);
|
|
|
|
su_log_soft_set_level(tport_log, level);
|
|
|
|
su_log_soft_set_level(nta_log, level);
|
|
|
|
su_log_soft_set_level(sresolv_log, level);
|
|
|
|
|
|
|
|
if (getenv("TPORT_LOG") == NULL && getenv("S2_TPORT_LOG") == NULL) {
|
|
|
|
if (s2sip)
|
|
|
|
tport_set_params(s2sip->master, TPTAG_LOG(level > 1), TAG_END());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
s2_nta_setup(char const *label,
|
|
|
|
char const * const *transports,
|
|
|
|
tag_type_t tag, tag_value_t value, ...)
|
|
|
|
{
|
|
|
|
ta_list ta;
|
|
|
|
|
|
|
|
s2_setup(label);
|
|
|
|
s2_nta_setup_logs(0);
|
|
|
|
s2_dns_setup(s2base->root);
|
|
|
|
ta_start(ta, tag, value);
|
|
|
|
s2_sip_setup("example.org", transports, ta_tags(ta));
|
|
|
|
ta_end(ta);
|
|
|
|
assert(s2sip->contact);
|
|
|
|
|
|
|
|
s2_dns_domain("example.org", 1,
|
|
|
|
"s2", 1, s2sip->udp.contact ? s2sip->udp.contact->m_url : NULL,
|
|
|
|
"s2", 1, s2sip->tcp.contact ? s2sip->tcp.contact->m_url : NULL,
|
|
|
|
"s2", 1, s2sip->tls.contact ? s2sip->tls.contact->m_url : NULL,
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
nta_agent_t *
|
|
|
|
s2_nta_agent_setup(url_string_t const *bind_url,
|
|
|
|
nta_message_f *callback,
|
|
|
|
nta_agent_magic_t *magic,
|
|
|
|
tag_type_t tag, tag_value_t value, ...)
|
|
|
|
{
|
|
|
|
ta_list ta;
|
|
|
|
|
|
|
|
assert(s2base);
|
|
|
|
|
|
|
|
s2 = su_home_new(sizeof *s2); assert(s2);
|
|
|
|
s2->root = su_root_clone(s2base->root, s2); assert(s2->root);
|
|
|
|
fail_unless(s2->root != NULL);
|
|
|
|
|
|
|
|
ta_start(ta, tag, value);
|
|
|
|
s2->nta =
|
|
|
|
nta_agent_create(s2->root,
|
|
|
|
bind_url ? bind_url : URL_STRING_MAKE("sip:*:*"),
|
|
|
|
callback,
|
|
|
|
magic,
|
|
|
|
/* Use internal DNS server */
|
|
|
|
/* Force sresolv to use localhost and s2dns as DNS server */
|
|
|
|
#if HAVE_WIN32
|
|
|
|
SRESTAG_RESOLV_CONF("NUL"),
|
|
|
|
#else
|
|
|
|
SRESTAG_RESOLV_CONF("/dev/null"),
|
|
|
|
#endif
|
|
|
|
ta_tags(ta));
|
|
|
|
ta_end(ta);
|
|
|
|
|
|
|
|
assert(s2->nta);
|
|
|
|
|
|
|
|
if (callback == NULL)
|
|
|
|
s2->default_leg = nta_leg_tcreate(s2->nta, s2_nta_leg_callback, NULL,
|
|
|
|
NTATAG_NO_DIALOG(1),
|
|
|
|
TAG_END());
|
|
|
|
|
|
|
|
return s2->nta;
|
|
|
|
}
|
|
|
|
|
|
|
|
void s2_nta_teardown(void)
|
|
|
|
{
|
|
|
|
if (s2) {
|
|
|
|
s2_nta_flush_events();
|
|
|
|
|
|
|
|
if (s2->default_leg)
|
|
|
|
nta_leg_destroy(s2->default_leg), s2->default_leg = NULL;
|
|
|
|
nta_agent_destroy(s2->nta), s2->nta = NULL;
|
|
|
|
su_root_destroy(s2->root), s2->root = NULL;
|
|
|
|
su_home_unref(s2->home);
|
|
|
|
s2 = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
s2_dns_teardown();
|
|
|
|
s2_sip_teardown();
|
|
|
|
s2_teardown();
|
|
|
|
}
|