forked from Mirrors/freeswitch
094de86372
* tport.c: add TPTAG_LOG() and TPTAG_DUMP() to tport_get_params() Fixed return value from tport_set_params(), too. git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@12374 d0543943-73ff-0310-b7d9-9358b9ac24b2
1707 lines
42 KiB
C
1707 lines
42 KiB
C
/*
|
|
* This file is part of the Sofia-SIP package
|
|
*
|
|
* Copyright (C) 2006 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 tport_test.c
|
|
*
|
|
* Test functions for transports
|
|
*
|
|
* @internal
|
|
*
|
|
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
|
|
*
|
|
* @date Created: Wed Apr 3 11:25:13 2002 ppessi
|
|
*/
|
|
|
|
/* always assert()s */
|
|
#undef NDEBUG
|
|
|
|
#include "config.h"
|
|
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <limits.h>
|
|
#include <stdio.h>
|
|
#include <assert.h>
|
|
|
|
typedef struct tp_test_s tp_test_t;
|
|
|
|
#define TP_STACK_T tp_test_t
|
|
#define TP_CLIENT_T struct called
|
|
|
|
#include <sofia-sip/su_wait.h>
|
|
#include <sofia-sip/su_md5.h>
|
|
|
|
#include "tport_internal.h" /* Get SU_DEBUG_*() */
|
|
|
|
#include "test_class.h"
|
|
#include "test_protos.h"
|
|
#include "sofia-sip/msg.h"
|
|
#include "sofia-sip/msg_mclass.h"
|
|
#include "sofia-sip/msg_addr.h"
|
|
|
|
#if HAVE_SIGCOMP
|
|
#include <sigcomp.h>
|
|
#endif
|
|
|
|
#include <sofia-sip/base64.h>
|
|
|
|
#include <sofia-sip/su_log.h>
|
|
|
|
#include "sofia-sip/tport.h"
|
|
|
|
struct tp_test_s {
|
|
su_home_t tt_home[1];
|
|
int tt_flags;
|
|
su_root_t *tt_root;
|
|
msg_mclass_t *tt_mclass;
|
|
tport_t *tt_srv_tports;
|
|
tport_t *tt_tports;
|
|
|
|
tport_t *tt_rtport;
|
|
|
|
tp_name_t tt_udp_name[1];
|
|
tp_name_t tt_udp_comp[1];
|
|
|
|
tp_name_t tt_tcp_name[1];
|
|
tp_name_t tt_tcp_comp[1];
|
|
|
|
tp_name_t tt_sctp_name[1];
|
|
tp_name_t tt_sctp_comp[1];
|
|
|
|
tp_name_t tt_tls_name[1];
|
|
tp_name_t tt_tls_comp[1];
|
|
|
|
#if HAVE_SIGCOMP
|
|
struct sigcomp_state_handler *state_handler;
|
|
struct sigcomp_algorithm const *algorithm;
|
|
struct sigcomp_compartment *master_cc;
|
|
|
|
#define IF_SIGCOMP_TPTAG_COMPARTMENT(cc) TAG_IF(cc, TPTAG_COMPARTMENT(cc)),
|
|
#else
|
|
#define IF_SIGCOMP_TPTAG_COMPARTMENT(cc)
|
|
#endif
|
|
|
|
int tt_status;
|
|
int tt_received;
|
|
msg_t *tt_rmsg;
|
|
uint8_t tt_digest[SU_MD5_DIGEST_SIZE];
|
|
|
|
su_addrinfo_t const *tt_tcp_addr;
|
|
tport_t *tt_tcp;
|
|
};
|
|
|
|
int tstflags;
|
|
#define TSTFLAGS tstflags
|
|
|
|
#include <sofia-sip/tstdef.h>
|
|
|
|
char const name[] = "tport_test";
|
|
|
|
SOFIAPUBVAR su_log_t tport_log[];
|
|
|
|
static int name_test(tp_test_t *tt)
|
|
{
|
|
tp_name_t tpn[1];
|
|
|
|
su_home_t home[1] = { SU_HOME_INIT(home) };
|
|
|
|
su_sockaddr_t su[1];
|
|
|
|
BEGIN();
|
|
|
|
memset(su, 0, sizeof su);
|
|
|
|
su->su_port = htons(5060);
|
|
su->su_family = AF_INET;
|
|
|
|
TEST(tport_convert_addr(home, tpn, "tcp", "localhost", su), 0);
|
|
|
|
su->su_family = AF_INET;
|
|
|
|
TEST(tport_convert_addr(home, tpn, "tcp", "localhost", su), 0);
|
|
|
|
#if SU_HAVE_IN6
|
|
su->su_family = AF_INET6;
|
|
TEST(tport_convert_addr(home, tpn, "tcp", "localhost", su), 0);
|
|
#endif
|
|
|
|
END();
|
|
}
|
|
|
|
/* Count number of transports in chain */
|
|
static
|
|
int count_tports(tport_t *tp)
|
|
{
|
|
int n = 0;
|
|
|
|
for (tp = tport_primaries(tp); tp; tp = tport_next(tp))
|
|
n++;
|
|
|
|
return n;
|
|
}
|
|
|
|
static int check_msg(tp_test_t *tt, msg_t *msg, char const *ident)
|
|
{
|
|
msg_test_t *tst;
|
|
msg_payload_t *pl;
|
|
usize_t i, len;
|
|
|
|
BEGIN();
|
|
|
|
TEST_1(tst = msg_test_public(msg));
|
|
TEST_1(pl = tst->msg_payload);
|
|
|
|
if (ident) {
|
|
if (!tst->msg_content_location ||
|
|
strcmp(ident, tst->msg_content_location->g_string))
|
|
return 1;
|
|
}
|
|
|
|
len = pl->pl_len;
|
|
|
|
for (i = 0; i < len; i++) {
|
|
if (pl->pl_data[i] != (char) (i % 240))
|
|
break;
|
|
}
|
|
|
|
if (pl)
|
|
return i != len;
|
|
|
|
END();
|
|
}
|
|
|
|
static int test_create_md5(tp_test_t *tt, msg_t *msg)
|
|
{
|
|
msg_test_t *tst;
|
|
msg_payload_t *pl;
|
|
su_md5_t md5[1];
|
|
|
|
BEGIN();
|
|
|
|
TEST_1(tst = msg_test_public(msg));
|
|
TEST_1(pl = tst->msg_payload);
|
|
|
|
su_md5_init(md5);
|
|
su_md5_update(md5, pl->pl_data, pl->pl_len);
|
|
su_md5_digest(md5, tt->tt_digest);
|
|
|
|
END();
|
|
}
|
|
|
|
static int test_check_md5(tp_test_t *tt, msg_t *msg)
|
|
{
|
|
msg_test_t *tst;
|
|
msg_payload_t *pl;
|
|
su_md5_t md5[1];
|
|
uint8_t digest[SU_MD5_DIGEST_SIZE];
|
|
|
|
BEGIN();
|
|
|
|
TEST_1(tst = msg_test_public(msg));
|
|
TEST_1(pl = tst->msg_payload);
|
|
|
|
su_md5_init(md5);
|
|
su_md5_update(md5, pl->pl_data, pl->pl_len);
|
|
su_md5_digest(md5, digest);
|
|
|
|
TEST(memcmp(digest, tt->tt_digest, sizeof digest), 0);
|
|
|
|
END();
|
|
}
|
|
|
|
static int test_msg_md5(tp_test_t *tt, msg_t *msg)
|
|
{
|
|
msg_test_t *tst;
|
|
|
|
BEGIN();
|
|
|
|
TEST_1(tst = msg_test_public(msg));
|
|
|
|
if (tst->msg_content_md5) {
|
|
su_md5_t md5sum[1];
|
|
uint8_t digest[SU_MD5_DIGEST_SIZE];
|
|
char b64[BASE64_SIZE(SU_MD5_DIGEST_SIZE) + 1];
|
|
|
|
msg_payload_t *pl =tst->msg_payload;
|
|
|
|
su_md5_init(md5sum);
|
|
su_md5_update(md5sum, pl->pl_data, pl->pl_len);
|
|
su_md5_digest(md5sum, digest);
|
|
|
|
base64_e(b64, sizeof(b64), digest, sizeof(digest));
|
|
|
|
if (strcmp(b64, tst->msg_content_md5->g_string)) {
|
|
;
|
|
}
|
|
|
|
TEST_S(b64, tst->msg_content_md5->g_string);
|
|
} else {
|
|
TEST_1(tst->msg_content_md5);
|
|
}
|
|
|
|
END();
|
|
}
|
|
|
|
#define TPORT_TEST_VERSION MSG_TEST_VERSION_CURRENT
|
|
|
|
static int new_test_msg(tp_test_t *tt, msg_t **retval,
|
|
char const *ident,
|
|
int N, int len)
|
|
{
|
|
msg_t *msg;
|
|
msg_test_t *tst;
|
|
su_home_t *home;
|
|
msg_request_t *rq;
|
|
msg_unknown_t *u;
|
|
msg_content_location_t *cl;
|
|
msg_content_md5_t *md5;
|
|
msg_content_length_t *l;
|
|
msg_separator_t *sep;
|
|
msg_payload_t payload[1];
|
|
msg_header_t *h;
|
|
int i;
|
|
|
|
su_md5_t md5sum[1];
|
|
uint8_t digest[SU_MD5_DIGEST_SIZE];
|
|
char b64[BASE64_SIZE(SU_MD5_DIGEST_SIZE) + 1];
|
|
|
|
BEGIN();
|
|
|
|
TEST_1(msg = msg_create(tt->tt_mclass, 0));
|
|
TEST_1(tst = msg_test_public(msg));
|
|
TEST_1(home = msg_home(msg));
|
|
|
|
TEST_SIZE(msg_maxsize(msg, 1024 + N * len), 0);
|
|
|
|
TEST_1(rq = msg_request_make(home, "DO im:foo@faa " TPORT_TEST_VERSION));
|
|
TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)rq), 0);
|
|
|
|
TEST_1(u = msg_unknown_make(home, "Foo: faa"));
|
|
TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)u), 0);
|
|
|
|
TEST_1(u = msg_unknown_make(home, "Foo: faa"));
|
|
TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)u), 0);
|
|
|
|
if (ident) {
|
|
TEST_1(cl = msg_content_location_make(home, ident));
|
|
TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)cl), 0);
|
|
}
|
|
|
|
msg_payload_init(payload);
|
|
|
|
payload->pl_len = len;
|
|
TEST_1(payload->pl_data = su_zalloc(home, payload->pl_len));
|
|
|
|
for (i = 0; i < len; i++) {
|
|
payload->pl_data[i] = (char) (i % 240);
|
|
}
|
|
|
|
su_md5_init(md5sum);
|
|
|
|
for (i = 0; i < N; i++) {
|
|
h = msg_header_dup(home, (msg_header_t*)payload);
|
|
TEST_1(h);
|
|
TEST(msg_header_insert(msg, (void *)tst, h), 0);
|
|
su_md5_update(md5sum, payload->pl_data, payload->pl_len);
|
|
}
|
|
|
|
TEST_1(l = msg_content_length_format(home, MOD_ZU, (size_t)(N * payload->pl_len)));
|
|
TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)l), 0);
|
|
|
|
su_md5_digest(md5sum, digest);
|
|
|
|
base64_e(b64, sizeof(b64), digest, sizeof(digest));
|
|
|
|
TEST_1(md5 = msg_content_md5_make(home, b64));
|
|
TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)md5), 0);
|
|
|
|
TEST_1(sep = msg_separator_create(home));
|
|
TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)sep), 0);
|
|
|
|
TEST(msg_serialize(msg, (void *)tst), 0);
|
|
|
|
*retval = msg;
|
|
|
|
END();
|
|
}
|
|
|
|
static
|
|
struct sigcomp_compartment *
|
|
test_sigcomp_compartment(tp_test_t *tt, tport_t *tp, tp_name_t const *tpn);
|
|
|
|
static void tp_test_recv(tp_test_t *tt,
|
|
tport_t *tp,
|
|
msg_t *msg,
|
|
tp_magic_t *magic,
|
|
su_time_t now)
|
|
{
|
|
tp_name_t frm[1];
|
|
|
|
if (tport_delivered_from(tp, msg, frm) != -1 && frm->tpn_comp) {
|
|
struct sigcomp_compartment *cc = test_sigcomp_compartment(tt, tp, frm);
|
|
|
|
tport_sigcomp_accept(tp, cc, msg);
|
|
}
|
|
|
|
tt->tt_status = 1;
|
|
tt->tt_received++;
|
|
|
|
if (msg_has_error(msg)) {
|
|
tt->tt_status = -1;
|
|
tt->tt_rtport = tp;
|
|
}
|
|
else if (test_msg_md5(tt, msg))
|
|
msg_destroy(msg);
|
|
else if (tt->tt_rmsg)
|
|
msg_destroy(msg);
|
|
else {
|
|
tt->tt_rmsg = msg;
|
|
tt->tt_rtport = tp;
|
|
}
|
|
}
|
|
|
|
static void tp_test_error(tp_test_t *tt,
|
|
tport_t *tp,
|
|
int errcode,
|
|
char const *remote)
|
|
{
|
|
tt->tt_status = -1;
|
|
fprintf(stderr, "tp_test_error(%p): error %d (%s) from %s\n",
|
|
(void *)tp, errcode, su_strerror(errcode),
|
|
remote ? remote : "<unknown destination>");
|
|
}
|
|
|
|
msg_t *tp_test_msg(tp_test_t *tt, int flags,
|
|
char const data[], usize_t size,
|
|
tport_t const *tp,
|
|
tp_client_t *tpc)
|
|
{
|
|
msg_t *msg = msg_create(tt->tt_mclass, flags);
|
|
|
|
msg_maxsize(msg, 2 * 1024 * 1024);
|
|
|
|
return msg;
|
|
}
|
|
|
|
|
|
static
|
|
struct sigcomp_compartment *
|
|
test_sigcomp_compartment(tp_test_t *tt,
|
|
tport_t *tp,
|
|
tp_name_t const *tpn)
|
|
{
|
|
struct sigcomp_compartment *cc = NULL;
|
|
#if HAVE_SIGCOMP
|
|
char name[256];
|
|
int namesize;
|
|
|
|
namesize = snprintf(name, sizeof name, "TEST_%s/%s:%s",
|
|
tpn->tpn_proto,
|
|
tpn->tpn_host,
|
|
tpn->tpn_port);
|
|
|
|
if (namesize <= 0 || namesize >= sizeof name)
|
|
return NULL;
|
|
|
|
cc = sigcomp_compartment_access(tt->state_handler,
|
|
0, name, namesize, NULL, 0);
|
|
|
|
if (cc == NULL) {
|
|
cc = sigcomp_compartment_create(tt->algorithm, tt->state_handler,
|
|
0, name, namesize, NULL, 0);
|
|
|
|
sigcomp_compartment_option(cc, "dms=32768");
|
|
}
|
|
#endif
|
|
|
|
return cc;
|
|
}
|
|
|
|
/* Accept/reject early SigComp message */
|
|
int test_sigcomp_accept(tp_stack_t *tt, tport_t *tp, msg_t *msg)
|
|
{
|
|
struct sigcomp_compartment *cc = NULL;
|
|
|
|
cc = test_sigcomp_compartment(tt, tp, tport_name(tp));
|
|
|
|
if (cc)
|
|
tport_sigcomp_assign(tp, cc);
|
|
|
|
return tport_sigcomp_accept(tp, cc, msg);
|
|
}
|
|
|
|
|
|
tp_stack_class_t const tp_test_class[1] =
|
|
{{
|
|
/* tpac_size */ sizeof(tp_test_class),
|
|
/* tpac_recv */ tp_test_recv,
|
|
/* tpac_error */ tp_test_error,
|
|
/* tpac_alloc */ tp_test_msg,
|
|
}};
|
|
|
|
static int init_test(tp_test_t *tt)
|
|
{
|
|
tp_name_t myname[1] = {{ "*", "*", "*", "*", "sigcomp" }};
|
|
#if HAVE_SCTP
|
|
char const * transports[] = { "udp", "tcp", "sctp", NULL };
|
|
#else
|
|
char const * transports[] = { "udp", "tcp", NULL };
|
|
#endif
|
|
tp_name_t const *tpn;
|
|
tport_t *tp;
|
|
unsigned idle;
|
|
int logging = -1;
|
|
|
|
BEGIN();
|
|
|
|
int mask = AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST;
|
|
|
|
#ifdef AI_ALL
|
|
mask |= AI_ALL;
|
|
#endif
|
|
#ifdef AI_V4MAPPED_CFG
|
|
mask |= AI_V4MAPPED_CFG;
|
|
#endif
|
|
#ifdef AI_ADDRCONFIG
|
|
mask |= AI_ADDRCONFIG;
|
|
#endif
|
|
#ifdef AI_V4MAPPED
|
|
mask |= AI_V4MAPPED;
|
|
#endif
|
|
|
|
/* Test that we have no common flags with underlying getaddrinfo() */
|
|
TEST(mask & TP_AI_MASK, 0);
|
|
|
|
TEST_1(tt->tt_root = su_root_create(NULL));
|
|
|
|
myname->tpn_host = "127.0.0.1";
|
|
myname->tpn_ident = "client";
|
|
|
|
/* Create message class */
|
|
TEST_1(tt->tt_mclass = msg_mclass_clone(msg_test_mclass, 0, 0));
|
|
|
|
/* Try to insert Content-Length header (expecting failure) */
|
|
TEST(msg_mclass_insert(tt->tt_mclass, msg_content_length_href), -1);
|
|
|
|
#if HAVE_SIGCOMP
|
|
TEST_1(tt->state_handler = sigcomp_state_handler_create());
|
|
TEST_1(tt->algorithm =
|
|
sigcomp_algorithm_by_name(getenv("SIGCOMP_ALGORITHM")));
|
|
TEST_1(tt->master_cc =
|
|
sigcomp_compartment_create(tt->algorithm, tt->state_handler,
|
|
0, "", 0, NULL, 0));
|
|
TEST(sigcomp_compartment_option(tt->master_cc, "stateless"), 1);
|
|
#endif
|
|
|
|
/* Create client transport */
|
|
TEST_1(tt->tt_tports =
|
|
tport_tcreate(tt, tp_test_class, tt->tt_root,
|
|
IF_SIGCOMP_TPTAG_COMPARTMENT(tt->master_cc)
|
|
TAG_END()));
|
|
|
|
/* Bind client transports */
|
|
TEST(tport_tbind(tt->tt_tports, myname, transports,
|
|
TPTAG_SERVER(0), TAG_END()),
|
|
0);
|
|
|
|
if (getenv("TPORT_TEST_HOST"))
|
|
myname->tpn_host = getenv("TPORT_TEST_HOST");
|
|
else
|
|
myname->tpn_host = "*";
|
|
|
|
if (getenv("TPORT_TEST_PORT"))
|
|
myname->tpn_port = getenv("TPORT_TEST_PORT");
|
|
|
|
myname->tpn_ident = "server";
|
|
|
|
/* Create server transport */
|
|
TEST_1(tt->tt_srv_tports =
|
|
tport_tcreate(tt, tp_test_class, tt->tt_root,
|
|
IF_SIGCOMP_TPTAG_COMPARTMENT(tt->master_cc)
|
|
TAG_END()));
|
|
|
|
/* Bind server transports */
|
|
TEST(tport_tbind(tt->tt_srv_tports, myname, transports,
|
|
TPTAG_SERVER(1),
|
|
TAG_END()),
|
|
0);
|
|
|
|
/* Check that the master transport has idle parameter */
|
|
TEST(tport_get_params(tt->tt_srv_tports,
|
|
TPTAG_IDLE_REF(idle),
|
|
TAG_END()), 1);
|
|
|
|
/* Check that logging tag works */
|
|
TEST(tport_get_params(tt->tt_srv_tports,
|
|
TPTAG_LOG_REF(logging),
|
|
TAG_END()), 1);
|
|
TEST(tport_set_params(tt->tt_srv_tports,
|
|
TPTAG_LOG(logging),
|
|
TAG_END()), 1);
|
|
|
|
|
|
for (tp = tport_primaries(tt->tt_srv_tports); tp; tp = tport_next(tp))
|
|
TEST_S(tport_name(tp)->tpn_ident, "server");
|
|
|
|
{
|
|
su_sockaddr_t su[1];
|
|
socklen_t sulen;
|
|
int s;
|
|
int i, before, after;
|
|
char port[8];
|
|
|
|
tp_name_t rname[1];
|
|
|
|
*rname = *myname;
|
|
|
|
/* Check that we cannot bind to an already used socket */
|
|
|
|
memset(su, 0, sulen = sizeof(su->su_sin));
|
|
s = su_socket(su->su_family = AF_INET, SOCK_STREAM, 0); TEST_1(s != -1);
|
|
TEST_1(bind(s, &su->su_sa, sulen) != -1);
|
|
TEST_1(listen(s, 5) != -1);
|
|
TEST_1(getsockname(s, &su->su_sa, &sulen) != -1);
|
|
|
|
sprintf(port, "%u", ntohs(su->su_port));
|
|
|
|
rname->tpn_port = port;
|
|
rname->tpn_ident = "failure";
|
|
|
|
before = count_tports(tt->tt_srv_tports);
|
|
|
|
/* Bind server transports to an reserved port - this should fail */
|
|
TEST(tport_tbind(tt->tt_srv_tports, rname, transports,
|
|
TPTAG_SERVER(1),
|
|
TAG_END()),
|
|
-1);
|
|
|
|
after = count_tports(tt->tt_srv_tports);
|
|
|
|
/* Check that no new primary transports has been added by failed call */
|
|
TEST(before, after);
|
|
|
|
/* Add new transports to an ephemeral port with new identity */
|
|
|
|
for (tp = tport_primaries(tt->tt_srv_tports); tp; tp = tport_next(tp))
|
|
TEST_S(tport_name(tp)->tpn_ident, "server");
|
|
|
|
rname->tpn_port = "*";
|
|
rname->tpn_ident = "server2";
|
|
|
|
/* Bind server transports to another port */
|
|
TEST(tport_tbind(tt->tt_srv_tports, rname, transports,
|
|
TPTAG_SERVER(1),
|
|
TAG_END()),
|
|
0);
|
|
|
|
/* Check that new transports are after old ones. */
|
|
for (i = 0, tp = tport_primaries(tt->tt_srv_tports);
|
|
i < before;
|
|
i++, tp = tport_next(tp))
|
|
TEST_S(tport_name(tp)->tpn_ident, "server");
|
|
|
|
for (; tp; tp = tport_next(tp))
|
|
TEST_S(tport_name(tp)->tpn_ident, "server2");
|
|
}
|
|
|
|
#if HAVE_TLS
|
|
{
|
|
tp_name_t tlsname[1] = {{ "tls", "*", "*", "*", NULL }};
|
|
char const * transports[] = { "tls", NULL };
|
|
|
|
char const *srcdir = getenv("srcdir");
|
|
|
|
if (srcdir == NULL)
|
|
srcdir = ".";
|
|
|
|
tlsname->tpn_host = myname->tpn_host;
|
|
tlsname->tpn_ident = "server";
|
|
|
|
/* Bind client transports */
|
|
TEST(tport_tbind(tt->tt_tports, tlsname, transports,
|
|
TPTAG_SERVER(0),
|
|
TPTAG_CERTIFICATE(srcdir),
|
|
TAG_END()),
|
|
0);
|
|
|
|
/* Bind tls server transport */
|
|
TEST(tport_tbind(tt->tt_srv_tports, tlsname, transports,
|
|
TPTAG_SERVER(1),
|
|
TPTAG_CERTIFICATE(srcdir),
|
|
TAG_END()),
|
|
0);
|
|
}
|
|
#endif
|
|
|
|
for (tp = tport_primaries(tt->tt_srv_tports); tp; tp = tport_next(tp)) {
|
|
TEST_1(tpn = tport_name(tp));
|
|
|
|
if (tt->tt_flags & tst_verbatim) {
|
|
char const *host = tpn->tpn_host != tpn->tpn_canon ? tpn->tpn_host : "";
|
|
printf("bound transport to %s/%s:%s%s%s%s%s\n",
|
|
tpn->tpn_proto, tpn->tpn_canon, tpn->tpn_port,
|
|
host[0] ? ";maddr=" : "", host,
|
|
tpn->tpn_comp ? ";comp=" : "",
|
|
tpn->tpn_comp ? tpn->tpn_comp : "");
|
|
}
|
|
|
|
/* Ignore server2 tports for now */
|
|
if (strcmp(tpn->tpn_ident, "server"))
|
|
continue;
|
|
|
|
if (strcmp(tpn->tpn_proto, "udp") == 0) {
|
|
*tt->tt_udp_name = *tpn;
|
|
tt->tt_udp_name->tpn_comp = NULL;
|
|
tt->tt_udp_name->tpn_ident = NULL;
|
|
*tt->tt_udp_comp = *tpn;
|
|
tt->tt_udp_comp->tpn_ident = NULL;
|
|
}
|
|
else if (strcmp(tpn->tpn_proto, "tcp") == 0) {
|
|
*tt->tt_tcp_name = *tpn;
|
|
tt->tt_tcp_name->tpn_comp = NULL;
|
|
tt->tt_tcp_name->tpn_ident = NULL;
|
|
*tt->tt_tcp_comp = *tpn;
|
|
tt->tt_tcp_comp->tpn_ident = NULL;
|
|
|
|
if (tt->tt_tcp_addr == NULL) {
|
|
tt->tt_tcp_addr = tport_get_address(tp);
|
|
tt->tt_tcp = tp;
|
|
}
|
|
}
|
|
else if (strcmp(tpn->tpn_proto, "sctp") == 0) {
|
|
*tt->tt_sctp_name = *tpn;
|
|
tt->tt_sctp_name->tpn_ident = NULL;
|
|
}
|
|
else if (strcmp(tpn->tpn_proto, "tls") == 0) {
|
|
*tt->tt_tls_name = *tpn;
|
|
tt->tt_tls_name->tpn_ident = NULL;
|
|
}
|
|
}
|
|
|
|
END();
|
|
}
|
|
|
|
char const payload[] =
|
|
"Some data\n"
|
|
"More data\n";
|
|
|
|
#include <time.h>
|
|
|
|
int
|
|
tport_test_run(tp_test_t *tt, unsigned timeout)
|
|
{
|
|
time_t now = time(NULL);
|
|
|
|
tt->tt_status = 0;
|
|
|
|
msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
|
|
tt->tt_rtport = NULL;
|
|
|
|
while (!tt->tt_status) {
|
|
if (tt->tt_flags & tst_verbatim) {
|
|
fputs(".", stdout); fflush(stdout);
|
|
}
|
|
su_root_step(tt->tt_root, 500L);
|
|
|
|
if (!getenv("TPORT_TEST_DEBUG") &&
|
|
time(NULL) > (time_t)(now + timeout))
|
|
return 0;
|
|
}
|
|
|
|
return tt->tt_status;
|
|
}
|
|
|
|
static int udp_test(tp_test_t *tt)
|
|
{
|
|
tport_t *tp;
|
|
msg_t *msg;
|
|
msg_test_t *tst;
|
|
su_home_t *home;
|
|
msg_request_t *rq;
|
|
msg_unknown_t *u;
|
|
msg_content_length_t *l;
|
|
msg_content_md5_t *md5;
|
|
msg_separator_t *sep;
|
|
msg_payload_t *pl;
|
|
|
|
BEGIN();
|
|
|
|
TEST_1(msg = msg_create(tt->tt_mclass, 0));
|
|
TEST_1(tst = msg_test_public(msg));
|
|
TEST_1(home = msg_home(msg));
|
|
|
|
TEST_1(rq = msg_request_make(home, "DO im:foo@faa " TPORT_TEST_VERSION));
|
|
TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)rq), 0);
|
|
|
|
TEST_1(u = msg_unknown_make(home, "Foo: faa"));
|
|
TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)u), 0);
|
|
|
|
TEST_1(pl = msg_payload_make(home, payload));
|
|
TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)pl), 0);
|
|
|
|
TEST_1(l = msg_content_length_format(home, MOD_ZU, (size_t)pl->pl_len));
|
|
TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)l), 0);
|
|
|
|
TEST_1(md5 = msg_content_md5_make(home, "R6nitdrtJFpxYzrPaSXfrA=="));
|
|
TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)md5), 0);
|
|
|
|
TEST_1(sep = msg_separator_create(home));
|
|
TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)sep), 0);
|
|
|
|
TEST(msg_serialize(msg, (void *)tst), 0);
|
|
|
|
TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_udp_name, TAG_END()));
|
|
|
|
TEST_S(tport_name(tp)->tpn_ident, "client");
|
|
|
|
TEST(tport_test_run(tt, 5), 1);
|
|
|
|
msg_destroy(msg);
|
|
|
|
#if 0
|
|
tp_name_t tpn[1] = {{ NULL }};
|
|
|
|
TEST_1(msg = tt->tt_rmsg); tt->tt_rmsg = NULL;
|
|
|
|
TEST_1(home = msg_home(msg));
|
|
|
|
TEST_1(tport_convert_addr(home, tpn, "udp", NULL, msg_addr(msg)) == 0);
|
|
|
|
tpn->tpn_comp = tport_name(tt->tt_rtport)->tpn_comp;
|
|
|
|
/* reply */
|
|
TEST_1(tport_tsend(tt->tt_rtport, msg, tpn, TAG_END()) != NULL);
|
|
|
|
msg_destroy(msg);
|
|
|
|
TEST(tport_test_run(tt, 5), 1);
|
|
|
|
msg_destroy(msg);
|
|
#endif
|
|
|
|
msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
|
|
|
|
END();
|
|
}
|
|
|
|
int pending_server_close, pending_client_close;
|
|
|
|
void server_closed_callback(tp_stack_t *tt, tp_client_t *client,
|
|
tport_t *tp, msg_t *msg, int error)
|
|
{
|
|
assert(msg == NULL);
|
|
assert(client == NULL);
|
|
if (msg == NULL) {
|
|
tport_release(tp, pending_server_close, NULL, NULL, client, 0);
|
|
pending_server_close = 0;
|
|
}
|
|
}
|
|
|
|
void client_closed_callback(tp_stack_t *tt, tp_client_t *client,
|
|
tport_t *tp, msg_t *msg, int error)
|
|
{
|
|
assert(msg == NULL);
|
|
assert(client == NULL);
|
|
if (msg == NULL) {
|
|
tport_release(tp, pending_client_close, NULL, NULL, client, 0);
|
|
pending_client_close = 0;
|
|
}
|
|
}
|
|
|
|
static int tcp_test(tp_test_t *tt)
|
|
{
|
|
BEGIN();
|
|
|
|
msg_t *msg = NULL;
|
|
int i, N;
|
|
tport_t *tp, *tp0;
|
|
char ident[16];
|
|
su_time_t started;
|
|
|
|
/* Send a single message */
|
|
TEST_1(!new_test_msg(tt, &msg, "tcp-first", 1, 1024));
|
|
TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_tcp_name, TAG_END()));
|
|
TEST_S(tport_name(tp)->tpn_ident, "client");
|
|
tp0 = tport_incref(tp);
|
|
msg_destroy(msg);
|
|
|
|
tport_set_params(tp,
|
|
TPTAG_KEEPALIVE(100),
|
|
TPTAG_PINGPONG(500),
|
|
TPTAG_IDLE(500),
|
|
TAG_END());
|
|
|
|
TEST(tport_test_run(tt, 5), 1);
|
|
TEST_1(!check_msg(tt, tt->tt_rmsg, "tcp-first"));
|
|
msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
|
|
|
|
/* Ask for notification upon close */
|
|
pending_client_close = tport_pend(tp0, NULL, client_closed_callback, NULL);
|
|
TEST_1(pending_client_close > 0);
|
|
tp = tt->tt_rtport;
|
|
pending_server_close = tport_pend(tp, NULL, server_closed_callback, NULL);
|
|
TEST_1(pending_server_close > 0);
|
|
|
|
N = 0; tt->tt_received = 0;
|
|
|
|
#ifndef WIN32 /* Windows seems to be buffering too much */
|
|
|
|
/* Create a large message, just to force queueing in sending end */
|
|
TEST(new_test_msg(tt, &msg, "tcp-0", 1, 16 * 64 * 1024), 0);
|
|
test_create_md5(tt, msg);
|
|
TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_tcp_name, TAG_END()));
|
|
N++;
|
|
TEST_S(tport_name(tp)->tpn_ident, "client");
|
|
TEST_P(tport_incref(tp), tp0); tport_decref(&tp);
|
|
msg_destroy(msg);
|
|
|
|
/* Fill up the queue */
|
|
for (i = 1; i < TPORT_QUEUESIZE; i++) {
|
|
snprintf(ident, sizeof ident, "tcp-%u", i);
|
|
|
|
TEST(new_test_msg(tt, &msg, ident, 1, 64 * 1024), 0);
|
|
TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_tcp_name, TAG_END()));
|
|
N++;
|
|
TEST_S(tport_name(tp)->tpn_ident, "client");
|
|
TEST_P(tport_incref(tp), tp0); tport_decref(&tp);
|
|
msg_destroy(msg);
|
|
}
|
|
|
|
/* This overflows the queue */
|
|
TEST(new_test_msg(tt, &msg, "tcp-overflow", 1, 1024), 0);
|
|
TEST_1(!tport_tsend(tt->tt_tports, msg, tt->tt_tcp_name, TAG_END()));
|
|
msg_destroy(msg);
|
|
|
|
TEST(tport_test_run(tt, 60), 1);
|
|
TEST_1(!check_msg(tt, tt->tt_rmsg, "tcp-0"));
|
|
test_check_md5(tt, tt->tt_rmsg);
|
|
msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
|
|
|
|
if (tt->tt_received < TPORT_QUEUESIZE) { /* We have not received it all */
|
|
snprintf(ident, sizeof ident, "tcp-%u", tt->tt_received);
|
|
TEST(tport_test_run(tt, 5), 1);
|
|
TEST_1(!check_msg(tt, tt->tt_rmsg, ident));
|
|
msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
|
|
}
|
|
#else
|
|
(void)i; (void)ident;
|
|
#endif
|
|
|
|
/* This uses a new connection */
|
|
TEST_1(!new_test_msg(tt, &msg, "tcp-no-reuse", 1, 1024));
|
|
TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_tcp_name,
|
|
TPTAG_REUSE(0), TAG_END()));
|
|
N++;
|
|
TEST_S(tport_name(tp)->tpn_ident, "client");
|
|
TEST_1(tport_incref(tp) != tp0); tport_decref(&tp);
|
|
msg_destroy(msg);
|
|
|
|
/* This uses the old connection */
|
|
TEST_1(!new_test_msg(tt, &msg, "tcp-reuse", 1, 1024));
|
|
TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_tcp_name,
|
|
TPTAG_REUSE(1), TAG_END()));
|
|
N++;
|
|
TEST_S(tport_name(tp)->tpn_ident, "client");
|
|
TEST_1(tport_incref(tp) == tp0); tport_decref(&tp);
|
|
msg_destroy(msg);
|
|
|
|
/* Receive every message from queue */
|
|
while (tt->tt_received < N) {
|
|
TEST(tport_test_run(tt, 5), 1);
|
|
/* Validate message */
|
|
TEST_1(!check_msg(tt, tt->tt_rmsg, NULL));
|
|
msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
|
|
}
|
|
|
|
/* Try to send a single message */
|
|
TEST_1(!new_test_msg(tt, &msg, "tcp-last", 1, 1024));
|
|
TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_tcp_name, TAG_END()));
|
|
TEST_S(tport_name(tp)->tpn_ident, "client");
|
|
TEST_P(tport_incref(tp), tp0); tport_decref(&tp);
|
|
msg_destroy(msg);
|
|
|
|
TEST(tport_test_run(tt, 5), 1);
|
|
|
|
TEST_1(!check_msg(tt, tt->tt_rmsg, "tcp-last"));
|
|
msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
|
|
|
|
TEST_1(pending_server_close && pending_client_close);
|
|
SU_DEBUG_3(("tport_test(%p): waiting for PONG timeout\n", (void *)tp0));
|
|
|
|
/* Wait until notifications -
|
|
client closes when no pong is received and notifys pending,
|
|
then server closes and notifys pending */
|
|
while (pending_server_close || pending_client_close)
|
|
su_root_step(tt->tt_root, 50);
|
|
|
|
tport_decref(&tp0);
|
|
|
|
/* Again a single message */
|
|
TEST_1(!new_test_msg(tt, &msg, "tcp-pingpong", 1, 512));
|
|
TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_tcp_name, TAG_END()));
|
|
TEST_S(tport_name(tp)->tpn_ident, "client");
|
|
tp0 = tport_incref(tp);
|
|
msg_destroy(msg);
|
|
|
|
tport_set_params(tp0,
|
|
TPTAG_KEEPALIVE(250),
|
|
TPTAG_PINGPONG(200),
|
|
TAG_END());
|
|
|
|
TEST(tport_test_run(tt, 5), 1);
|
|
TEST_1(!check_msg(tt, tt->tt_rmsg, "tcp-pingpong"));
|
|
msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
|
|
|
|
/* Ask for notifications upon close */
|
|
pending_client_close = tport_pend(tp0, NULL, client_closed_callback, NULL);
|
|
TEST_1(pending_client_close > 0);
|
|
|
|
tp = tt->tt_rtport;
|
|
pending_server_close = tport_pend(tp, NULL, server_closed_callback, NULL);
|
|
TEST_1(pending_server_close > 0);
|
|
|
|
/* Now server responds with pong ... */
|
|
TEST(tport_set_params(tp, TPTAG_PONG2PING(1), TAG_END()), 1);
|
|
|
|
started = su_now();
|
|
|
|
while (pending_server_close && pending_client_close) {
|
|
su_root_step(tt->tt_root, 50);
|
|
if (su_duration(su_now(), started) > 1000)
|
|
break;
|
|
}
|
|
|
|
/* ... and we are still pending after a second */
|
|
TEST_1(pending_client_close && pending_server_close);
|
|
TEST_1(su_duration(su_now(), started) > 1000);
|
|
|
|
tport_shutdown(tp0, 2);
|
|
tport_unref(tp0);
|
|
|
|
while (pending_server_close || pending_client_close)
|
|
su_root_step(tt->tt_root, 50);
|
|
|
|
END();
|
|
}
|
|
|
|
static int test_incomplete(tp_test_t *tt)
|
|
{
|
|
BEGIN();
|
|
|
|
su_addrinfo_t const *ai = tt->tt_tcp_addr;
|
|
su_socket_t s;
|
|
int connected;
|
|
|
|
TEST_1(ai != NULL);
|
|
|
|
TEST(tport_set_params(tt->tt_tcp, TPTAG_TIMEOUT(500), TAG_END()), 1);
|
|
|
|
s = su_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
|
|
TEST_1(s != SOCKET_ERROR);
|
|
|
|
su_setblocking(s, 1);
|
|
connected = connect(s, ai->ai_addr, (socklen_t)ai->ai_addrlen);
|
|
|
|
su_root_step(tt->tt_root, 50);
|
|
|
|
TEST(su_send(s, "F", 1, 0), 1);
|
|
su_root_step(tt->tt_root, 50);
|
|
TEST(su_send(s, "O", 1, 0), 1);
|
|
su_root_step(tt->tt_root, 50);
|
|
TEST(su_send(s, "O", 1, 0), 1);
|
|
su_root_step(tt->tt_root, 50);
|
|
TEST(su_send(s, " ", 1, 0), 1);
|
|
su_root_step(tt->tt_root, 50);
|
|
|
|
tt->tt_received = 0;
|
|
TEST(tport_test_run(tt, 5), -1);
|
|
TEST(tt->tt_received, 1);
|
|
TEST_P(tt->tt_rmsg, NULL);
|
|
|
|
su_close(s);
|
|
|
|
END();
|
|
}
|
|
|
|
static int reuse_test(tp_test_t *tt)
|
|
{
|
|
msg_t *msg = NULL;
|
|
int i, reuse = -1;
|
|
tport_t *tp, *tp0, *tp1;
|
|
tp_name_t tpn[1];
|
|
|
|
BEGIN();
|
|
|
|
/* Flush existing connections */
|
|
*tpn = *tt->tt_tcp_name;
|
|
tpn->tpn_port = "*";
|
|
TEST_1(tp = tport_by_name(tt->tt_tports, tpn));
|
|
TEST_1(tport_is_primary(tp));
|
|
TEST(tport_flush(tp), 0);
|
|
|
|
for (i = 0; i < 10; i++)
|
|
su_root_step(tt->tt_root, 10L);
|
|
|
|
TEST(tport_set_params(tp, TPTAG_REUSE(0), TAG_END()), 1);
|
|
|
|
/* Send two messages */
|
|
TEST(new_test_msg(tt, &msg, "reuse-1", 1, 1024), 0);
|
|
TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_tcp_name, TAG_END()));
|
|
TEST_S(tport_name(tp)->tpn_ident, "client");
|
|
TEST_1(tp0 = tport_incref(tp));
|
|
TEST(tport_get_params(tp, TPTAG_REUSE_REF(reuse), TAG_END()), 1);
|
|
TEST(reuse, 0);
|
|
msg_destroy(msg), msg = NULL;
|
|
|
|
TEST(new_test_msg(tt, &msg, "reuse-2", 1, 1024), 0);
|
|
TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_tcp_name, TAG_END()));
|
|
TEST_S(tport_name(tp)->tpn_ident, "client");
|
|
TEST_1(tp1 = tport_incref(tp)); TEST_1(tp0 != tp1);
|
|
TEST(tport_get_params(tp, TPTAG_REUSE_REF(reuse), TAG_END()), 1);
|
|
TEST(reuse, 0);
|
|
msg_destroy(msg), msg = NULL;
|
|
|
|
/* Receive every message from queue */
|
|
for (tt->tt_received = 0;
|
|
tt->tt_received < 2;) {
|
|
TEST(tport_test_run(tt, 5), 1);
|
|
msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
|
|
}
|
|
|
|
/* Enable reuse on single connection */
|
|
TEST(tport_set_params(tp1, TPTAG_REUSE(1), TAG_END()), 1);
|
|
TEST(new_test_msg(tt, &msg, "reuse-3", 1, 1024), 0);
|
|
TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_tcp_name,
|
|
TPTAG_REUSE(1),
|
|
TAG_END()));
|
|
TEST_S(tport_name(tp)->tpn_ident, "client");
|
|
TEST_1(tp1 == tp);
|
|
TEST(tport_get_params(tp, TPTAG_REUSE_REF(reuse), TAG_END()), 1);
|
|
TEST(reuse, 1);
|
|
msg_destroy(msg), msg = NULL;
|
|
|
|
TEST(tport_test_run(tt, 5), 1);
|
|
msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
|
|
|
|
TEST_1(tp = tport_by_name(tt->tt_tports, tpn));
|
|
TEST_1(tport_is_primary(tp));
|
|
TEST(tport_set_params(tp, TPTAG_REUSE(1), TAG_END()), 1);
|
|
|
|
/* Send a single message with different connection */
|
|
TEST_1(!new_test_msg(tt, &msg, "fresh-1", 1, 1024));
|
|
TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_tcp_name,
|
|
TPTAG_FRESH(1),
|
|
TPTAG_REUSE(1),
|
|
TAG_END()));
|
|
TEST_S(tport_name(tp)->tpn_ident, "client");
|
|
TEST_1(tport_incref(tp) != tp1); tport_decref(&tp);
|
|
msg_destroy(msg);
|
|
|
|
TEST(tport_test_run(tt, 5), 1);
|
|
|
|
TEST_1(!check_msg(tt, tt->tt_rmsg, "fresh-1"));
|
|
msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
|
|
|
|
TEST_1(tport_shutdown(tp0, 2) >= 0);
|
|
TEST_1(tport_shutdown(tp1, 2) >= 0);
|
|
TEST_1(tport_shutdown(tp0, 1) >= 0);
|
|
|
|
TEST(tport_shutdown(NULL, 0), -1);
|
|
|
|
tport_decref(&tp0);
|
|
tport_decref(&tp1);
|
|
|
|
END();
|
|
}
|
|
|
|
static int sctp_test(tp_test_t *tt)
|
|
{
|
|
BEGIN();
|
|
|
|
msg_t *msg = NULL;
|
|
int i, n;
|
|
tport_t *tp, *tp0;
|
|
char buffer[32];
|
|
|
|
if (!tt->tt_sctp_name->tpn_proto)
|
|
return 0;
|
|
|
|
/* Just a small and nice message first */
|
|
TEST_1(!new_test_msg(tt, &msg, "cid:sctp-first", 1, 1024));
|
|
test_create_md5(tt, msg);
|
|
TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_sctp_name, TAG_END()));
|
|
TEST_S(tport_name(tp)->tpn_ident, "client");
|
|
msg_destroy(msg);
|
|
|
|
tport_set_params(tp, TPTAG_KEEPALIVE(100), TPTAG_IDLE(500), TAG_END());
|
|
|
|
TEST(tport_test_run(tt, 5), 1);
|
|
|
|
TEST_1(!check_msg(tt, tt->tt_rmsg, NULL));
|
|
test_check_md5(tt, tt->tt_rmsg);
|
|
msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
|
|
|
|
tp0 = tport_ref(tp);
|
|
|
|
pending_server_close = pending_client_close = 0;
|
|
|
|
/* Ask for notification upon close */
|
|
pending_client_close = tport_pend(tp, NULL, client_closed_callback, NULL);
|
|
TEST_1(pending_client_close > 0);
|
|
tp = tt->tt_rtport;
|
|
pending_server_close = tport_pend(tp, NULL, server_closed_callback, NULL);
|
|
TEST_1(pending_server_close > 0);
|
|
|
|
if (0) { /* SCTP does not work reliably. Really. */
|
|
|
|
tt->tt_received = 0;
|
|
|
|
/* Create large messages, just to force queueing in sending end */
|
|
for (n = 0; !tport_queuelen(tp); n++) {
|
|
snprintf(buffer, sizeof buffer, "cid:sctp-%u", n);
|
|
TEST_1(!new_test_msg(tt, &msg, buffer, 1, 32000));
|
|
test_create_md5(tt, msg);
|
|
TEST_1(tp = tport_tsend(tp0, msg, tt->tt_sctp_name, TAG_END()));
|
|
TEST_S(tport_name(tp)->tpn_ident, "client");
|
|
msg_destroy(msg);
|
|
}
|
|
|
|
/* Fill up the queue */
|
|
for (i = 1; i < TPORT_QUEUESIZE; i++) {
|
|
snprintf(buffer, sizeof buffer, "cid:sctp-%u", n + i);
|
|
TEST_1(!new_test_msg(tt, &msg, buffer, 1, 1024));
|
|
TEST_1(tp = tport_tsend(tp0, msg, tt->tt_sctp_name, TAG_END()));
|
|
msg_destroy(msg);
|
|
}
|
|
|
|
/* Try to overflow the queue */
|
|
snprintf(buffer, sizeof buffer, "cid:sctp-%u", n + i);
|
|
TEST_1(!new_test_msg(tt, &msg, buffer, 1, 1024));
|
|
TEST_1(!tport_tsend(tt->tt_tports, msg, tt->tt_sctp_name, TAG_END()));
|
|
msg_destroy(msg);
|
|
|
|
TEST(tport_test_run(tt, 5), 1);
|
|
|
|
TEST_1(!check_msg(tt, tt->tt_rmsg, NULL));
|
|
test_check_md5(tt, tt->tt_rmsg);
|
|
msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
|
|
|
|
/* This uses a new connection */
|
|
TEST_1(!new_test_msg(tt, &msg, "cid:sctp-new", 1, 1024));
|
|
TEST_1(tport_tsend(tt->tt_tports, msg, tt->tt_sctp_name,
|
|
TPTAG_REUSE(0), TAG_END()));
|
|
msg_destroy(msg);
|
|
|
|
/* Receive every message from queue */
|
|
for (; tt->tt_received < n + TPORT_QUEUESIZE - 1;) {
|
|
TEST(tport_test_run(tt, 10), 1);
|
|
/* Validate message */
|
|
TEST_1(!check_msg(tt, tt->tt_rmsg, NULL));
|
|
msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
|
|
}
|
|
|
|
/* Try to send a single message */
|
|
TEST_1(!new_test_msg(tt, &msg, "cid:sctp-final", 1, 512));
|
|
TEST_1(tport_tsend(tt->tt_tports, msg, tt->tt_sctp_name, TAG_END()));
|
|
msg_destroy(msg);
|
|
|
|
TEST(tport_test_run(tt, 10), 1);
|
|
|
|
TEST_1(!check_msg(tt, tt->tt_rmsg, NULL));
|
|
msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
|
|
}
|
|
|
|
tport_unref(tp0);
|
|
|
|
/* Wait until notifications -
|
|
client closes when idle and notifys pending,
|
|
then server closes and notifys pending */
|
|
while (pending_server_close || pending_client_close)
|
|
su_root_step(tt->tt_root, 50);
|
|
|
|
END();
|
|
}
|
|
|
|
struct called {
|
|
int n, error, pending, released;
|
|
};
|
|
|
|
static
|
|
void tls_error_callback(tp_stack_t *tt, tp_client_t *client,
|
|
tport_t *tp, msg_t *msg, int error)
|
|
{
|
|
struct called *called = (struct called *)client;
|
|
|
|
tt->tt_status = -1;
|
|
|
|
called->n++, called->error = error;
|
|
|
|
if (called->pending) {
|
|
called->released = tport_release(tp, called->pending, msg, NULL, client, 0);
|
|
called->pending = 0;
|
|
}
|
|
}
|
|
|
|
static int tls_test(tp_test_t *tt)
|
|
{
|
|
BEGIN();
|
|
|
|
#if HAVE_TLS
|
|
tp_name_t const *dst = tt->tt_tls_name;
|
|
msg_t *msg = NULL;
|
|
int i;
|
|
char ident[16];
|
|
tport_t *tp, *tp0;
|
|
struct called called[1] = {{ 0, 0, 0, 0 }};
|
|
|
|
TEST_S(dst->tpn_proto, "tls");
|
|
|
|
/* Send a single message */
|
|
TEST_1(!new_test_msg(tt, &msg, "tls-first", 1, 1024));
|
|
TEST_1(tp = tport_tsend(tt->tt_tports, msg, dst, TAG_END()));
|
|
TEST_1(tp0 = tport_ref(tp));
|
|
TEST_1(called->pending = tport_pend(tp, msg, tls_error_callback, (tp_client_t *)called));
|
|
|
|
i = tport_test_run(tt, 5);
|
|
msg_destroy(msg);
|
|
|
|
if (i < 0) {
|
|
if (called->n) {
|
|
TEST(called->released, 0);
|
|
puts("test_tport: skipping TLS tests");
|
|
tport_unref(tp0);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
TEST(i, 1);
|
|
|
|
TEST_1(!check_msg(tt, tt->tt_rmsg, "tls-first"));
|
|
msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
|
|
|
|
tport_set_params(tp, TPTAG_KEEPALIVE(100), TPTAG_IDLE(500), TAG_END());
|
|
|
|
/* Ask for notification upon close */
|
|
pending_client_close = tport_pend(tp0, NULL, client_closed_callback, NULL);
|
|
TEST_1(pending_client_close > 0);
|
|
tp = tt->tt_rtport;
|
|
pending_server_close = tport_pend(tp, NULL, server_closed_callback, NULL);
|
|
|
|
TEST_1(pending_server_close > 0);
|
|
|
|
/* Send a largish message */
|
|
TEST_1(!new_test_msg(tt, &msg, "tls-0", 16, 16 * 1024));
|
|
test_create_md5(tt, msg);
|
|
TEST_1(tp = tport_tsend(tt->tt_tports, msg, dst, TAG_END()));
|
|
TEST_1(tp == tp0);
|
|
msg_destroy(msg);
|
|
|
|
/* Fill up the queue */
|
|
for (i = 1; i < TPORT_QUEUESIZE; i++) {
|
|
snprintf(ident, sizeof ident, "tls-%u", i);
|
|
|
|
TEST_1(!new_test_msg(tt, &msg, ident, 2, 512));
|
|
TEST_1(tp = tport_tsend(tt->tt_tports, msg, dst, TAG_END()));
|
|
TEST_1(tp == tp0);
|
|
msg_destroy(msg);
|
|
}
|
|
|
|
/* This uses a new connection */
|
|
TEST_1(!new_test_msg(tt, &msg, "tls-no-reuse", 1, 1024));
|
|
TEST_1(tp = tport_tsend(tt->tt_tports, msg, dst,
|
|
TPTAG_REUSE(0), TAG_END()));
|
|
TEST_1(tp != tp0);
|
|
msg_destroy(msg);
|
|
|
|
tt->tt_received = 0;
|
|
|
|
/* Receive every message from queue */
|
|
while (tt->tt_received < TPORT_QUEUESIZE + 1) {
|
|
TEST(tport_test_run(tt, 5), 1);
|
|
/* Validate message */
|
|
msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
|
|
}
|
|
|
|
/* Try to send a single message */
|
|
TEST_1(!new_test_msg(tt, &msg, "tls-last", 1, 1024));
|
|
TEST_1(tport_tsend(tt->tt_tports, msg, dst, TAG_END()));
|
|
msg_destroy(msg);
|
|
|
|
TEST(tport_test_run(tt, 5), 1);
|
|
|
|
TEST_1(!check_msg(tt, tt->tt_rmsg, "tls-last"));
|
|
msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
|
|
|
|
tport_decref(&tp0);
|
|
|
|
/* Wait until notifications -
|
|
client closes when idle and notifys pending,
|
|
then server closes and notifys pending */
|
|
while (pending_server_close || pending_client_close)
|
|
su_root_step(tt->tt_root, 50);
|
|
|
|
#endif
|
|
|
|
END();
|
|
}
|
|
|
|
static int sigcomp_test(tp_test_t *tt)
|
|
{
|
|
BEGIN();
|
|
|
|
#if HAVE_SIGCOMP
|
|
su_home_t *home;
|
|
tp_name_t tpn[1] = {{ NULL }};
|
|
struct sigcomp_compartment *cc;
|
|
|
|
if (tt->tt_udp_comp->tpn_comp) {
|
|
msg_t *msg = NULL;
|
|
|
|
TEST_1(cc = test_sigcomp_compartment(tt, tt->tt_tports, tt->tt_udp_comp));
|
|
|
|
TEST_1(!new_test_msg(tt, &msg, "udp-sigcomp", 1, 1200));
|
|
test_create_md5(tt, msg);
|
|
TEST_1(tport_tsend(tt->tt_tports,
|
|
msg,
|
|
tt->tt_udp_comp,
|
|
TPTAG_COMPARTMENT(cc),
|
|
TAG_END()));
|
|
msg_destroy(msg);
|
|
|
|
TEST(tport_test_run(tt, 5), 1);
|
|
|
|
TEST_1(!check_msg(tt, tt->tt_rmsg, NULL));
|
|
|
|
test_check_md5(tt, tt->tt_rmsg);
|
|
|
|
TEST_1(msg = tt->tt_rmsg); tt->tt_rmsg = NULL;
|
|
|
|
TEST_1(home = msg_home(msg));
|
|
|
|
TEST_1(tport_convert_addr(home, tpn, "udp", NULL, msg_addr(msg)) == 0);
|
|
|
|
tpn->tpn_comp = tport_name(tt->tt_rtport)->tpn_comp;
|
|
|
|
/* reply */
|
|
TEST_1(cc = test_sigcomp_compartment(tt, tt->tt_tports, tpn));
|
|
TEST_1(tport_tsend(tt->tt_rtport, msg, tpn,
|
|
TPTAG_COMPARTMENT(cc),
|
|
TAG_END()) != NULL);
|
|
|
|
msg_destroy(msg);
|
|
|
|
TEST(tport_test_run(tt, 5), 1);
|
|
|
|
TEST_1(!check_msg(tt, tt->tt_rmsg, NULL));
|
|
test_check_md5(tt, tt->tt_rmsg);
|
|
msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
|
|
}
|
|
|
|
if (tt->tt_tcp_comp->tpn_comp) {
|
|
tport_t *tp;
|
|
msg_t *msg = NULL;
|
|
|
|
*tpn = *tt->tt_tcp_comp;
|
|
|
|
TEST_1(!new_test_msg(tt, &msg, "tcp-sigcomp", 1, 1500));
|
|
test_create_md5(tt, msg);
|
|
|
|
tport_log->log_level = 9;
|
|
|
|
TEST_1(cc = test_sigcomp_compartment(tt, tt->tt_tports, tpn));
|
|
TEST_1(tp = tport_tsend(tt->tt_tports,
|
|
msg,
|
|
tpn,
|
|
TPTAG_COMPARTMENT(cc),
|
|
TAG_END()));
|
|
TEST_1(tport_incref(tp)); tport_decref(&tp);
|
|
msg_destroy(msg);
|
|
|
|
TEST(tport_test_run(tt, 5), 1);
|
|
|
|
TEST_1(!check_msg(tt, tt->tt_rmsg, "tcp-sigcomp"));
|
|
test_check_md5(tt, tt->tt_rmsg);
|
|
msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
|
|
|
|
TEST_1(!new_test_msg(tt, &msg, "tcp-sigcomp-2", 1, 3000));
|
|
test_create_md5(tt, msg);
|
|
TEST_1(tp = tport_tsend(tt->tt_tports,
|
|
msg,
|
|
tt->tt_tcp_comp,
|
|
TPTAG_COMPARTMENT(cc),
|
|
TAG_END()));
|
|
TEST_1(tport_incref(tp)); tport_decref(&tp);
|
|
msg_destroy(msg);
|
|
|
|
TEST(tport_test_run(tt, 5), 1);
|
|
|
|
TEST_1(!check_msg(tt, tt->tt_rmsg, "tcp-sigcomp-2"));
|
|
test_check_md5(tt, tt->tt_rmsg);
|
|
|
|
msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
|
|
|
|
TEST_1(!new_test_msg(tt, &msg, "tcp-sigcomp-3", 1, 45500));
|
|
test_create_md5(tt, msg);
|
|
TEST_1(tp = tport_tsend(tt->tt_tports,
|
|
msg,
|
|
tt->tt_tcp_comp,
|
|
TPTAG_COMPARTMENT(cc),
|
|
TAG_END()));
|
|
TEST_1(tport_incref(tp));
|
|
msg_destroy(msg);
|
|
|
|
TEST(tport_test_run(tt, 5), 1);
|
|
|
|
tport_decref(&tp);
|
|
TEST_1(!check_msg(tt, tt->tt_rmsg, "tcp-sigcomp-3"));
|
|
test_check_md5(tt, tt->tt_rmsg);
|
|
msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
|
|
|
|
{
|
|
tp_name_t tpn[1];
|
|
tport_t *ctp, *rtp;
|
|
|
|
*tpn = *tt->tt_tcp_comp; tpn->tpn_comp = NULL;
|
|
|
|
TEST_1(!new_test_msg(tt, &msg, "tcp-sigcomp-4", 1, 1000));
|
|
test_create_md5(tt, msg);
|
|
TEST_1(tp = tport_tsend(tt->tt_tports,
|
|
msg,
|
|
tpn,
|
|
TPTAG_COMPARTMENT(cc),
|
|
TPTAG_FRESH(1),
|
|
TAG_END()));
|
|
TEST_1(ctp = tport_incref(tp));
|
|
msg_destroy(msg);
|
|
|
|
TEST(tport_test_run(tt, 5), 1);
|
|
|
|
TEST_1(!check_msg(tt, tt->tt_rmsg, "tcp-sigcomp-4"));
|
|
test_check_md5(tt, tt->tt_rmsg);
|
|
TEST_1((msg_addrinfo(tt->tt_rmsg)->ai_flags & TP_AI_COMPRESSED) == 0);
|
|
msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
|
|
TEST_1(rtp = tport_incref(tt->tt_rtport));
|
|
|
|
TEST_1(!new_test_msg(tt, &msg, "tcp-sigcomp-5", 1, 1000));
|
|
test_create_md5(tt, msg);
|
|
{
|
|
/* Mess with internal data structures in order to
|
|
force tport to use SigComp on this connection */
|
|
tp_name_t *tpn = (tp_name_t *)tport_name(rtp);
|
|
tpn->tpn_comp = "sigcomp";
|
|
}
|
|
TEST_1(tp = tport_tsend(rtp,
|
|
msg,
|
|
tt->tt_tcp_comp,
|
|
TPTAG_COMPARTMENT(cc),
|
|
TAG_END()));
|
|
TEST_1(tport_incref(tp));
|
|
msg_destroy(msg);
|
|
|
|
TEST(tp, rtp);
|
|
|
|
TEST(tport_test_run(tt, 5), 1);
|
|
|
|
tport_decref(&tp);
|
|
TEST_1(!check_msg(tt, tt->tt_rmsg, "tcp-sigcomp-5"));
|
|
test_check_md5(tt, tt->tt_rmsg);
|
|
TEST_1((msg_addrinfo(tt->tt_rmsg)->ai_flags & TP_AI_COMPRESSED) != 0);
|
|
msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
|
|
TEST(ctp, tt->tt_rtport);
|
|
tport_decref(&ctp);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
END();
|
|
}
|
|
|
|
#if HAVE_SOFIA_STUN
|
|
|
|
#include <sofia-sip/stun_tag.h>
|
|
|
|
static int stun_test(tp_test_t *tt)
|
|
{
|
|
BEGIN();
|
|
|
|
tport_t *mr;
|
|
tp_name_t tpn[1] = {{ "*", "*", "*", "*", NULL }};
|
|
#if HAVE_NETINET_SCTP_H
|
|
char const * transports[] = { "udp", "tcp", "sctp", NULL };
|
|
#else
|
|
char const * transports[] = { "udp", "tcp", NULL };
|
|
#endif
|
|
|
|
TEST_1(mr = tport_tcreate(tt, tp_test_class, tt->tt_root, TAG_END()));
|
|
|
|
TEST(tport_tbind(tt->tt_tports, tpn, transports, TPTAG_SERVER(1),
|
|
STUNTAG_SERVER("999.999.999.999"),
|
|
TAG_END()), -1);
|
|
|
|
tport_destroy(mr);
|
|
|
|
END();
|
|
}
|
|
#else
|
|
static int stun_test(tp_test_t *tt)
|
|
{
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static int deinit_test(tp_test_t *tt)
|
|
{
|
|
BEGIN();
|
|
|
|
/* Destroy client transports */
|
|
tport_destroy(tt->tt_tports), tt->tt_tports = NULL;
|
|
|
|
/* Destroy server transports */
|
|
tport_destroy(tt->tt_srv_tports), tt->tt_srv_tports = NULL;
|
|
|
|
#if HAVE_SIGCOMP
|
|
sigcomp_state_handler_free(tt->state_handler); tt->state_handler = NULL;
|
|
#endif
|
|
|
|
END();
|
|
}
|
|
|
|
/* Test tport_tags filter */
|
|
static int filter_test(tp_test_t *tt)
|
|
{
|
|
tagi_t *lst, *result;
|
|
|
|
su_home_t home[1] = { SU_HOME_INIT(home) };
|
|
|
|
BEGIN();
|
|
|
|
lst = tl_list(TSTTAG_HEADER_STR("X: Y"),
|
|
TAG_SKIP(2),
|
|
TPTAG_IDENT("foo"),
|
|
TSTTAG_HEADER_STR("X: Y"),
|
|
TPTAG_IDENT("bar"),
|
|
TAG_NULL());
|
|
|
|
TEST_1(lst);
|
|
|
|
result = tl_afilter(home, tport_tags, lst);
|
|
|
|
TEST_1(result);
|
|
TEST_P(result[0].t_tag, tptag_ident);
|
|
TEST_P(result[1].t_tag, tptag_ident);
|
|
|
|
free(lst);
|
|
su_home_deinit(home);
|
|
|
|
END();
|
|
}
|
|
|
|
#if HAVE_ALARM
|
|
#include <signal.h>
|
|
|
|
static RETSIGTYPE sig_alarm(int s)
|
|
{
|
|
fprintf(stderr, "%s: FAIL! test timeout!\n", name);
|
|
exit(1);
|
|
}
|
|
|
|
char const alarm_option[] = " [--no-alarm]";
|
|
|
|
#else
|
|
char const alarm_option[] = "";
|
|
#endif
|
|
|
|
void usage(int exitcode)
|
|
{
|
|
fprintf(stderr, "usage: %s [-v] [-a]%s\n", name, alarm_option);
|
|
exit(exitcode);
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
int flags = 0; /* XXX */
|
|
int retval = 0;
|
|
int no_alarm = 0;
|
|
int i;
|
|
|
|
tp_test_t tt[1] = {{{ SU_HOME_INIT(tt) }}};
|
|
|
|
for (i = 1; argv[i]; i++) {
|
|
if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbatim") == 0)
|
|
tstflags |= tst_verbatim;
|
|
else if (strcmp(argv[i], "-a") == 0 || strcmp(argv[i], "--abort") == 0)
|
|
tstflags |= tst_abort;
|
|
else if (strcmp(argv[i], "--no-alarm") == 0)
|
|
no_alarm = 1;
|
|
else
|
|
usage(1);
|
|
}
|
|
|
|
#if HAVE_OPEN_C
|
|
tstflags |= tst_verbatim;
|
|
#endif
|
|
|
|
#if HAVE_ALARM
|
|
if (!no_alarm) {
|
|
signal(SIGALRM, sig_alarm);
|
|
alarm(120);
|
|
}
|
|
#endif
|
|
|
|
/* Use log */
|
|
if (flags & tst_verbatim)
|
|
tport_log->log_default = 9;
|
|
else
|
|
tport_log->log_default = 1;
|
|
|
|
su_init();
|
|
|
|
retval |= name_test(tt); fflush(stdout);
|
|
retval |= filter_test(tt); fflush(stdout);
|
|
|
|
retval |= init_test(tt); fflush(stdout);
|
|
if (retval == 0) {
|
|
retval |= sigcomp_test(tt); fflush(stdout);
|
|
retval |= sctp_test(tt); fflush(stdout);
|
|
retval |= udp_test(tt); fflush(stdout);
|
|
retval |= tcp_test(tt); fflush(stdout);
|
|
retval |= test_incomplete(tt); fflush(stdout);
|
|
retval |= reuse_test(tt); fflush(stdout);
|
|
retval |= tls_test(tt); fflush(stdout);
|
|
if (0) /* Not yet working... */
|
|
retval |= stun_test(tt); fflush(stdout);
|
|
retval |= deinit_test(tt); fflush(stdout);
|
|
}
|
|
|
|
su_deinit();
|
|
|
|
#if HAVE_OPEN_C
|
|
sleep(10);
|
|
#endif
|
|
|
|
return retval;
|
|
}
|
|
|