/* * This file is part of the Sofia-SIP package * * Copyright (C) 2005 Nokia Corporation. * * Contact: Pekka Pessi * * 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 * */ /**@internal * @CFILE test_nta.c * * Test functions for NTA. * * @author Pekka Pessi * * @date Created: Tue Aug 21 15:18:26 2001 ppessi */ #include "config.h" typedef struct agent_t agent_t; typedef struct client_t client_t; #define SU_ROOT_MAGIC_T agent_t #include #include #define NTA_AGENT_MAGIC_T agent_t #define NTA_LEG_MAGIC_T agent_t #define NTA_OUTGOING_MAGIC_T client_t #define NTA_OUTGOING_MAGIC_T0 agent_t #define NTA_INCOMING_MAGIC_T agent_t #define NTA_RELIABLE_MAGIC_T agent_t #include "sofia-sip/nta.h" #include "nta_internal.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if HAVE_OPEN_C #include #endif SOFIAPUBVAR su_log_t nta_log[]; SOFIAPUBVAR su_log_t tport_log[]; int tstflags = 0; #define TSTFLAGS tstflags #include #if HAVE_FUNC #elif HAVE_FUNCTION #define __func__ __FUNCTION__ #else #define __func__ name #endif #define NONE ((void *)-1) int expensive_checks; #define EXPENSIVE_CHECKS (expensive_checks) struct sigcomp_compartment; char const name[] = "test_nta"; typedef struct invite_client_t invite_client_t; typedef int client_check_f(client_t *, nta_outgoing_t *, sip_t const *); typedef int client_deinit_f(client_t *); struct client_t { agent_t *c_ag; char const *c_name; client_check_f * c_check; client_check_f * const * c_checks; client_deinit_f * c_deinit; void *c_extra; nta_outgoing_t *c_orq; int c_status; int c_final; int c_errors; }; struct agent_t { su_home_t ag_home[1]; int ag_flags; su_root_t *ag_root; msg_mclass_t *ag_mclass; nta_agent_t *ag_agent; url_string_t *ag_obp; /**< Outbound proxy. */ nta_leg_t *ag_server_leg; /**< Leg for sip:%@% */ nta_leg_t *ag_default_leg; /**< Leg for rest */ unsigned ag_drop; nta_outgoing_t *ag_orq; unsigned ag_running :1, ag_canceled:1, ag_acked:1, :0; char const *ag_comp; struct sigcomp_compartment *ag_client_compartment; /* Server side */ int ag_response; /**< What we answer by default */ nta_incoming_t *ag_irq; struct sigcomp_compartment *ag_server_compartment; char const *ag_m; sip_contact_t const *ag_contact; sip_from_t *ag_alice; sip_to_t *ag_bob; sip_contact_t *ag_m_alice; sip_contact_t *ag_m_bob; sip_contact_t *ag_aliases; nta_leg_t *ag_alice_leg; nta_leg_t *ag_bob_leg; msg_t *ag_request; nta_leg_t *ag_expect_leg; nta_leg_t *ag_latest_leg; nta_leg_t *ag_call_leg; nta_leg_t *ag_tag_remote; /**< If this is set, outgoing_callback() * tags it with the tag from remote. */ nta_reliable_t *ag_reliable; sip_via_t *ag_in_via; /**< Incoming via */ sip_content_type_t *ag_content_type; sip_payload_t *ag_payload; msg_t *ag_probe_msg; /* Dummy servers */ char const *ag_sink_port; su_socket_t ag_sink_socket, ag_down_socket; }; static int test_init(agent_t *ag, char const *resolv_conf); static int test_deinit(agent_t *ag); static int test_bad_messages(agent_t *ag); static int test_routing(agent_t *ag); static int test_tports(agent_t *ag); static int test_resolv(agent_t *ag, char const *resolv_conf); static int test_dialog(agent_t *ag); static int test_call(agent_t *ag); static int test_prack(agent_t *ag); static int test_fix_467(agent_t *ag); static int test_for_ack(agent_t *ag, nta_incoming_t *irq, sip_t const *sip); static int test_for_ack_or_timeout(agent_t *ag, nta_incoming_t *irq, sip_t const *sip); int agent_callback(agent_t *ag, nta_agent_t *nta, msg_t *msg, sip_t *sip) { if (tstflags & tst_verbatim) { if (sip->sip_request) { printf("%s: %s: %s " URL_PRINT_FORMAT " %s\n", name, __func__, sip->sip_request->rq_method_name, URL_PRINT_ARGS(sip->sip_request->rq_url), sip->sip_request->rq_version); } else { printf("%s: %s: %s %03d %s\n", name, __func__, sip->sip_status->st_version, sip->sip_status->st_status, sip->sip_status->st_phrase); } } msg_destroy(msg); return 0; } static void leg_match(agent_t *ag, nta_leg_t *leg, int always, char const *func) { char const *match = "unknown leg"; if (!always && (tstflags & tst_verbatim) != tst_verbatim) return; if (leg == ag->ag_default_leg) match = "ag_default_leg"; else if (leg == ag->ag_server_leg) match = "ag_server_leg"; else if (leg == ag->ag_alice_leg) match = "ag_alice_leg"; else if (leg == ag->ag_bob_leg) match = "ag_bob_leg"; printf("%s: %s: %smatched with %s\n", name, func, always ? "mis" : "", match); } static void leg_zap(agent_t *ag, nta_leg_t *leg) { if (leg == ag->ag_default_leg) ag->ag_default_leg = NULL; else if (leg == ag->ag_server_leg) ag->ag_server_leg = NULL; else if (leg == ag->ag_alice_leg) ag->ag_alice_leg = NULL; else if (leg == ag->ag_bob_leg) ag->ag_bob_leg = NULL; else printf("%s:%u: %s: did not exist\n", __FILE__, __LINE__, __func__); nta_leg_destroy(leg); } int leg_callback_200(agent_t *ag, nta_leg_t *leg, nta_incoming_t *irq, sip_t const *sip) { if (tstflags & tst_verbatim) { printf("%s: %s: %s " URL_PRINT_FORMAT " %s\n", name, __func__, sip->sip_request->rq_method_name, URL_PRINT_ARGS(sip->sip_request->rq_url), sip->sip_request->rq_version); } if (!sip->sip_content_length || !sip->sip_via || !sip->sip_from || !sip->sip_from->a_tag) return 500; if (ag->ag_in_via == NULL) ag->ag_in_via = sip_via_dup(ag->ag_home, sip->sip_via); if (ag->ag_request == NULL) ag->ag_request = nta_incoming_getrequest(irq); ag->ag_latest_leg = leg; if (ag->ag_expect_leg && leg != ag->ag_expect_leg) { leg_match(ag, leg, 1, __func__); return 500; } leg_match(ag, leg, 0, __func__); if (sip->sip_request->rq_method == sip_method_bye) { leg_zap(ag, leg); } return 200; } int leg_callback_500(agent_t *ag, nta_leg_t *leg, nta_incoming_t *irq, sip_t const *sip) { if (tstflags & tst_verbatim) { printf("%s: %s: %s " URL_PRINT_FORMAT " %s\n", name, __func__, sip->sip_request->rq_method_name, URL_PRINT_ARGS(sip->sip_request->rq_url), sip->sip_request->rq_version); } return 500; } int new_leg_callback_200(agent_t *ag, nta_leg_t *leg, nta_incoming_t *irq, sip_t const *sip) { if (tstflags & tst_verbatim) { printf("%s: %s: %s " URL_PRINT_FORMAT " %s\n", name, __func__, sip->sip_request->rq_method_name, URL_PRINT_ARGS(sip->sip_request->rq_url), sip->sip_request->rq_version); } if (!sip->sip_content_length || !sip->sip_via || !sip->sip_from || !sip->sip_from->a_tag) return 500; ag->ag_latest_leg = leg; if (ag->ag_expect_leg && leg != ag->ag_expect_leg) { leg_match(ag, leg, 1, __func__); return 500; } leg_match(ag, leg, 0, __func__); ag->ag_bob_leg = nta_leg_tcreate(ag->ag_agent, leg_callback_200, ag, URLTAG_URL(sip->sip_request->rq_url), SIPTAG_CALL_ID(sip->sip_call_id), SIPTAG_FROM(sip->sip_to), SIPTAG_TO(sip->sip_from), TAG_END()); if (!ag->ag_bob_leg || !nta_leg_tag(ag->ag_bob_leg, NULL) || !nta_leg_get_tag(ag->ag_bob_leg) || !nta_incoming_tag(irq, nta_leg_get_tag(ag->ag_bob_leg))) return 500; return 200; } static client_check_f * const default_checks[]; int outgoing_callback(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip) { agent_t *ag = ctx->c_ag; int status = nta_outgoing_status(orq); client_check_f * const *checks; if (tstflags & tst_verbatim) { if (sip) printf("%s: %s: response %s %03d %s\n", name, ctx->c_name, sip->sip_status->st_version, sip->sip_status->st_status, sip->sip_status->st_phrase); else printf("%s: %s: callback %03d\n", name, ctx->c_name, status); } if (status >= 200 && ag->ag_comp) { /* XXX */ nta_compartment_decref(&ag->ag_client_compartment); ag->ag_client_compartment = nta_outgoing_compartment(ctx->c_orq); } if (status > ctx->c_status) ctx->c_status = status; if (status >= 200) ctx->c_final = 1; if (ctx->c_check && ctx->c_check(ctx, orq, sip)) ctx->c_errors++; checks = ctx->c_checks; for (checks = checks ? checks : default_checks; *checks; checks++) if ((*checks)(ctx, ctx->c_orq, sip)) ctx->c_errors++; return 0; } /** Deinit client. Return nonzero if client checks failed. */ static int client_deinit(client_t *c) { int errors = c->c_errors; if (c->c_deinit && c->c_deinit(c)) errors++; if (c->c_orq) nta_outgoing_destroy(c->c_orq), c->c_orq = NULL; c->c_errors = 0; c->c_status = 0; return errors; } static void nta_test_run(agent_t *ag) { for (ag->ag_running = 1; ag->ag_running;) { if (tstflags & tst_verbatim) { fputs(".", stdout); fflush(stdout); } su_root_step(ag->ag_root, 500L); } } /** Run client test. Return nonzero if client checks failed. */ static int client_run_with(client_t *c, int expected, void (*runner)(client_t *c)) { int resulting; TEST_1(c->c_orq != NULL); runner(c); resulting = c->c_status; if (client_deinit(c)) return 1; if (expected) TEST(resulting, expected); return 0; } static void until_final_received(client_t *c) { for (c->c_final = 0; !c->c_final; ) { if (tstflags & tst_verbatim) { fputs(".", stdout); fflush(stdout); } su_root_step(c->c_ag->ag_root, 500L); } } static int client_run(client_t *c, int expected) { return client_run_with(c, expected, until_final_received); } static void until_server_acked(client_t *c) { agent_t *ag = c->c_ag; for (ag->ag_acked = 0; !ag->ag_acked;) { if (tstflags & tst_verbatim) { fputs(".", stdout); fflush(stdout); } su_root_step(ag->ag_root, 500L); } } static int client_run_until_acked(client_t *c, int expected) { return client_run_with(c, expected, until_server_acked); } void until_server_canceled(client_t *c) { agent_t *ag = c->c_ag; for (ag->ag_canceled = 0; !ag->ag_canceled;) { if (tstflags & tst_verbatim) { fputs(".", stdout); fflush(stdout); } su_root_step(ag->ag_root, 500L); } } static int client_run_until_canceled(client_t *c, int expected) { return client_run_with(c, expected, until_server_canceled); } #include int test_init(agent_t *ag, char const *resolv_conf) { char const *contact = "sip:*:*;comp=sigcomp"; su_sockaddr_t su; socklen_t sulen, sulen0; su_socket_t s; int af, err = -1; BEGIN(); ag->ag_root = su_root_create(ag); TEST_1(ag->ag_root); ag->ag_mclass = msg_mclass_clone(sip_default_mclass(), 0, 0); TEST_1(ag->ag_mclass); #if SU_HAVE_IN6 if (str0cmp(getenv("ipv6"), "true") == 0) { contact = "sip:[::]:*;comp=sigcomp"; af = AF_INET6, sulen0 = sizeof (struct sockaddr_in6); } else { af = AF_INET, sulen0 = sizeof (struct sockaddr_in); contact = "sip:0.0.0.0:*;comp=sigcomp"; } #else af = AF_INET, sulen0 = sizeof (struct sockaddr_in); contact = "sip:0.0.0.0:*;comp=sigcomp"; #endif if (ag->ag_m) contact = ag->ag_m; else if (getenv("SIPCONTACT")) contact = getenv("SIPCONTACT"); /* Sink server */ s = su_socket(af, SOCK_DGRAM, 0); TEST_1(s != INVALID_SOCKET); memset(&su, 0, sulen = sulen0); su.su_family = af; if (getenv("sink")) { su.su_port = htons(atoi(getenv("sink"))); } TEST_1(bind(s, &su.su_sa, sulen) < 0 ? (perror("bind"), 0) : 1); TEST_1(getsockname(s, &su.su_sa, &sulen) == 0); ag->ag_sink_port = su_sprintf(ag->ag_home, "%u", ntohs(su.su_sin.sin_port)); ag->ag_sink_socket = s; /* Down server */ s = su_socket(af, SOCK_STREAM, 0); TEST_1(s != INVALID_SOCKET); memset(&su, 0, sulen = sulen0); su.su_family = af; if (getenv("down")) { su.su_port = htons(atoi(getenv("down"))); } TEST_1(bind(s, &su.su_sa, sulen) < 0 ? (perror("bind"), 0) : 1); ag->ag_down_socket = s; /* Create agent */ ag->ag_agent = nta_agent_create(ag->ag_root, (url_string_t *)contact, NULL, NULL, NTATAG_MCLASS(ag->ag_mclass), NTATAG_USE_TIMESTAMP(1), SRESTAG_RESOLV_CONF(resolv_conf), NTATAG_USE_NAPTR(0), NTATAG_USE_SRV(0), NTATAG_PRELOAD(2048), TAG_END()); TEST_1(ag->ag_agent); { /* Initialize our headers */ sip_from_t from[1]; sip_to_t to[1]; sip_contact_t m[1]; sip_from_init(from); sip_to_init(to); sip_contact_init(m); TEST_1(ag->ag_contact = nta_agent_contact(ag->ag_agent)); *m->m_url = *ag->ag_contact->m_url; m->m_url->url_user = "bob"; TEST_1(ag->ag_m_bob = sip_contact_dup(ag->ag_home, m)); to->a_display = "Bob"; *to->a_url = *ag->ag_contact->m_url; to->a_url->url_user = "bob"; to->a_url->url_port = NULL; TEST_1(ag->ag_bob = sip_to_dup(ag->ag_home, to)); *m->m_url = *ag->ag_contact->m_url; m->m_url->url_user = "alice"; TEST_1(ag->ag_m_alice = sip_contact_dup(ag->ag_home, m)); from->a_display = "Alice"; *from->a_url = *ag->ag_contact->m_url; from->a_url->url_user = "alice"; from->a_url->url_port = NULL; TEST_1(ag->ag_alice = sip_from_dup(ag->ag_home, from)); } { char const data[] = "v=0\r\n" "o=- 425432 423412 IN IP4 127.0.0.1\r\n" "s= \r\n" "c=IN IP4 127.0.0.1\r\n" "m=5004 audio 8 0\r\n"; ag->ag_content_type = sip_content_type_make(ag->ag_home, "application/sdp"); ag->ag_payload = sip_payload_make(ag->ag_home, data); } { sip_contact_t *m; ag->ag_aliases = sip_contact_make(ag->ag_home, "sip:127.0.0.1, sip:localhost, sip:[::1]"); TEST_1(ag->ag_aliases); TEST_1(ag->ag_aliases->m_next); TEST_1(ag->ag_aliases->m_next->m_next); TEST_P(ag->ag_aliases->m_next->m_next->m_next, NULL); for (m = ag->ag_aliases; m; m = m->m_next) m->m_url->url_port = ag->ag_contact->m_url->url_port; TEST_1(m = sip_contact_dup(ag->ag_home, ag->ag_contact)); m->m_next = ag->ag_aliases; ag->ag_aliases = m; err = nta_agent_set_params(ag->ag_agent, NTATAG_ALIASES(ag->ag_aliases), NTATAG_REL100(1), NTATAG_UA(1), NTATAG_USE_NAPTR(1), NTATAG_USE_SRV(1), NTATAG_MAX_FORWARDS(20), TAG_END()); TEST(err, 6); err = nta_agent_set_params(ag->ag_agent, NTATAG_ALIASES(ag->ag_aliases), NTATAG_DEFAULT_PROXY("sip:127.0.0.1"), TAG_END()); TEST(err, 2); err = nta_agent_set_params(ag->ag_agent, NTATAG_ALIASES(ag->ag_aliases), NTATAG_DEFAULT_PROXY(NULL), TAG_END()); TEST(err, 2); err = nta_agent_set_params(ag->ag_agent, NTATAG_DEFAULT_PROXY("tel:+35878008000"), TAG_END()); TEST(err, -1); } { url_t url[1]; /* Create the server leg */ *url = *ag->ag_aliases->m_url; url->url_user = "%"; ag->ag_server_leg = nta_leg_tcreate(ag->ag_agent, leg_callback_200, ag, NTATAG_NO_DIALOG(1), URLTAG_URL(url), TAG_END()); TEST_1(ag->ag_server_leg); } END(); } int test_reinit(agent_t *ag) { BEGIN(); /* Create a new default leg */ nta_leg_destroy(ag->ag_default_leg), ag->ag_default_leg = NULL; TEST_1(ag->ag_default_leg = nta_leg_tcreate(ag->ag_agent, leg_callback_200, ag, NTATAG_NO_DIALOG(1), TAG_END())); END(); } int test_deinit(agent_t *ag) { BEGIN(); if (ag->ag_request) msg_destroy(ag->ag_request), ag->ag_request = NULL; su_free(ag->ag_home, ag->ag_in_via), ag->ag_in_via = NULL; nta_leg_destroy(ag->ag_alice_leg); nta_leg_destroy(ag->ag_bob_leg); nta_leg_destroy(ag->ag_default_leg); nta_leg_destroy(ag->ag_server_leg); nta_agent_destroy(ag->ag_agent); su_root_destroy(ag->ag_root); su_free(ag->ag_home, (void *)ag->ag_sink_port), ag->ag_sink_port = NULL; free(ag->ag_mclass), ag->ag_mclass = NULL; END(); } static int readfile(FILE *f, void **contents) { /* Read in whole (binary!) file */ char *buffer = NULL; long size; size_t len; /* Read whole file in */ if (fseek(f, 0, SEEK_END) < 0 || (size = ftell(f)) < 0 || fseek(f, 0, SEEK_SET) < 0 || (long)(len = (size_t)size) != size) { fprintf(stderr, "%s: unable to determine file size (%s)\n", __func__, strerror(errno)); return -1; } if (!(buffer = malloc(len + 2)) || fread(buffer, 1, len, f) != len) { fprintf(stderr, "%s: unable to read file (%s)\n", __func__, strerror(errno)); if (buffer) free(buffer); return -1; } buffer[len] = '\0'; *contents = buffer; return (int)len; } #if HAVE_DIRENT_H #include #endif static int test_bad_messages(agent_t *ag) { BEGIN(); #if HAVE_DIRENT_H DIR *dir; struct dirent *d; char name[PATH_MAX + 1] = "../sip/tests/"; size_t offset; char const *host, *port; su_addrinfo_t *ai, hints[1]; su_socket_t s; su_sockaddr_t su[1]; socklen_t sulen; char via[64]; size_t vlen; int i; dir = opendir(name); if (dir == NULL && getenv("srcdir")) { strncpy(name, getenv("srcdir"), PATH_MAX); strncat(name, "/../sip/tests/", PATH_MAX); dir = opendir(name); } if (dir == NULL) { fprintf(stderr, "test_nta: cannot find sip torture messages\n"); fprintf(stderr, "test_nta: tried %s\n", name); } offset = strlen(name); TEST_1(ag->ag_default_leg = nta_leg_tcreate(ag->ag_agent, leg_callback_500, ag, NTATAG_NO_DIALOG(1), TAG_END())); host = ag->ag_contact->m_url->url_host; if (host_is_ip6_reference(host)) { host = strcpy(via, host + 1); via[strlen(via) - 1] = '\0'; } port = url_port(ag->ag_contact->m_url); memset(hints, 0, sizeof hints); hints->ai_socktype = SOCK_DGRAM; hints->ai_protocol = IPPROTO_UDP; TEST(su_getaddrinfo(host, port, hints, &ai), 0); TEST_1(ai); s = su_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); TEST_1(s != -1); memset(su, 0, sulen = ai->ai_addrlen); su->su_len = sizeof su; su->su_family = ai->ai_family; TEST_1(bind(s, &su->su_sa, sulen) == 0); TEST_1(getsockname(s, &su->su_sa, &sulen) == 0); sprintf(via, "v: SIP/2.0/UDP is.invalid:%u\r\n", ntohs(su->su_port)); vlen = strlen(via); for (d = dir ? readdir(dir) : NULL; d; d = readdir(dir)) { size_t len = strlen(d->d_name); FILE *f; int blen, n; void *buffer; char *r; if (len < strlen(".txt")) continue; if (strcmp(d->d_name + len - strlen(".txt"), ".txt")) continue; strncpy(name + offset, d->d_name, PATH_MAX - offset); TEST_1(f = fopen(name, "rb")); TEST_1((blen = readfile(f, &buffer)) > 0); fclose(f); r = buffer; if (strncmp(r, "JUNK ", 5) == 0) { TEST_SIZE(su_sendto(s, r, blen, 0, ai->ai_addr, ai->ai_addrlen), blen); } else if (strncmp(r, "INVITE ", 7) != 0) { su_iovec_t vec[3]; n = strcspn(r, "\r\n"); n += strspn(r + n, "\r\n"); vec[0].siv_base = r, vec[0].siv_len = n; vec[1].siv_base = via, vec[1].siv_len = vlen; vec[2].siv_base = r + n, vec[2].siv_len = blen - n; TEST_SIZE(su_vsend(s, vec, 3, 0, (void *)ai->ai_addr, ai->ai_addrlen), blen + vlen); } free(buffer); su_root_step(ag->ag_root, 1); } TEST_SIZE(su_sendto(s, "\r\n\r\n", 4, 0, (void *)ai->ai_addr, ai->ai_addrlen), 4); su_root_step(ag->ag_root, 1); TEST_SIZE(su_sendto(s, "", 0, 0, ai->ai_addr, ai->ai_addrlen), 0); su_close(s); for (i = 0; i < 20; i++) su_root_step(ag->ag_root, 1); nta_leg_destroy(ag->ag_default_leg), ag->ag_default_leg = NULL; if (dir) closedir(dir); #endif /* HAVE_DIRENT_H */ END(); } static unsigned char const code[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; #include sip_payload_t *test_payload(su_home_t *home, size_t size) { sip_payload_t *pl = sip_payload_create(home, NULL, (isize_t)size); if (pl) { size_t i; char *data = (char *)pl->pl_data; for (i = 0; i < size; i++) { if ((i & 63) != 63) data[i] = code[su_randint(0, 63)]; else data[i] = '\n'; } } return pl; } static int client_check_to_tag(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip) { if (sip) TEST_1(sip->sip_to && sip->sip_to->a_tag); return 0; } static int check_magic_branch(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip) { if (sip) { TEST_1(sip->sip_via); TEST_S(sip->sip_via->v_branch, "MagicalBranch"); } return 0; } static int check_via_with_sigcomp(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip) { if (sip && sip->sip_via) { TEST_S(sip->sip_via->v_comp, "sigcomp"); } return 0; } static int check_via_without_sigcomp(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip) { if (sip && sip->sip_via) { TEST_1(sip->sip_via->v_comp == NULL); } return 0; } static int check_via_with_tcp(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip) { if (sip && sip->sip_via) { TEST_S(sip->sip_via->v_protocol, "SIP/2.0/TCP"); } return 0; } static int check_via_with_sctp(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip) { if (sip && sip->sip_via) { TEST_S(sip->sip_via->v_protocol, "SIP/2.0/SCTP"); } return 0; } static int check_via_with_udp(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip) { if (sip && sip->sip_via) { TEST_S(sip->sip_via->v_protocol, "SIP/2.0/UDP"); } return 0; } static int save_and_check_tcp(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip) { if (ctx->c_status >= 200 && ctx->c_extra) { tport_t *tport = nta_outgoing_transport(orq); TEST_1(tport); *(tport_t **)ctx->c_extra = tport; } return check_via_with_tcp(ctx, orq, sip); } static client_check_f * const default_checks[] = { client_check_to_tag, NULL }; static client_check_f * const no_default_checks[] = { NULL }; /* Test transports */ int test_tports(agent_t *ag) { int udp = 0, tcp = 0, sctp = 0, tls = 0; sip_via_t const *v, *v_udp_only = NULL; char const *udp_comp = NULL; char const *tcp_comp = NULL; tport_t *tcp_tport = NULL; url_t url[1]; BEGIN(); *url = *ag->ag_contact->m_url; url->url_port = "*"; url->url_params = "transport=tcp"; url->url_params = "transport=udp"; TEST_1(nta_agent_add_tport(ag->ag_agent, (url_string_t *)url, TAG_END()) == 0); TEST_1(v = nta_agent_via(ag->ag_agent)); for (; v; v = v->v_next) { if (strcasecmp(v->v_protocol, sip_transport_udp) == 0) { if (udp) v_udp_only = v; udp = 1; if (udp_comp == NULL) udp_comp = v->v_comp; } else if (strcasecmp(v->v_protocol, sip_transport_tcp) == 0) { tcp = 1; if (tcp_comp == NULL) tcp_comp = v->v_comp; } else if (strcasecmp(v->v_protocol, sip_transport_sctp) == 0) { sctp = 1; } else if (strcasecmp(v->v_protocol, sip_transport_tls) == 0) { tls = 1; } } *url = *ag->ag_aliases->m_url; url->url_user = "bob"; if (udp_comp || tcp_comp) ag->ag_comp = "sigcomp"; { /* Test 0.1 * Send a message from default leg to default leg */ char const p_acid[] = "P-Access-Network-Info: IEEE-802.11g\n"; url_t url[1]; client_t ctx[1] = {{ ag, "Test 0.1", check_via_without_sigcomp }}; *url = *ag->ag_contact->m_url; url->url_params = NULL; ag->ag_expect_leg = ag->ag_default_leg; ctx->c_orq = nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, ag->ag_obp, SIP_METHOD_MESSAGE, (url_string_t *)url, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_FROM(ag->ag_alice), SIPTAG_TO(ag->ag_bob), SIPTAG_CONTACT(ag->ag_m_alice), SIPTAG_HEADER_STR(p_acid), TAG_END()); TEST_1(!client_run(ctx, 200)); TEST_P(ag->ag_latest_leg, ag->ag_default_leg); TEST_1(ag->ag_request); msg_destroy(ag->ag_request), ag->ag_request = NULL; nta_leg_bind(ag->ag_default_leg, leg_callback_200, ag); } { /* Test 0.1.2: test url_headers * * Send a message from default leg to default leg. */ url_t url[1]; sip_t *sip; client_t ctx[1] = {{ ag, "Test 0.1.2", check_via_without_sigcomp }}; *url = *ag->ag_contact->m_url; /* Test that method parameter is stripped and headers in query are used */ url->url_params = "method=MESSAGE;user=IP"; url->url_headers = "organization=United%20Testers"; ag->ag_expect_leg = ag->ag_default_leg; ctx->c_orq = nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, ag->ag_obp, SIP_METHOD_MESSAGE, (url_string_t *)url, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_FROM(ag->ag_alice), SIPTAG_TO(ag->ag_bob), SIPTAG_CONTACT(ag->ag_m_alice), TAG_END()); TEST_1(!client_run(ctx, 200)); TEST_P(ag->ag_latest_leg, ag->ag_default_leg); TEST_1(ag->ag_request); TEST_1(sip = sip_object(ag->ag_request)); TEST_1(sip->sip_organization); TEST_S(sip->sip_organization->g_string, "United Testers"); TEST_S(sip->sip_request->rq_url->url_params, "user=IP"); nta_leg_bind(ag->ag_default_leg, leg_callback_200, ag); } /* Test 0.1.3 * Send a message from Bob to Alice using SIGCOMP and TCP */ if (tcp_comp) { url_t url[1]; sip_payload_t *pl; size_t size = 1024; client_t ctx[1] = {{ ag, "Test 0.1.3", check_via_with_sigcomp }}; *url = *ag->ag_aliases->m_url; url->url_user = "alice"; if (url->url_params) url->url_params = su_sprintf(NULL, "%s;transport=tcp", url->url_params); else url->url_params = "transport=tcp"; TEST_1(pl = test_payload(ag->ag_home, size)); ag->ag_expect_leg = ag->ag_server_leg; ctx->c_orq = nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, ag->ag_obp, SIP_METHOD_MESSAGE, (url_string_t *)url, NTATAG_COMP("sigcomp"), SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_FROM(ag->ag_bob), SIPTAG_TO(ag->ag_alice), SIPTAG_CONTACT(ag->ag_m_bob), SIPTAG_PAYLOAD(pl), TAG_END()); su_free(ag->ag_home, pl); TEST_1(!client_run(ctx, 200)); TEST_1(ag->ag_client_compartment); nta_compartment_decref(&ag->ag_client_compartment); TEST_P(ag->ag_latest_leg, ag->ag_server_leg); } /* Test 0.2 * Send a message from Bob to Alice * This time specify a TCP URI, and include a large payload * of 512 kB */ if (tcp) { client_t ctx[1] = {{ ag, "Test 0.2", save_and_check_tcp, }}; url_t url[1]; sip_payload_t *pl; usize_t size = 512 * 1024; ctx->c_extra = &tcp_tport; *url = *ag->ag_aliases->m_url; url->url_user = "alice"; url->url_params = "transport=tcp"; TEST_1(pl = test_payload(ag->ag_home, size)); ag->ag_expect_leg = ag->ag_server_leg; ctx->c_orq = nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, NULL, SIP_METHOD_MESSAGE, (url_string_t *)url, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_FROM(ag->ag_bob), SIPTAG_TO(ag->ag_alice), SIPTAG_CONTACT(ag->ag_m_bob), SIPTAG_PAYLOAD(pl), NTATAG_DEFAULT_PROXY(ag->ag_obp), TAG_END()); su_free(ag->ag_home, pl); TEST_1(!client_run(ctx, 200)); TEST_1(tcp_tport); TEST_P(ag->ag_latest_leg, ag->ag_server_leg); } if (tcp_tport) { /* Test 0.2.1 - always use transport connection from NTATAG_TPORT() * * Test bug reported by geaaru * - NTATAG_TPORT() is not used if NTATAG_DEFAULT_PROXY() is given */ client_t ctx[1] = {{ ag, "Test 0.2.1", save_and_check_tcp }}; url_t url[1]; sip_payload_t *pl; tport_t *used_tport = NULL; ctx->c_extra = &used_tport; TEST(tport_shutdown(tcp_tport, 1), 0); /* Not going to send anymore */ TEST_1(pl = test_payload(ag->ag_home, 512)); ag->ag_expect_leg = ag->ag_server_leg; ctx->c_orq = nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, NULL, SIP_METHOD_MESSAGE, (url_string_t *)url, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_FROM(ag->ag_bob), SIPTAG_TO(ag->ag_alice), SIPTAG_CONTACT(ag->ag_m_bob), SIPTAG_PAYLOAD(pl), NTATAG_DEFAULT_PROXY(ag->ag_obp), NTATAG_TPORT(tcp_tport), TAG_END()); su_free(ag->ag_home, pl); TEST_1(!client_run(ctx, 503)); TEST_P(ag->ag_latest_leg, ag->ag_server_leg); TEST_1(used_tport == tcp_tport); tport_unref(tcp_tport), tcp_tport = NULL; if (v_udp_only) /* Prepare for next test */ TEST_1(tcp_tport = tport_ref(tport_parent(used_tport))); tport_unref(used_tport); } if (tcp_tport) { /* test 0.2.2 - select transport protocol using NTATAG_TPORT() * * Use primary NTATAG_TPORT() to select transport */ client_t ctx[1] = {{ ag, "Test 0.2.2", save_and_check_tcp }}; url_t url[1]; sip_payload_t *pl; tport_t *used_tport = NULL; ctx->c_extra = &used_tport; TEST_1(tport_is_primary(tcp_tport)); TEST_1(pl = test_payload(ag->ag_home, 512)); *url = *ag->ag_aliases->m_url; url->url_user = "alice"; url->url_host = v_udp_only->v_host; url->url_port = v_udp_only->v_port; url->url_params = NULL; /* No sigcomp */ ag->ag_expect_leg = ag->ag_server_leg; ctx->c_orq = nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, (url_string_t *)url, SIP_METHOD_MESSAGE, (url_string_t *)url, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_FROM(ag->ag_bob), SIPTAG_TO(ag->ag_alice), SIPTAG_CONTACT(ag->ag_m_bob), SIPTAG_PAYLOAD(pl), NTATAG_TPORT(tcp_tport), TAG_END()); su_free(ag->ag_home, pl); TEST_1(!client_run(ctx, 503)); TEST_P(ag->ag_latest_leg, ag->ag_server_leg); TEST_1(used_tport); TEST_1(tport_is_tcp(used_tport)); tport_unref(used_tport); tport_unref(tcp_tport), tcp_tport = NULL; } /* Test 0.3 * Send a message from Bob to Alice * This time include a large payload of 512 kB, let NTA choose transport. */ if (tcp) { client_t ctx[1] = {{ ag, "Test 0.3" }}; url_t url[1]; sip_payload_t *pl; usize_t size = 512 * 1024; *url = *ag->ag_aliases->m_url; url->url_user = "alice"; TEST_1(pl = test_payload(ag->ag_home, size)); ag->ag_expect_leg = ag->ag_server_leg; ctx->c_orq = nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, ag->ag_obp, SIP_METHOD_MESSAGE, (url_string_t *)url, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_FROM(ag->ag_bob), SIPTAG_TO(ag->ag_alice), SIPTAG_CONTACT(ag->ag_m_bob), SIPTAG_PAYLOAD(pl), TAG_END()); su_free(ag->ag_home, pl); TEST_1(!client_run(ctx, 200)); TEST_P(ag->ag_latest_leg, ag->ag_server_leg); } /* Test 0.4.1: * Send a message from Bob to Alice * This time include a payload of 2 kB, let NTA choose transport. */ { client_t ctx[1] = {{ ag, "Test 0.4.1", check_via_with_tcp }}; url_t url[1]; sip_payload_t *pl; usize_t size = 2 * 1024; *url = *ag->ag_aliases->m_url; url->url_user = "alice"; TEST_1(pl = test_payload(ag->ag_home, size)); ag->ag_expect_leg = ag->ag_server_leg; ctx->c_orq = nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, ag->ag_obp, SIP_METHOD_MESSAGE, (url_string_t *)url, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_FROM(ag->ag_bob), SIPTAG_TO(ag->ag_alice), SIPTAG_CONTACT(ag->ag_m_bob), SIPTAG_PAYLOAD(pl), TAG_END()); su_free(ag->ag_home, pl); TEST_1(!client_run(ctx, 200)); TEST_P(ag->ag_latest_leg, ag->ag_server_leg); su_free(ag->ag_home, ag->ag_in_via), ag->ag_in_via = NULL; } /* Test 0.4.2: * Send a message from Bob to Alices UDP-only address * This time include a payload of 2 kB, let NTA choose transport. */ if (v_udp_only) { client_t ctx[1] = {{ ag, "Test 0.4.2", check_via_with_udp }}; url_t url[1]; sip_payload_t *pl; usize_t size = 2 * 1024; *url = *ag->ag_aliases->m_url; url->url_user = "alice"; url->url_host = v_udp_only->v_host; url->url_port = v_udp_only->v_port; url->url_params = NULL; /* No sigcomp */ TEST_1(pl = test_payload(ag->ag_home, size)); ag->ag_expect_leg = ag->ag_default_leg; su_free(ag->ag_home, ag->ag_in_via), ag->ag_in_via = NULL; ctx->c_orq = nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, ag->ag_obp, SIP_METHOD_MESSAGE, (url_string_t *)url, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_FROM(ag->ag_bob), SIPTAG_TO(ag->ag_alice), SIPTAG_CONTACT(ag->ag_m_bob), SIPTAG_PAYLOAD(pl), TAG_END()); su_free(ag->ag_home, pl); TEST_1(!client_run(ctx, 200)); TEST_P(ag->ag_latest_leg, ag->ag_default_leg); TEST_1(ag->ag_in_via); TEST_1(strcasecmp(ag->ag_in_via->v_protocol, "SIP/2.0/UDP") == 0); su_free(ag->ag_home, ag->ag_in_via), ag->ag_in_via = NULL; } /* Test 0.5: * Send a message from Bob to Alice * This time include a payload of 2 kB, try to use UDP. */ if (udp) { client_t ctx[1] = {{ ag, "Test 0.5", check_via_with_udp }}; url_t url[1]; sip_payload_t *pl; usize_t size = 2 * 1024; *url = *ag->ag_aliases->m_url; url->url_user = "alice"; TEST_1(pl = test_payload(ag->ag_home, size)); ag->ag_expect_leg = ag->ag_server_leg; ctx->c_orq = nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, ag->ag_obp, SIP_METHOD_MESSAGE, (url_string_t *)url, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_FROM(ag->ag_bob), SIPTAG_TO(ag->ag_alice), SIPTAG_CONTACT(ag->ag_m_bob), SIPTAG_PAYLOAD(pl), TPTAG_MTU(0xffffffff), TAG_END()); su_free(ag->ag_home, pl); TEST_1(!client_run(ctx, 200)); TEST_P(ag->ag_latest_leg, ag->ag_server_leg); } if (udp) { /* Test 0.6 * Send a message from default leg to server leg * using a prefilled Via header */ client_t ctx[1] = {{ ag, "Test 0.6", check_magic_branch }}; sip_via_t via[1]; sip_via_init(via); via->v_protocol = sip_transport_udp; via->v_host = ag->ag_contact->m_url->url_host; via->v_port = ag->ag_contact->m_url->url_port; sip_via_add_param(ag->ag_home, via, "branch=MagicalBranch"); nta_agent_set_params(ag->ag_agent, NTATAG_ALIASES(ag->ag_aliases), NTATAG_USER_VIA(1), TAG_END()); ag->ag_expect_leg = ag->ag_server_leg; ctx->c_orq = nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, ag->ag_obp, SIP_METHOD_MESSAGE, (url_string_t *)url, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_FROM(ag->ag_alice), SIPTAG_TO(ag->ag_bob), SIPTAG_CONTACT(ag->ag_m_alice), SIPTAG_VIA(via), TAG_END()); TEST_1(!client_run(ctx, 200)); TEST_P(ag->ag_latest_leg, ag->ag_server_leg); nta_agent_set_params(ag->ag_agent, NTATAG_USER_VIA(0), TAG_END()); } /* Test 0.7 * Send a message from Bob to Alice using SCTP */ if (sctp) { url_t url[1]; sip_payload_t *pl; usize_t size = 16 * 1024; client_t ctx[1] = {{ ag, "Test 0.7", check_via_with_sctp }}; *url = *ag->ag_aliases->m_url; url->url_user = "alice"; #if 0 if (url->url_params) url->url_params = su_sprintf(NULL, "%s;transport=sctp", url->url_params); else #endif url->url_params = "transport=sctp"; TEST_1(pl = test_payload(ag->ag_home, size)); ag->ag_expect_leg = ag->ag_server_leg; ctx->c_orq = nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, ag->ag_obp, SIP_METHOD_MESSAGE, (url_string_t *)url, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_FROM(ag->ag_bob), SIPTAG_TO(ag->ag_alice), SIPTAG_CONTACT(ag->ag_m_bob), SIPTAG_PAYLOAD(pl), TAG_END()); su_free(ag->ag_home, pl); TEST_1(!client_run(ctx, 200)); TEST_P(ag->ag_latest_leg, ag->ag_server_leg); } /* Test 0.8: Send a too large message */ if (tcp) { url_t url[1]; sip_payload_t *pl; usize_t size = 128 * 1024; client_t ctx[1] = {{ ag, "Test 0.8" }}; nta_agent_set_params(ag->ag_agent, NTATAG_MAXSIZE(65536), TAG_END()); *url = *ag->ag_aliases->m_url; url->url_user = "alice"; TEST_1(pl = test_payload(ag->ag_home, size)); ag->ag_expect_leg = ag->ag_server_leg; ag->ag_latest_leg = NULL; ctx->c_orq = nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, ag->ag_obp, SIP_METHOD_MESSAGE, (url_string_t *)url, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_FROM(ag->ag_bob), SIPTAG_TO(ag->ag_alice), SIPTAG_CONTACT(ag->ag_m_bob), SIPTAG_PAYLOAD(pl), TAG_END()); su_free(ag->ag_home, pl); TEST_1(!client_run(ctx, 413)); TEST_P(ag->ag_latest_leg, NULL); nta_agent_set_params(ag->ag_agent, NTATAG_MAXSIZE(2 * 1024 * 1024), TAG_END()); } /* Test 0.9: Timeout */ { url_t url[1]; client_t ctx[1] = {{ ag, "Test 0.9" }}; printf("%s: starting MESSAGE timeout test, completing in 4 seconds\n", name); nta_agent_set_params(ag->ag_agent, NTATAG_TIMEOUT_408(1), NTATAG_SIP_T1(25), NTATAG_SIP_T1X64(64 * 25), NTATAG_SIP_T2(8 * 25), NTATAG_SIP_T4(10 * 25), TAG_END()); *url = *ag->ag_aliases->m_url; url->url_user = "timeout"; url->url_port = ag->ag_sink_port; ag->ag_expect_leg = ag->ag_server_leg; ag->ag_latest_leg = NULL; ctx->c_orq = nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, ag->ag_obp, SIP_METHOD_MESSAGE, (url_string_t *)url, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_FROM(ag->ag_bob), SIPTAG_TO(ag->ag_alice), SIPTAG_CONTACT(ag->ag_m_bob), TAG_END()); TEST_1(!client_run(ctx, 408)); TEST_P(ag->ag_latest_leg, NULL); nta_agent_set_params(ag->ag_agent, NTATAG_SIP_T1(500), NTATAG_SIP_T1X64(64 * 500), NTATAG_SIP_T2(NTA_SIP_T2), NTATAG_SIP_T4(NTA_SIP_T4), TAG_END()); } END(); } int leg_callback_destroy(agent_t *ag, nta_leg_t *leg, nta_incoming_t *irq, sip_t const *sip) { if (tstflags & tst_verbatim) { printf("%s: %s: %s " URL_PRINT_FORMAT " %s\n", name, __func__, sip->sip_request->rq_method_name, URL_PRINT_ARGS(sip->sip_request->rq_url), sip->sip_request->rq_version); } ag->ag_latest_leg = leg; nta_incoming_destroy(irq); return 0; } int leg_callback_save(agent_t *ag, nta_leg_t *leg, nta_incoming_t *irq, sip_t const *sip) { if (tstflags & tst_verbatim) { printf("%s: %s: %s " URL_PRINT_FORMAT " %s\n", name, __func__, sip->sip_request->rq_method_name, URL_PRINT_ARGS(sip->sip_request->rq_url), sip->sip_request->rq_version); } ag->ag_latest_leg = leg; ag->ag_irq = irq; ag->ag_running = 0; return 0; } int test_destroy_incoming(agent_t *ag) { BEGIN(); url_t url[1]; *url = *ag->ag_contact->m_url; { client_t ctx[1] = {{ ag, "Test 3.1" }}; /* Test 3.1 * Check that when a incoming request is destroyed in callback, * a 500 response is sent */ ag->ag_expect_leg = ag->ag_default_leg; nta_leg_bind(ag->ag_default_leg, leg_callback_destroy, ag); ctx->c_orq = nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, ag->ag_obp, SIP_METHOD_MESSAGE, (url_string_t *)url, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_FROM(ag->ag_alice), SIPTAG_TO(ag->ag_bob), TAG_END()); TEST_1(!client_run(ctx, 500)); TEST_P(ag->ag_latest_leg, ag->ag_default_leg); } { /* Test 3.2 * Check that when an incoming request is destroyed, a 500 response is sent */ client_t ctx[1] = {{ ag, "Test 3.2" }}; nta_leg_bind(ag->ag_default_leg, leg_callback_save, ag); ctx->c_orq = nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, ag->ag_obp, SIP_METHOD_MESSAGE, (url_string_t *)url, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_FROM(ag->ag_alice), SIPTAG_TO(ag->ag_bob), TAG_END()); TEST_1(ctx->c_orq); nta_test_run(ag); TEST(ctx->c_status, 0); TEST_1(ag->ag_irq); TEST_1(ctx->c_orq); TEST_P(ag->ag_latest_leg, ag->ag_default_leg); nta_incoming_destroy(ag->ag_irq), ag->ag_irq = NULL; TEST_1(!client_run(ctx, 500)); } END(); } int test_resolv(agent_t *ag, char const *resolv_conf) { int udp = 0, tcp = 0, sctp = 0, tls = 0; sip_via_t const *v; url_t *url; if (!resolv_conf) return 0; BEGIN(); nta_leg_bind(ag->ag_default_leg, leg_callback_200, ag); nta_agent_set_params(ag->ag_agent, NTATAG_SIP_T1(8 * 25), NTATAG_SIP_T1X64(64 * 25), NTATAG_SIP_T4(10 * 25), TAG_END()); TEST_1(v = nta_agent_via(ag->ag_agent)); for (; v; v = v->v_next) { if (strcasecmp(v->v_protocol, sip_transport_udp) == 0) udp = 1; else if (strcasecmp(v->v_protocol, sip_transport_tcp) == 0) tcp = 1; else if (strcasecmp(v->v_protocol, sip_transport_sctp) == 0) sctp = 1; else if (strcasecmp(v->v_protocol, sip_transport_tls) == 0) tls = 1; } url = url_hdup(ag->ag_home, (void *)"sip:example.org"); TEST_1(url); { /* Test 1.1 * Send a message to sip:example.org */ client_t ctx[1] = {{ ag, "Test 1.1" }}; ag->ag_expect_leg = ag->ag_default_leg; ctx->c_orq = nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, ag->ag_obp, SIP_METHOD_MESSAGE, (url_string_t *)url, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_FROM(ag->ag_alice), SIPTAG_TO(ag->ag_bob), SIPTAG_CONTACT(ag->ag_m_alice), TAG_END()); TEST_1(!client_run(ctx, 200)); TEST_P(ag->ag_latest_leg, ag->ag_default_leg); } { /* Test 1.2 * Send a message to sip:srv.example.org */ client_t ctx[1] = {{ ag, "Test 1.2" }}; url->url_host = "srv.example.org"; ag->ag_expect_leg = ag->ag_default_leg; ctx->c_orq = nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, ag->ag_obp, SIP_METHOD_MESSAGE, (url_string_t *)url, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_FROM(ag->ag_alice), SIPTAG_TO(ag->ag_bob), SIPTAG_CONTACT(ag->ag_m_alice), TAG_END()); TEST_1(!client_run(ctx, 200)); TEST_P(ag->ag_latest_leg, ag->ag_default_leg); } { /* Test 1.3 * Send a message to sip:ipv.example.org */ client_t ctx[1] = {{ ag, "Test 1.3" }}; url->url_host = "ipv.example.org"; ag->ag_expect_leg = ag->ag_default_leg; ctx->c_orq = nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, ag->ag_obp, SIP_METHOD_MESSAGE, (url_string_t *)url, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_FROM(ag->ag_alice), SIPTAG_TO(ag->ag_bob), SIPTAG_CONTACT(ag->ag_m_alice), TAG_END()); TEST_1(!client_run(ctx, 200)); TEST_P(ag->ag_latest_leg, ag->ag_default_leg); } { /* Test 1.4.1 * Send a message to sip:down.example.org */ client_t ctx[1] = {{ ag, "Test 1.4.1" }}; url->url_host = "down.example.org"; ag->ag_expect_leg = ag->ag_default_leg; ctx->c_orq = nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, ag->ag_obp, SIP_METHOD_MESSAGE, (url_string_t *)url, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_FROM(ag->ag_alice), SIPTAG_TO(ag->ag_bob), SIPTAG_CONTACT(ag->ag_m_alice), TAG_END()); TEST_1(!client_run(ctx, 200)); TEST_P(ag->ag_latest_leg, ag->ag_default_leg); } { /* Test 1.4.2 * Send a message to sip:na503.example.org */ client_t ctx[1] = {{ ag, "Test 1.4.2" }}; url->url_host = "na503.example.org"; ag->ag_expect_leg = ag->ag_default_leg; ctx->c_orq = nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, ag->ag_obp, SIP_METHOD_MESSAGE, (url_string_t *)url, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_FROM(ag->ag_alice), SIPTAG_TO(ag->ag_bob), SIPTAG_CONTACT(ag->ag_m_alice), TAG_END()); TEST_1(!client_run(ctx, 503)); TEST_P(ag->ag_latest_leg, ag->ag_default_leg); } { /* Test 1.4.3 * Send a message to sip:nona.example.org */ client_t ctx[1] = {{ ag, "Test 1.4.3" }}; url->url_host = "nona.example.org"; ag->ag_expect_leg = ag->ag_default_leg; ctx->c_orq = nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, ag->ag_obp, SIP_METHOD_MESSAGE, (url_string_t *)url, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_FROM(ag->ag_alice), SIPTAG_TO(ag->ag_bob), SIPTAG_CONTACT(ag->ag_m_alice), TAG_END()); TEST_1(!client_run(ctx, 200)); TEST_P(ag->ag_latest_leg, ag->ag_default_leg); } { /* Test 1.4.4 * Send a message to sip:nosrv.example.org * After failing to find _sip._udp.nosrv.example.org, * second SRV with _sip._udp.srv.example.org succeeds */ client_t ctx[1] = {{ ag, "Test 1.4.4" }}; url->url_host = "nosrv.example.org"; ag->ag_expect_leg = ag->ag_default_leg; ctx->c_orq = nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, ag->ag_obp, SIP_METHOD_MESSAGE, (url_string_t *)url, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_FROM(ag->ag_alice), SIPTAG_TO(ag->ag_bob), SIPTAG_CONTACT(ag->ag_m_alice), TAG_END()); TEST_1(!client_run(ctx, 200)); TEST_P(ag->ag_latest_leg, ag->ag_default_leg); } { /* Test 1.5.1 * Send a message to sip:srv.example.org;transport=tcp * Test outgoing_make_srv_query() */ client_t ctx[1] = {{ ag, "Test 1.5.1: outgoing_make_srv_query()" }}; url->url_host = "srv.example.org"; url->url_params = "transport=tcp"; ag->ag_expect_leg = ag->ag_default_leg; ctx->c_orq = nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, ag->ag_obp, SIP_METHOD_MESSAGE, (url_string_t *)url, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_FROM(ag->ag_alice), SIPTAG_TO(ag->ag_bob), SIPTAG_CONTACT(ag->ag_m_alice), TAG_END()); TEST_1(!client_run(ctx, 200)); TEST_P(ag->ag_latest_leg, ag->ag_default_leg); url->url_params = NULL; } { /* Test 1.5.2 * Send a message to sip:srv.example.org;transport=udp * Test outgoing_make_srv_query() */ client_t ctx[1] = {{ ag, "Test 1.5.2: outgoing_make_srv_query()" }}; url->url_host = "srv.example.org"; url->url_params = "transport=udp"; ag->ag_expect_leg = ag->ag_default_leg; ctx->c_orq = nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, ag->ag_obp, SIP_METHOD_MESSAGE, (url_string_t *)url, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_FROM(ag->ag_alice), SIPTAG_TO(ag->ag_bob), SIPTAG_CONTACT(ag->ag_m_alice), TAG_END()); TEST_1(!client_run(ctx, 200)); TEST_P(ag->ag_latest_leg, ag->ag_default_leg); url->url_params = NULL; } { /* Test 1.5.3 * Send a message to sip:srv2.example.org;transport=udp * Test outgoing_query_srv_a() */ client_t ctx[1] = {{ ag, "Test 1.5: outgoing_query_srv_a()" }}; url->url_host = "srv2.example.org"; url->url_params = "transport=udp"; ag->ag_expect_leg = ag->ag_default_leg; ctx->c_orq = nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, ag->ag_obp, SIP_METHOD_MESSAGE, (url_string_t *)url, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_FROM(ag->ag_alice), SIPTAG_TO(ag->ag_bob), SIPTAG_CONTACT(ag->ag_m_alice), TAG_END()); TEST_1(!client_run(ctx, 200)); TEST_P(ag->ag_latest_leg, ag->ag_default_leg); url->url_params = NULL; } { /* Test 1.6.1 * Send a message to sip:srv.example.org:$port * Test outgoing_make_a_aaaa_query() */ client_t ctx[1] = {{ ag, "Test 1.6.1: outgoing_make_a_aaaa_query()" }}; url->url_host = "srv.example.org"; url->url_port = ag->ag_contact->m_url->url_port; ag->ag_expect_leg = ag->ag_default_leg; ctx->c_orq = nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, ag->ag_obp, SIP_METHOD_MESSAGE, (url_string_t *)url, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_FROM(ag->ag_alice), SIPTAG_TO(ag->ag_bob), SIPTAG_CONTACT(ag->ag_m_alice), TAG_END()); TEST_1(!client_run(ctx, 503)); TEST_P(ag->ag_latest_leg, ag->ag_default_leg); } { /* Test 1.6.2 * Send a message to sip:a.example.org:$port * Test outgoing_make_a_aaaa_query() */ client_t ctx[1] = {{ ag, "Test 1.6.2: outgoing_make_a_aaaa_query()" }}; url->url_host = "a.example.org"; url->url_port = ag->ag_contact->m_url->url_port; ag->ag_expect_leg = ag->ag_default_leg; ctx->c_orq = nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, ag->ag_obp, SIP_METHOD_MESSAGE, (url_string_t *)url, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_FROM(ag->ag_alice), SIPTAG_TO(ag->ag_bob), SIPTAG_CONTACT(ag->ag_m_alice), TAG_END()); TEST_1(!client_run(ctx, 200)); TEST_P(ag->ag_latest_leg, ag->ag_default_leg); url->url_port = NULL; } #if 0 /* This must be run on host *without* proxy */ { /* Test 1.6c * Send a message to sip:na.example.org * Test outgoing_query_all() with NAPTR "A" flag */ client_t ctx[1] = {{ ag, "Test 1.6c" }}; url->url_host = "na.example.org"; ag->ag_expect_leg = ag->ag_default_leg; TEST_1(ctx->c_orq = nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, ag->ag_obp, SIP_METHOD_MESSAGE, (url_string_t *)url, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_FROM(ag->ag_alice), SIPTAG_TO(ag->ag_bob), SIPTAG_CONTACT(ag->ag_m_alice), TAG_END())); TEST_1(!client_run(ctx, 503)); TEST(ag->ag_latest_leg, ag->ag_default_leg); } #endif { /* Test 1.7 * Send a message to sip:down2.example.org:$port * Test A record failover. */ client_t ctx[1] = {{ ag, "Test 1.7: outgoing_make_a_aaaa_query()" }}; url->url_host = "down2.example.org"; url->url_port = ag->ag_contact->m_url->url_port; ag->ag_expect_leg = ag->ag_default_leg; ctx->c_orq = nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, ag->ag_obp, SIP_METHOD_MESSAGE, (url_string_t *)url, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_FROM(ag->ag_alice), SIPTAG_TO(ag->ag_bob), SIPTAG_CONTACT(ag->ag_m_alice), TAG_END()); TEST_1(!client_run(ctx, 200)); TEST_P(ag->ag_latest_leg, ag->ag_default_leg); url->url_params = NULL; } nta_agent_set_params(ag->ag_agent, NTATAG_SIP_T1(500), NTATAG_SIP_T1X64(64 * 500), NTATAG_SIP_T2(NTA_SIP_T2), NTATAG_SIP_T4(NTA_SIP_T4), TAG_END()); END(); } /* Test default routing */ int test_routing(agent_t *ag) { url_t url[1]; *url = *ag->ag_aliases->m_url; url->url_user = "bob"; nta_leg_bind(ag->ag_default_leg, leg_callback_200, ag); nta_agent_set_params(ag->ag_agent, NTATAG_MAXSIZE(2 * 1024 * 1024), TAG_END()); BEGIN(); { /* * Send a message from default leg to default leg * * We are now using url with an explicit port that does not match with * our own port number. */ url_t url2[1]; client_t ctx[1] = {{ ag, "Test 1.2" }}; *url2 = *url; url2->url_port = "9"; /* discard service */ ag->ag_expect_leg = ag->ag_default_leg; ctx->c_orq = nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, (url_string_t *)url, SIP_METHOD_MESSAGE, (url_string_t *)url2, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_FROM(ag->ag_alice), SIPTAG_TO(ag->ag_bob), SIPTAG_CONTACT(ag->ag_m_alice), TAG_END()); TEST_1(!client_run(ctx, 200)); TEST_P(ag->ag_latest_leg, ag->ag_default_leg); } END(); } /* Test dialogs and the tag handling */ int test_dialog(agent_t *ag) { BEGIN(); /* * Test establishing a dialog * * Alice sends a message to Bob, then Bob back to the Alice, and again * Alice to Bob. */ ag->ag_alice_leg = nta_leg_tcreate(ag->ag_agent, leg_callback_200, ag, SIPTAG_FROM(ag->ag_alice), SIPTAG_TO(ag->ag_bob), TAG_END()); TEST_1(ag->ag_alice_leg); TEST_1(nta_leg_tag(ag->ag_alice_leg, NULL)); { client_t ctx[1] = {{ ag, "Test 2.1" }}; nta_leg_bind(ag->ag_server_leg, new_leg_callback_200, ag); /* Send message from Alice to Bob establishing the dialog */ ag->ag_expect_leg = ag->ag_server_leg; ag->ag_tag_remote = ag->ag_alice_leg; ctx->c_orq = nta_outgoing_tcreate(ag->ag_alice_leg, outgoing_callback, ctx, ag->ag_obp, SIP_METHOD_MESSAGE, (url_string_t *)ag->ag_m_bob->m_url, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_FROM(ag->ag_alice), SIPTAG_TO(ag->ag_bob), SIPTAG_CONTACT(ag->ag_m_alice), TAG_END()); TEST_1(!client_run(ctx, 200)); TEST_P(ag->ag_latest_leg, ag->ag_server_leg); TEST_1(ag->ag_bob_leg != NULL); } { /* Send message from Bob to Alice */ client_t ctx[1] = {{ ag, "Test 2.2" }}; nta_leg_bind(ag->ag_server_leg, leg_callback_200, ag); ag->ag_expect_leg = ag->ag_alice_leg; ctx->c_orq = nta_outgoing_tcreate(ag->ag_bob_leg, outgoing_callback, ctx, NULL, SIP_METHOD_MESSAGE, (url_string_t *)ag->ag_m_alice->m_url, SIPTAG_SUBJECT_STR(ctx->c_name), TAG_END()); TEST_1(!client_run(ctx, 200)); TEST_P(ag->ag_latest_leg, ag->ag_alice_leg); } { /* Send again message from Alice to Bob */ client_t ctx[1] = {{ ag, "Test 2.3" }}; ag->ag_expect_leg = ag->ag_bob_leg; ctx->c_orq = nta_outgoing_tcreate(ag->ag_alice_leg, outgoing_callback, ctx, NULL, SIP_METHOD_MESSAGE, (url_string_t *)ag->ag_m_bob->m_url, SIPTAG_SUBJECT_STR(ctx->c_name), TAG_END()); TEST_1(!client_run(ctx, 200)); TEST_P(ag->ag_latest_leg, ag->ag_bob_leg); } { /* Send message from Bob to Alice * This time, however, specify request URI */ client_t ctx[1] = {{ ag, "Test 2.4" }}; ag->ag_expect_leg = ag->ag_alice_leg; ctx->c_orq = nta_outgoing_tcreate(ag->ag_bob_leg, outgoing_callback, ctx, NULL, SIP_METHOD_MESSAGE, (url_string_t *)ag->ag_m_alice->m_url, SIPTAG_SUBJECT_STR(ctx->c_name), TAG_END()); TEST_1(!client_run(ctx, 200)); TEST_P(ag->ag_latest_leg, ag->ag_alice_leg); } nta_leg_destroy(ag->ag_alice_leg), ag->ag_alice_leg = NULL; nta_leg_destroy(ag->ag_bob_leg), ag->ag_bob_leg = NULL; END(); } /* ---------------------------------------------------------------------- */ /* Test INVITE, dialogs */ static int test_for_ack(agent_t *ag, nta_incoming_t *irq, sip_t const *sip) { sip_method_t method; BEGIN(); method = sip ? sip->sip_request->rq_method : sip_method_unknown; nta_incoming_destroy(irq); TEST_P(irq, ag->ag_irq); ag->ag_irq = NULL; TEST(method, sip_method_ack); ag->ag_running = 0; END(); } static int test_for_prack(agent_t *ag, nta_reliable_t *rel, nta_incoming_t *prack, sip_t const *sip) { sip_method_t method = sip ? sip->sip_request->rq_method : sip_method_unknown; nta_incoming_treply(ag->ag_irq, SIP_200_OK, SIPTAG_CONTACT(ag->ag_m_alice), TAG_END()); TEST(method, sip_method_prack); return 200; } int alice_leg_callback(agent_t *ag, nta_leg_t *leg, nta_incoming_t *irq, sip_t const *sip) { BEGIN(); if (tstflags & tst_verbatim) { printf("%s: %s: %s " URL_PRINT_FORMAT " %s\n", name, __func__, sip->sip_request->rq_method_name, URL_PRINT_ARGS(sip->sip_request->rq_url), sip->sip_request->rq_version); } TEST_1(sip->sip_content_length); TEST_1(sip->sip_via); TEST_1(sip->sip_from && sip->sip_from->a_tag); if (sip->sip_request->rq_method == sip_method_prack) return 481; ag->ag_latest_leg = leg; if (leg != ag->ag_alice_leg) { leg_match(ag, leg, 1, __func__); return 500; } if (sip->sip_request->rq_method == sip_method_invite) { TEST_1(sip_has_feature(sip->sip_supported, "100rel")); nta_incoming_bind(irq, test_for_ack, ag); nta_incoming_treply(irq, SIP_100_TRYING, TAG_END()); nta_agent_set_params(ag->ag_agent, NTATAG_DEBUG_DROP_PROB(ag->ag_drop), TAG_END()); ag->ag_reliable = nta_reliable_treply(irq, NULL, NULL, SIP_183_SESSION_PROGRESS, SIPTAG_CONTENT_TYPE(ag->ag_content_type), SIPTAG_PAYLOAD(ag->ag_payload), SIPTAG_CONTACT(ag->ag_m_alice), TAG_END()); TEST_1(ag->ag_reliable); ag->ag_reliable = nta_reliable_treply(irq, NULL, NULL, 184, "Next", SIPTAG_CONTACT(ag->ag_m_alice), TAG_END()); TEST_1(ag->ag_reliable); ag->ag_reliable = nta_reliable_treply(irq, test_for_prack, ag, 185, "Last", SIPTAG_CONTACT(ag->ag_m_alice), TAG_END()); TEST_1(ag->ag_reliable); ag->ag_irq = irq; return 0; } if (sip->sip_request->rq_method == sip_method_bye) { leg_zap(ag, leg); } if (sip) return 200; END(); } int bob_leg_callback(agent_t *ag, nta_leg_t *leg, nta_incoming_t *irq, sip_t const *sip) { BEGIN(); if (tstflags & tst_verbatim) { printf("%s: %s: %s " URL_PRINT_FORMAT " %s\n", name, __func__, sip->sip_request->rq_method_name, URL_PRINT_ARGS(sip->sip_request->rq_url), sip->sip_request->rq_version); } TEST_1(sip->sip_content_length); TEST_1(sip->sip_via); TEST_1(sip->sip_from && sip->sip_from->a_tag); if (sip->sip_request->rq_method == sip_method_prack) return 481; ag->ag_latest_leg = leg; if (ag->ag_bob_leg && leg != ag->ag_bob_leg) { leg_match(ag, leg, 1, __func__); return 500; } if (ag->ag_bob_leg == NULL) { nta_leg_bind(leg, leg_callback_500, ag); ag->ag_bob_leg = nta_leg_tcreate(ag->ag_agent, bob_leg_callback, ag, SIPTAG_CALL_ID(sip->sip_call_id), SIPTAG_FROM(sip->sip_to), SIPTAG_TO(sip->sip_from), TAG_END()); TEST_1(ag->ag_bob_leg); TEST_1(nta_leg_tag(ag->ag_bob_leg, NULL)); TEST_1(nta_leg_get_tag(ag->ag_bob_leg)); TEST_1(nta_incoming_tag(irq, nta_leg_get_tag(ag->ag_bob_leg))); TEST(nta_leg_server_route(ag->ag_bob_leg, sip->sip_record_route, sip->sip_contact), 0); } if (sip->sip_request->rq_method != sip_method_invite) { return 200; } else { nta_incoming_bind(irq, test_for_ack, ag); #if 1 nta_incoming_treply(irq, SIP_180_RINGING, SIPTAG_CONTACT(ag->ag_m_bob), TAG_END()); nta_incoming_treply(irq, SIP_180_RINGING, SIPTAG_CONTACT(ag->ag_m_bob), TAG_END()); #endif nta_incoming_treply(irq, SIP_200_OK, SIPTAG_CONTENT_TYPE(ag->ag_content_type), SIPTAG_PAYLOAD(ag->ag_payload), SIPTAG_CONTACT(ag->ag_m_bob), TAG_END()); ag->ag_irq = irq; } END(); } struct invite_client_t { client_t ic_client[1]; nta_outgoing_t *ic_orq; /* Original INVITE transaction */ int ic_tag_status; /* Status for current branch */ char *ic_tag; }; static int invite_client_deinit(client_t *c) { agent_t *ag = c->c_ag; invite_client_t *ic = (invite_client_t *)c; if (ic->ic_orq) nta_outgoing_destroy(ic->ic_orq), ic->ic_orq = NULL; if (ic->ic_tag) su_free(ag->ag_home, ic->ic_tag), ic->ic_tag = NULL; return 0; } static int check_prack_sending(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip) { agent_t *ag = ctx->c_ag; int status = ctx->c_status; if (100 < status && status < 200) { if (sip->sip_require && sip_has_feature(sip->sip_require, "100rel")) { nta_outgoing_t *prack = NULL; TEST_1(sip->sip_rseq); prack = nta_outgoing_prack(ag->ag_call_leg, orq, NULL, NULL, NULL, sip, TAG_END()); nta_outgoing_destroy(prack); TEST_1(prack != NULL); } } return 0; } static int check_leg_tagging(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip) { agent_t *ag = ctx->c_ag; int status = ctx->c_status; if (200 <= status && status < 300) { TEST_1(nta_leg_rtag(ag->ag_call_leg, sip->sip_to->a_tag)); TEST(nta_leg_client_route(ag->ag_call_leg, sip->sip_record_route, sip->sip_contact), 0); } return 0; } static int check_tu_ack(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip) { agent_t *ag = ctx->c_ag; int status = ctx->c_status; if (200 <= status && status < 300) { nta_outgoing_t *ack; ack = nta_outgoing_tcreate(ag->ag_call_leg, NULL, NULL, NULL, SIP_METHOD_ACK, NULL, SIPTAG_CSEQ(sip->sip_cseq), TAG_END()); nta_outgoing_destroy(ack); TEST_1(ack); } return 0; } static int check_final_error(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip) { agent_t *ag = ctx->c_ag; int status = ctx->c_status; if (status >= 300) ag->ag_call_leg = NULL; return 0; } /** Cancel call after receiving 1XX response */ static int cancel_invite(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip) { int status = ctx->c_status; if (100 < status && status < 200) { nta_outgoing_cancel(orq); ctx->c_status = 0; } else if (status >= 200) { TEST_1(status == 487 || status == 504); } return 0; } static client_check_f * const checks_for_invite[] = { client_check_to_tag, check_leg_tagging, check_tu_ack, check_final_error, NULL, }; static client_check_f * const checks_for_reinvite[] = { client_check_to_tag, check_prack_sending, check_leg_tagging, check_tu_ack, NULL, }; int test_call(agent_t *ag) { sip_content_type_t *ct = ag->ag_content_type; sip_payload_t *sdp = ag->ag_payload; nta_leg_t *old_leg; sip_replaces_t *r1, *r2; BEGIN(); { invite_client_t ic[1] = {{ {{ ag, "Call 1", NULL, checks_for_invite, invite_client_deinit }} }}; client_t *ctx = ic->ic_client; /* * Test establishing a call * * Alice sends a INVITE to Bob, then Bob sends 200 Ok. */ ag->ag_alice_leg = nta_leg_tcreate(ag->ag_agent, alice_leg_callback, ag, SIPTAG_FROM(ag->ag_alice), SIPTAG_TO(ag->ag_bob), TAG_END()); TEST_1(ag->ag_alice_leg); TEST_1(nta_leg_tag(ag->ag_alice_leg, NULL)); nta_leg_bind(ag->ag_server_leg, bob_leg_callback, ag); /* Send INVITE */ ag->ag_expect_leg = ag->ag_server_leg; ctx->c_orq = nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_alice_leg, outgoing_callback, ctx, ag->ag_obp, SIP_METHOD_INVITE, (url_string_t *)ag->ag_m_bob->m_url, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_CONTACT(ag->ag_m_alice), SIPTAG_CONTENT_TYPE(ct), SIPTAG_ACCEPT_CONTACT_STR("*;audio"), SIPTAG_PAYLOAD(sdp), NTATAG_USE_TIMESTAMP(1), NTATAG_PASS_100(1), TAG_END()); TEST_1(ctx->c_orq); /* Try to CANCEL it immediately */ TEST_1(nta_outgoing_cancel(ctx->c_orq) == 0); /* As Bob immediately answers INVITE with 200 Ok, cancel should be answered with 481 and 200 Ok is teruned to INVITE. */ TEST_1(!client_run(ctx, 200)); TEST_P(ag->ag_latest_leg, ag->ag_server_leg); TEST_1(ag->ag_bob_leg != NULL); } TEST_1(r1 = nta_leg_make_replaces(ag->ag_alice_leg, ag->ag_home, 0)); TEST_1(r2 = sip_replaces_format(ag->ag_home, "%s;from-tag=%s;to-tag=%s", r1->rp_call_id, r1->rp_to_tag, r1->rp_from_tag)); TEST_P(ag->ag_alice_leg, nta_leg_by_replaces(ag->ag_agent, r2)); TEST_P(ag->ag_bob_leg, nta_leg_by_replaces(ag->ag_agent, r1)); { invite_client_t ic[1] = {{ {{ ag, "Re-INVITE in Call 1", NULL, checks_for_reinvite, invite_client_deinit }} }}; client_t *ctx = ic->ic_client; /* Re-INVITE from Bob to Alice. * * Alice first sends 183, waits for PRACK, then sends 184 and 185, * waits for PRACKs, then sends 200, waits for ACK. */ ag->ag_expect_leg = ag->ag_alice_leg; ctx->c_orq = nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_bob_leg, outgoing_callback, ctx, NULL, SIP_METHOD_INVITE, NULL, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_CONTACT(ag->ag_m_bob), SIPTAG_SUPPORTED_STR("foo"), SIPTAG_CONTENT_TYPE(ct), SIPTAG_PAYLOAD(sdp), TAG_END()); TEST_1(!client_run(ctx, 200)); TEST_P(ag->ag_latest_leg, ag->ag_alice_leg); } { client_t ctx[1] = {{ ag, "Hangup" }}; nta_agent_set_params(ag->ag_agent, NTATAG_DEBUG_DROP_PROB(0), TAG_END()); /* Send BYE from Bob to Alice */ old_leg = ag->ag_expect_leg = ag->ag_alice_leg; ctx->c_orq = nta_outgoing_tcreate(ag->ag_bob_leg, outgoing_callback, ctx, NULL, SIP_METHOD_BYE, NULL, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_FROM(ag->ag_alice), SIPTAG_TO(ag->ag_bob), SIPTAG_CONTACT(ag->ag_m_alice), SIPTAG_CONTENT_TYPE(ct), SIPTAG_PAYLOAD(sdp), TAG_END()); TEST_1(!client_run(ctx, 200)); TEST_P(ag->ag_latest_leg, old_leg); TEST_P(ag->ag_alice_leg, NULL); } nta_leg_destroy(ag->ag_bob_leg), ag->ag_bob_leg = NULL; ag->ag_latest_leg = NULL; ag->ag_call_leg = NULL; END(); } /* ============================================================================ */ /* Test early dialogs, PRACK */ int test_for_ack_or_timeout(agent_t *ag, nta_incoming_t *irq, sip_t const *sip) { BEGIN(); sip_method_t method = sip ? sip->sip_request->rq_method : sip_method_unknown; if (method == sip_method_ack) { TEST(method, sip_method_ack); ag->ag_acked = 1; } else if (method == sip_method_cancel) { nta_incoming_treply(irq, SIP_487_REQUEST_CANCELLED, TAG_END()); ag->ag_canceled = 1; } else { if (ag->ag_bob_leg) { nta_leg_destroy(ag->ag_bob_leg), ag->ag_bob_leg = NULL; } } nta_incoming_destroy(irq); TEST_P(irq, ag->ag_irq); ag->ag_irq = NULL; END(); } /* */ int bob_leg_callback2(agent_t *ag, nta_leg_t *leg, nta_incoming_t *irq, sip_t const *sip) { BEGIN(); if (tstflags & tst_verbatim) { printf("%s: %s: %s " URL_PRINT_FORMAT " %s\n", name, __func__, sip->sip_request->rq_method_name, URL_PRINT_ARGS(sip->sip_request->rq_url), sip->sip_request->rq_version); } TEST_1(sip->sip_content_length); TEST_1(sip->sip_via); TEST_1(sip->sip_from && sip->sip_from->a_tag); ag->ag_latest_leg = leg; if (ag->ag_bob_leg && leg != ag->ag_bob_leg) { leg_match(ag, leg, 1, __func__); return 500; } if (ag->ag_bob_leg == NULL) { nta_leg_bind(leg, leg_callback_500, ag); ag->ag_bob_leg = nta_leg_tcreate(ag->ag_agent, bob_leg_callback, ag, SIPTAG_CALL_ID(sip->sip_call_id), SIPTAG_FROM(sip->sip_to), SIPTAG_TO(sip->sip_from), TAG_END()); TEST_1(ag->ag_bob_leg); TEST_1(nta_leg_tag(ag->ag_bob_leg, NULL)); TEST_1(nta_leg_get_tag(ag->ag_bob_leg)); TEST_1(nta_incoming_tag(irq, nta_leg_get_tag(ag->ag_bob_leg))); TEST(nta_leg_server_route(ag->ag_bob_leg, sip->sip_record_route, sip->sip_contact), 0); } if (sip->sip_request->rq_method != sip_method_invite) { return 200; } nta_incoming_bind(irq, test_for_ack_or_timeout, ag); nta_incoming_treply(irq, SIP_183_SESSION_PROGRESS, SIPTAG_CONTENT_TYPE(ag->ag_content_type), SIPTAG_PAYLOAD(ag->ag_payload), SIPTAG_CONTACT(ag->ag_m_bob), TAG_END()); if (0) nta_incoming_treply(irq, SIP_180_RINGING, SIPTAG_CONTENT_TYPE(ag->ag_content_type), SIPTAG_PAYLOAD(ag->ag_payload), SIPTAG_CONTACT(ag->ag_m_bob), TAG_END()); nta_incoming_treply(irq, SIP_200_OK, SIPTAG_CONTACT(ag->ag_m_bob), TAG_END()); ag->ag_irq = irq; END(); } /** Fork the original INVITE. */ static int check_orq_tagging(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip) { agent_t *ag = ctx->c_ag; int status = ctx->c_status; invite_client_t *ic = (invite_client_t *)ctx; if (100 < status && status < 200) { TEST_1(sip->sip_rseq); TEST_1(sip->sip_to->a_tag); TEST_1(orq == ctx->c_orq); TEST_1(ic); TEST_1(ic->ic_orq == NULL); TEST_1(ic->ic_tag == NULL); ic->ic_orq = orq; ic->ic_tag = su_strdup(ag->ag_home, sip->sip_to->a_tag); TEST_1(ic->ic_tag); ic->ic_tag_status = status; TEST_S(nta_leg_rtag(ag->ag_call_leg, ic->ic_tag), ic->ic_tag); TEST(nta_leg_client_route(ag->ag_call_leg, sip->sip_record_route, sip->sip_contact), 0); orq = nta_outgoing_tagged(orq, outgoing_callback, ctx, ic->ic_tag, sip->sip_rseq); TEST_1(orq); nta_outgoing_destroy(ctx->c_orq); ctx->c_orq = orq; TEST_1(ctx->c_checks && ctx->c_checks[0] == check_orq_tagging); ctx->c_checks++; } return 0; } static client_check_f * const checks_for_100rel[] = { check_orq_tagging, client_check_to_tag, check_prack_sending, check_leg_tagging, check_tu_ack, NULL, }; static int process_prack(nta_reliable_magic_t *arg, nta_reliable_t *rel, nta_incoming_t *irq, sip_t const *sip) { agent_t *ag = (agent_t *)arg; if (irq) { return 200; } else if (ag->ag_irq) { nta_incoming_treply(ag->ag_irq, 504, "Reliable Response Timeout", TAG_END()); nta_incoming_destroy(ag->ag_irq); return 487; } return 487; } /* respond with 183 when receiving invite */ int bob_leg_callback3(agent_t *ag, nta_leg_t *leg, nta_incoming_t *irq, sip_t const *sip) { BEGIN(); if (tstflags & tst_verbatim) { printf("%s: %s: %s " URL_PRINT_FORMAT " %s\n", name, __func__, sip->sip_request->rq_method_name, URL_PRINT_ARGS(sip->sip_request->rq_url), sip->sip_request->rq_version); } TEST_1(sip->sip_content_length); TEST_1(sip->sip_via); TEST_1(sip->sip_from && sip->sip_from->a_tag); ag->ag_latest_leg = leg; if (ag->ag_bob_leg && leg != ag->ag_bob_leg) { leg_match(ag, leg, 1, __func__); return 500; } if (ag->ag_bob_leg == NULL) { nta_leg_bind(leg, leg_callback_500, ag); ag->ag_bob_leg = nta_leg_tcreate(ag->ag_agent, bob_leg_callback, ag, SIPTAG_CALL_ID(sip->sip_call_id), SIPTAG_FROM(sip->sip_to), SIPTAG_TO(sip->sip_from), TAG_END()); TEST_1(ag->ag_bob_leg); TEST_1(nta_leg_tag(ag->ag_bob_leg, NULL)); TEST_1(nta_leg_get_tag(ag->ag_bob_leg)); TEST_1(nta_incoming_tag(irq, nta_leg_get_tag(ag->ag_bob_leg))); TEST(nta_leg_server_route(ag->ag_bob_leg, sip->sip_record_route, sip->sip_contact), 0); } if (sip->sip_request->rq_method != sip_method_invite) { return 200; } else { nta_reliable_t *rel; nta_incoming_bind(irq, test_for_ack_or_timeout, ag); rel = nta_reliable_treply(irq, process_prack, ag, SIP_183_SESSION_PROGRESS, SIPTAG_CONTENT_TYPE(ag->ag_content_type), SIPTAG_PAYLOAD(ag->ag_payload), SIPTAG_CONTACT(ag->ag_m_bob), TAG_END()); ag->ag_irq = irq; } END(); } /* * Test establishing a call with an early dialog / 100 rel / timeout * * Alice sends a INVITE to Bob, then Bob sends 183, Alice sends PRACK, * Bob sends 200 to PRACK, Bob sends 200 to INVITE. * Bob sends BYE, Alice 200. */ int test_prack(agent_t *ag) { BEGIN(); sip_content_type_t *ct = ag->ag_content_type; sip_payload_t *sdp = ag->ag_payload; nta_leg_t *old_leg; { /* Send a PRACK from default leg, NTA responds to it with error */ url_t url[1]; client_t ctx[1] = {{ ag, "Test 1.1" }}; *url = *ag->ag_aliases->m_url; url->url_user = "bob"; ag->ag_expect_leg = ag->ag_server_leg; ag->ag_latest_leg = NULL; ctx->c_orq = nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, ag->ag_obp, SIP_METHOD_PRACK, (url_string_t *)url, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_FROM(ag->ag_alice), SIPTAG_TO(ag->ag_bob), SIPTAG_CONTACT(ag->ag_m_alice), SIPTAG_RACK_STR("1432432 42332432 INVITE"), TAG_END()); TEST_1(!client_run(ctx, 481)); TEST_P(ag->ag_latest_leg, NULL); } ag->ag_alice_leg = nta_leg_tcreate(ag->ag_agent, alice_leg_callback, ag, SIPTAG_FROM(ag->ag_alice), SIPTAG_TO(ag->ag_bob), TAG_END()); TEST_1(ag->ag_alice_leg); TEST_1(nta_leg_tag(ag->ag_alice_leg, NULL)); /* Send INVITE */ { invite_client_t ic[1] = {{ {{ ag, "Call 2", NULL, checks_for_100rel, invite_client_deinit }} }}; client_t *ctx = ic->ic_client; nta_leg_bind(ag->ag_server_leg, bob_leg_callback2, ag); ag->ag_expect_leg = ag->ag_server_leg; ctx->c_orq = nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_alice_leg, outgoing_callback, ctx, ag->ag_obp, SIP_METHOD_INVITE, (url_string_t *)ag->ag_m_bob->m_url, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_CONTACT(ag->ag_m_alice), SIPTAG_REQUIRE_STR("100rel"), SIPTAG_CONTENT_TYPE(ct), SIPTAG_PAYLOAD(sdp), TAG_END()); TEST_1(!client_run_until_acked(ctx, 200)); /*TEST(ic->ic_tag_status, 183); */ TEST_P(ag->ag_latest_leg, ag->ag_server_leg); TEST_1(ag->ag_bob_leg != NULL); } { client_t ctx[1] = {{ ag, "Hangup" }}; /* Send BYE from Bob to Alice */ old_leg = ag->ag_expect_leg = ag->ag_alice_leg; ctx->c_orq = nta_outgoing_tcreate(ag->ag_bob_leg, outgoing_callback, ctx, NULL, SIP_METHOD_BYE, NULL, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_FROM(ag->ag_alice), SIPTAG_TO(ag->ag_bob), SIPTAG_CONTACT(ag->ag_m_alice), SIPTAG_CONTENT_TYPE(ct), SIPTAG_PAYLOAD(sdp), TAG_END()); TEST_1(!client_run(ctx, 200)); TEST_P(ag->ag_latest_leg, old_leg); TEST_P(ag->ag_alice_leg, NULL); } nta_leg_destroy(ag->ag_bob_leg), ag->ag_bob_leg = NULL; ag->ag_latest_leg = NULL; ag->ag_call_leg = NULL; /* Test CANCELing a call after receiving 100rel response */ ag->ag_alice_leg = nta_leg_tcreate(ag->ag_agent, alice_leg_callback, ag, SIPTAG_FROM(ag->ag_alice), SIPTAG_TO(ag->ag_bob), TAG_END()); TEST_1(ag->ag_alice_leg); TEST_1(nta_leg_tag(ag->ag_alice_leg, NULL)); { invite_client_t ic[1] = {{ {{ ag, "Call 2b", cancel_invite, checks_for_invite, invite_client_deinit }} }}; client_t *ctx = ic->ic_client; /* Send INVITE */ nta_leg_bind(ag->ag_server_leg, bob_leg_callback3, ag); ag->ag_expect_leg = ag->ag_server_leg; ctx->c_orq = nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_alice_leg, outgoing_callback, ctx, ag->ag_obp, SIP_METHOD_INVITE, (url_string_t *)ag->ag_m_bob->m_url, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_CONTACT(ag->ag_m_alice), SIPTAG_REQUIRE_STR("100rel"), SIPTAG_CONTENT_TYPE(ct), SIPTAG_PAYLOAD(sdp), TAG_END()); TEST_1(!client_run(ctx, 0)); } TEST_P(ag->ag_latest_leg, ag->ag_server_leg); TEST_1(ag->ag_bob_leg != NULL); nta_leg_destroy(ag->ag_bob_leg), ag->ag_bob_leg = NULL; ag->ag_latest_leg = NULL; ag->ag_call_leg = NULL; if (EXPENSIVE_CHECKS) { printf("%s: starting 100rel timeout test, test will complete in 4 seconds\n", name); TEST(nta_agent_set_params(ag->ag_agent, NTATAG_SIP_T1(25), NTATAG_SIP_T1X64(64 * 25), TAG_END()), 2); ag->ag_alice_leg = nta_leg_tcreate(ag->ag_agent, alice_leg_callback, ag, SIPTAG_FROM(ag->ag_alice), SIPTAG_TO(ag->ag_bob), TAG_END()); TEST_1(ag->ag_alice_leg); TEST_1(nta_leg_tag(ag->ag_alice_leg, NULL)); { invite_client_t ic[1] = {{ {{ ag, "Call 3", NULL, checks_for_invite, invite_client_deinit }} }}; client_t *ctx = ic->ic_client; /* Send INVITE, * send precious provisional response * do not send PRACK, * timeout (after 64 * t1 ~ 3.2 seconds), */ nta_leg_bind(ag->ag_server_leg, bob_leg_callback2, ag); ag->ag_expect_leg = ag->ag_server_leg; ctx->c_orq = nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_alice_leg, outgoing_callback, ctx, ag->ag_obp, SIP_METHOD_INVITE, (url_string_t *)ag->ag_m_bob->m_url, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_CONTACT(ag->ag_m_alice), SIPTAG_REQUIRE_STR("100rel"), SIPTAG_CONTENT_TYPE(ct), SIPTAG_PAYLOAD(sdp), TAG_END()); TEST_1(ctx->c_orq); nta_test_run(ag); TEST(ctx->c_status, 503); TEST_P(ctx->c_orq, NULL); TEST_P(ag->ag_latest_leg, ag->ag_server_leg); TEST_1(ag->ag_bob_leg == NULL); } TEST(nta_agent_set_params(ag->ag_agent, NTATAG_SIP_T1(500), NTATAG_SIP_T1X64(64 * 500), TAG_END()), 2); } if (EXPENSIVE_CHECKS || 1) { /* * client sends INVITE, * server sends provisional response, * client PRACKs it, * client timeouts after timer C */ invite_client_t ic[1] = {{ {{ ag, "Call 4", NULL, checks_for_100rel, invite_client_deinit }} }}; client_t *ctx = ic->ic_client; printf("%s: starting timer C, test will complete in 1 seconds\n", name); TEST(nta_agent_set_params(ag->ag_agent, NTATAG_TIMER_C(1000), TAG_END()), 1); TEST_1(ag->ag_alice_leg = nta_leg_tcreate(ag->ag_agent, alice_leg_callback, ag, SIPTAG_FROM(ag->ag_alice), SIPTAG_TO(ag->ag_bob), TAG_END())); TEST_1(nta_leg_tag(ag->ag_alice_leg, NULL)); nta_leg_bind(ag->ag_server_leg, bob_leg_callback3, ag); ag->ag_expect_leg = ag->ag_server_leg; TEST_1(ctx->c_orq = nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_alice_leg, outgoing_callback, ic->ic_client, ag->ag_obp, SIP_METHOD_INVITE, (url_string_t *)ag->ag_m_bob->m_url, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_CONTACT(ag->ag_m_alice), SIPTAG_REQUIRE_STR("100rel"), SIPTAG_CONTENT_TYPE(ct), SIPTAG_PAYLOAD(sdp), TAG_END())); /* Run until 1) server gets CANCEL and 2) client gets 408 */ TEST_1(!client_run_until_canceled(ctx, 408)); TEST_1(ag->ag_canceled != 0); TEST_P(ag->ag_latest_leg, ag->ag_server_leg); TEST_1(ag->ag_bob_leg); nta_leg_destroy(ag->ag_bob_leg), ag->ag_bob_leg = NULL; TEST(nta_agent_set_params(ag->ag_agent, NTATAG_TIMER_C(185 * 1000), TAG_END()), 1); nta_leg_destroy(ag->ag_bob_leg), ag->ag_bob_leg = NULL; ag->ag_latest_leg = NULL; ag->ag_call_leg = NULL; } END(); } int alice_leg_callback2(agent_t *ag, nta_leg_t *leg, nta_incoming_t *irq, sip_t const *sip) { BEGIN(); if (tstflags & tst_verbatim) { printf("%s: %s: %s " URL_PRINT_FORMAT " %s\n", name, __func__, sip->sip_request->rq_method_name, URL_PRINT_ARGS(sip->sip_request->rq_url), sip->sip_request->rq_version); } TEST_1(sip->sip_content_length); TEST_1(sip->sip_via); TEST_1(sip->sip_from && sip->sip_from->a_tag); if (sip->sip_request->rq_method == sip_method_prack) return 481; ag->ag_latest_leg = leg; if (leg != ag->ag_alice_leg) { leg_match(ag, leg, 1, __func__); return 500; } if (sip->sip_request->rq_method == sip_method_invite) { TEST_1(sip_has_feature(sip->sip_supported, "100rel")); nta_incoming_bind(irq, test_for_ack, ag); nta_incoming_treply(irq, SIP_100_TRYING, TAG_END()); nta_agent_set_params(ag->ag_agent, NTATAG_DEBUG_DROP_PROB(ag->ag_drop), TAG_END()); ag->ag_reliable = nta_reliable_treply(irq, NULL, NULL, SIP_183_SESSION_PROGRESS, SIPTAG_CONTENT_TYPE(ag->ag_content_type), SIPTAG_PAYLOAD(ag->ag_payload), SIPTAG_CONTACT(ag->ag_m_alice), TAG_END()); TEST_1(ag->ag_reliable); ag->ag_reliable = nta_reliable_treply(irq, NULL, NULL, 184, "Next", SIPTAG_CONTACT(ag->ag_m_alice), TAG_END()); TEST_1(ag->ag_reliable); ag->ag_reliable = nta_reliable_treply(irq, NULL, NULL, 185, "Last", SIPTAG_CONTACT(ag->ag_m_alice), TAG_END()); TEST_1(ag->ag_reliable); TEST(nta_incoming_treply(irq, SIP_200_OK, TAG_END()), 0); ag->ag_irq = irq; return 0; } if (sip->sip_request->rq_method == sip_method_bye) { leg_zap(ag, leg); } if(sip) return 200; END(); } /* * Test establishing a call with an early dialog / 100 rel / timeout * * Alice sends a INVITE to Bob, then Bob sends 183, 184, 185, and 200. * Bob sends BYE, Alice 200. * * See bug #467. */ int test_fix_467(agent_t *ag) { sip_content_type_t *ct = ag->ag_content_type; sip_payload_t *sdp = ag->ag_payload; nta_leg_t *old_leg; BEGIN(); ag->ag_alice_leg = nta_leg_tcreate(ag->ag_agent, alice_leg_callback2, ag, SIPTAG_FROM(ag->ag_alice), SIPTAG_TO(ag->ag_bob), TAG_END()); TEST_1(ag->ag_alice_leg); TEST_1(nta_leg_tag(ag->ag_alice_leg, NULL)); ag->ag_bob_leg = NULL; { invite_client_t ic[1] = {{ {{ ag, "Call 5", NULL, checks_for_100rel, invite_client_deinit }} }}; client_t *ctx = ic->ic_client; /* Send INVITE */ nta_leg_bind(ag->ag_server_leg, bob_leg_callback2, ag); ag->ag_expect_leg = ag->ag_server_leg; ctx->c_orq = nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_alice_leg, outgoing_callback, ic->ic_client, ag->ag_obp, SIP_METHOD_INVITE, (url_string_t *)ag->ag_m_bob->m_url, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_CONTACT(ag->ag_m_alice), SIPTAG_REQUIRE_STR("100rel"), SIPTAG_CONTENT_TYPE(ct), SIPTAG_PAYLOAD(sdp), TAG_END()); TEST_1(!client_run(ctx, 200)); /*TEST(ag->ag_tag_status, 183);*/ TEST_P(ag->ag_latest_leg, ag->ag_server_leg); TEST_1(ag->ag_bob_leg != NULL); } old_leg = ag->ag_expect_leg = ag->ag_alice_leg; { client_t ctx[1] = {{ ag, "Hangup" }}; /* Send BYE from Bob to Alice */ ctx->c_orq = nta_outgoing_tcreate(ag->ag_bob_leg, outgoing_callback, ctx, NULL, SIP_METHOD_BYE, NULL, SIPTAG_SUBJECT_STR(ctx->c_name), SIPTAG_FROM(ag->ag_alice), SIPTAG_TO(ag->ag_bob), SIPTAG_CONTACT(ag->ag_m_alice), SIPTAG_CONTENT_TYPE(ct), SIPTAG_PAYLOAD(sdp), TAG_END()); TEST_1(!client_run(ctx, 200)); TEST_P(ag->ag_latest_leg, old_leg); TEST_P(ag->ag_alice_leg, NULL); } END(); /* nta_leg_destroy(ag->ag_bob_leg), ag->ag_bob_leg = NULL; ag->ag_latest_leg = NULL; ag->ag_call_leg = NULL; */ } #if HAVE_ALARM #include #include static RETSIGTYPE sig_alarm(int s) { fprintf(stderr, "%s: FAIL! test timeout!\n", name); exit(1); } #endif static char const nta_test_usage[] = "usage: %s OPTIONS\n" "where OPTIONS are\n" " -v | --verbose be verbose\n" " -a | --abort abort() on error\n" " -q | --quiet be quiet\n" " --expensive run expensive tests, too\n" " -1 quit on first error\n" " -l level set logging level (0 by default)\n" " -p uri specify uri of outbound proxy\n" " -m uri bind to local uri\n" " --attach print pid, wait for a debugger to be attached\n" #if HAVE_ALARM " --no-alarm don't ask for guard ALARM\n" #endif ; void usage(int exitcode) { fprintf(stderr, nta_test_usage, name); exit(exitcode); } #if HAVE_OPEN_C int posix_main(int argc, char *argv[]); int main(int argc, char *argv[]) { int retval; tstflags |= tst_verbatim; su_log_set_level(su_log_default, 9); su_log_set_level(nta_log, 9); su_log_set_level(tport_log, 9); retval = posix_main(argc, argv); sleep(7); return retval; } #define main posix_main #endif int main(int argc, char *argv[]) { int retval = 0, quit_on_single_failure = 0; int i, o_attach = 0, o_alarm = 1; agent_t ag[1] = {{ { SU_HOME_INIT(ag) }, 0, NULL }}; expensive_checks = getenv("EXPENSIVE_CHECKS") != NULL; for (i = 1; argv[i]; i++) { if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbose") == 0) tstflags |= tst_verbatim; else if (strcmp(argv[i], "-a") == 0 || strcmp(argv[i], "--abort") == 0) tstflags |= tst_abort; else if (strcmp(argv[i], "-q") == 0 || strcmp(argv[i], "--quiet") == 0) tstflags &= ~tst_verbatim; else if (strcmp(argv[i], "--expensive") == 0) expensive_checks = 1; else if (strcmp(argv[i], "-1") == 0) quit_on_single_failure = 1; else if (strncmp(argv[i], "-l", 2) == 0) { int level = 3; char *rest = NULL; if (argv[i][2]) level = strtol(argv[i] + 2, &rest, 10); else if (argv[i + 1]) level = strtol(argv[i + 1], &rest, 10), i++; else level = 3, rest = ""; if (rest == NULL || *rest) usage(1); su_log_set_level(nta_log, level); su_log_set_level(tport_log, level); } else if (strncmp(argv[i], "-p", 2) == 0) { if (argv[i][2]) ag->ag_obp = (url_string_t *)(argv[i] + 2); else if (argv[i + 1]) ag->ag_obp = (url_string_t *)(argv[++i]); else usage(1); } else if (strncmp(argv[i], "-m", 2) == 0) { if (argv[i][2]) ag->ag_m = argv[i] + 2; else if (argv[i + 1]) ag->ag_m = argv[++i]; else usage(1); } else if (strcmp(argv[i], "--attach") == 0) { o_attach = 1; } else if (strcmp(argv[i], "--no-alarm") == 0) { o_alarm = 0; } else if (strcmp(argv[i], "-") == 0) { i++; break; } else if (argv[i][0] != '-') { break; } else usage(1); } if (o_attach) { char line[10], *got; printf("nua_test: pid %u\n", getpid()); printf("\n"); got = fgets(line, sizeof line, stdin); (void)got; } #if HAVE_ALARM else if (o_alarm) { alarm(60); signal(SIGALRM, sig_alarm); } #endif su_init(); if (!(TSTFLAGS & tst_verbatim)) { su_log_soft_set_level(nta_log, 0); su_log_soft_set_level(tport_log, 0); } #define SINGLE_FAILURE_CHECK() \ do { fflush(stdout); \ if (retval && quit_on_single_failure) { su_deinit(); return retval; } \ } while(0) retval |= test_init(ag, argv[i]); SINGLE_FAILURE_CHECK(); if (retval == 0) { retval |= test_bad_messages(ag); SINGLE_FAILURE_CHECK(); retval |= test_reinit(ag); SINGLE_FAILURE_CHECK(); retval |= test_tports(ag); SINGLE_FAILURE_CHECK(); retval |= test_destroy_incoming(ag); SINGLE_FAILURE_CHECK(); retval |= test_resolv(ag, argv[i]); SINGLE_FAILURE_CHECK(); retval |= test_routing(ag); SINGLE_FAILURE_CHECK(); retval |= test_dialog(ag); SINGLE_FAILURE_CHECK(); retval |= test_call(ag); SINGLE_FAILURE_CHECK(); retval |= test_prack(ag); SINGLE_FAILURE_CHECK(); retval |= test_fix_467(ag); SINGLE_FAILURE_CHECK(); } retval |= test_deinit(ag); fflush(stdout); su_home_deinit(ag->ag_home); su_deinit(); return retval; }