Added basic synchronization code to network-based selftest

This commit is contained in:
Joseph Henry
2017-10-19 11:42:39 -07:00
parent 448ed75c48
commit 1267b90db5

View File

@@ -299,11 +299,10 @@ void str2addr(std::string ipstr, int port, int ipv, struct sockaddr *saddr)
{
if (ipv == 4) {
struct sockaddr_in *in4 = (struct sockaddr_in*)saddr;
in4->sin_port = htons(port);
in4->sin_addr.s_addr = inet_addr(ipstr.c_str());
in4->sin_family = AF_INET;
}
if (ipv == 6) {
in4->sin_port = htons(port);
} if (ipv == 6) {
struct sockaddr_in6 *in6 = (struct sockaddr_in6*)saddr;
inet_pton(AF_INET6, ipstr.c_str(), &(in6->sin6_addr));
in6->sin6_flowinfo = 0;
@@ -319,18 +318,74 @@ void RECORD_RESULTS(bool passed, char *details, std::vector<std::string> *result
if (passed == PASSED) {
DEBUG_TEST("%s", ok_str);
results->push_back(std::string(ok_str) + " " + std::string(details));
}
else {
} else {
DEBUG_ERROR("%s", fail_str);
results->push_back(std::string(fail_str) + " " + std::string(details));
}
if (EXIT_ON_FAIL && !passed) {
} if (EXIT_ON_FAIL && !passed) {
fprintf(stderr, "%s\n", results->at(results->size()-1).c_str());
exit(0);
}
memset(details, 0, DETAILS_STR_LEN);
}
void wait_until_everyone_is_ready(struct sockaddr *local_addr, struct sockaddr *remote_addr, int start_port)
{
/* try to connect to (and listen for) other selftest instances on the network.
When one is found, send some sort of synchronization message and allow test to
begin */
int err;
struct sockaddr_in client;
socklen_t client_addrlen = sizeof(sockaddr_in);
bool connected = false;
int accepted_fd;
// listen socket setup
int listen_fd;
if ((listen_fd = SOCKET(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket");
exit(0);
} if ((err = BIND(listen_fd, (struct sockaddr *)local_addr, sizeof(struct sockaddr_in)) < 0)) {
perror("bind");
exit(0);
} if ((err = LISTEN(listen_fd, 0)) < 0) {
perror("listen");
exit(0);
} if ((err = FCNTL(listen_fd, F_SETFL, O_NONBLOCK) < 0)) {
perror("fcntl");
exit(0);
}
// connect socket setup
int conn_fd;
if ((conn_fd = SOCKET(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket");
exit(0);
} if ((err = FCNTL(conn_fd, F_SETFL, O_NONBLOCK) < 0)) {
perror("fcntl");
exit(0);
}
while(connected == false) {
if ((err = CONNECT(conn_fd, (const struct sockaddr *)remote_addr, sizeof(*remote_addr))) < 0) {
if (errno == EISCONN) {
connected = true;
}
}
else {
connected = true;
}
if (connected == false) {
struct sockaddr_in client;
socklen_t client_addrlen = sizeof(sockaddr_in);
if ((accepted_fd = ACCEPT(listen_fd, (struct sockaddr *)&client, &client_addrlen)) < 0) {
DEBUG_TEST("errno = %d", errno);}
else {
connected = true;
}
}
sleep(1);
}
close(listen_fd);
close(conn_fd);
close(accepted_fd);
}
/****************************************************************************/
@@ -419,14 +474,11 @@ void tcp_select_server(TCP_UNIT_TEST_SIG_4)
}
}
}
DEBUG_TEST("complete");
sleep(ARTIFICIAL_SOCKET_LINGER);
err = CLOSE(fd);
sprintf(details, "%s, err=%d, r=%d, w=%d", testname.c_str(), err, r, w);
*passed = (w == len && r == len && !err) && !strcmp(rbuf, msg.c_str());
exit(0);
}
void tcp_select_client(TCP_UNIT_TEST_SIG_4)
@@ -498,30 +550,19 @@ void tcp_select_client(TCP_UNIT_TEST_SIG_4)
}
}
}
DEBUG_TEST("complete");
sleep(ARTIFICIAL_SOCKET_LINGER);
err = CLOSE(fd);
sprintf(details, "%s, err=%d, r=%d, w=%d", testname.c_str(), err, r, w);
*passed = (w == len && r == len && !err) && !strcmp(rbuf, msg.c_str());
exit(0);
}
/****************************************************************************/
/* SIMPLE */
/****************************************************************************/
// TCP
// TEST-1
void tcp_client_4(TCP_UNIT_TEST_SIG_4)
{
std::string testname = "tcp_client_4";
@@ -569,7 +610,6 @@ void tcp_client_4(TCP_UNIT_TEST_SIG_4)
// TEST-2
void tcp_server_4(TCP_UNIT_TEST_SIG_4)
{
std::string testname = "tcp_server_4";
@@ -630,7 +670,6 @@ void tcp_server_4(TCP_UNIT_TEST_SIG_4)
// TEST-3
void tcp_client_6(TCP_UNIT_TEST_SIG_6)
{
std::string testname = "tcp_client_6";
@@ -678,8 +717,6 @@ void tcp_client_6(TCP_UNIT_TEST_SIG_6)
// TEST-4
void tcp_server_6(TCP_UNIT_TEST_SIG_6)
{
std::string testname = "tcp_server_6";
@@ -745,7 +782,6 @@ void tcp_server_6(TCP_UNIT_TEST_SIG_6)
// UDP
// TEST-5
void udp_client_4(UDP_UNIT_TEST_SIG_4)
{
std::string testname = "udp_client_4";
@@ -802,7 +838,6 @@ void udp_client_4(UDP_UNIT_TEST_SIG_4)
// TEST-6
void udp_server_4(UDP_UNIT_TEST_SIG_4)
{
std::string testname = "udp_server_4";
@@ -862,9 +897,23 @@ void udp_server_4(UDP_UNIT_TEST_SIG_4)
int zts_bind_test(int fd, const struct sockaddr *addr, socklen_t addrlen)
{
int err = -1;
DEBUG_EXTRA("fd=%d", fd);
DEBUG_INFO("addrp=%p", addr);
DEBUG_INFO("addrlen=%d", addrlen);
DEBUG_INFO("sa_family======%d", addr->sa_family);
struct sockaddr_storage ss;
memcpy(&ss, addr, addrlen);
DEBUG_INFO("ss->sa_family=%d", ss.ss_family);
//fix_addr_socket_family((struct sockaddr*)&ss);
//ss.ss_family=AF_INET6;
//DEBUG_INFO("ss->sa_family=%d", ss.ss_family);
//err = lwip_bind(fd, (struct sockaddr*)&ss, addrlen);
exit(0);
}
// TEST-7
void udp_client_6(UDP_UNIT_TEST_SIG_6)
{
std::string testname = "udp_client_6";
@@ -887,14 +936,14 @@ void udp_client_6(UDP_UNIT_TEST_SIG_6)
*passed = false;
return;
}
DEBUG_TEST("[1] binding and sending UDP packets until I get a single response...");
if ((err = BIND(fd, (struct sockaddr *)local_addr, sizeof(struct sockaddr_in6)) < 0)) {
DEBUG_ERROR("error binding to interface (%d)", err);
if ((err = BIND(fd, (struct sockaddr*)local_addr, sizeof(struct sockaddr_in6)) < 0)) {
DEBUG_ERROR("error binding to interface (err=%d, errno=%d)", err, errno);
perror("bind");
*passed = false;
return;
}
// start sending UDP packets in the hopes that at least one will be picked up by the server
struct sockaddr_storage saddr;
while (true) {
@@ -923,8 +972,6 @@ void udp_client_6(UDP_UNIT_TEST_SIG_6)
// TEST-8
void udp_server_6(UDP_UNIT_TEST_SIG_6)
{
std::string testname = "udp_server_6";
@@ -2618,6 +2665,14 @@ void bind_to_localhost_test(int port)
#endif // __SELFTEST__
int trigger_address_sanitizer()
{
// Deliberately create a bad read to trigger address sanitizer
int stack_array[100];
stack_array[1] = 0;
return stack_array[1 + 100]; // BOOM
}
/****************************************************************************/
/* main(), calls test_driver(...) */
/****************************************************************************/
@@ -2629,7 +2684,6 @@ int main(int argc , char *argv[])
fprintf(stderr, "e.g. : selftest 3 test/test.conf alice to bob\n");
return 1;
}
int num_repeats = atoi(argv[1]);
std::string path = argv[2];
std::string from = argv[3];
@@ -2694,16 +2748,11 @@ int main(int argc , char *argv[])
fprintf(stderr, "\tremote_ipstr = %s\n", remote_ipstr.c_str());
fprintf(stderr, "\tremote_ipstr6 = %s\n", remote_ipstr6.c_str());
fprintf(stderr, "\tremote_echo_ipv4 = %s\n", remote_echo_ipv4.c_str());
fprintf(stderr, "\tme = %s\n", me.c_str());
#if defined(__SELFTEST__)
long int selftest_start_time = get_now_ts();
subtest_expected_duration = 5;
if (me != "dummy") { // used for testing ZT service wrapper API (before, during, and after coming online)
// set start time here since we need to wait for both libzt instances to be online
DEBUG_TEST("Waiting for libzt to come online...\n");
DEBUG_TEST("app-thread, waiting for libzt to come online...\n");
zts_startjoin(path.c_str(), nwid.c_str());
char device_id[ZTO_ID_LEN];
zts_get_id(device_id);
@@ -2714,20 +2763,19 @@ int main(int argc , char *argv[])
if (mode == TEST_MODE_CLIENT) {
DEBUG_TEST("Ready. Contacting selftest program on first host.\n\n");
}
// What follows is a long-form of zts_start():
/*
zts_start(path.c_str());
printf("waiting for service to start...\n");
while (zts_running() == false)
sleep(1);
printf("joining network...\n");
zts_join(nwid.c_str());
printf("waiting for address assignment...\n");
while (zts_has_address(nwid.c_str()) == false)
sleep(1);
*/
}
// SYNCHRONIZE test start times between multiple instances of the selftest on the network
ipv = 4;
int negotiation_port = start_port + 1000;
port = negotiation_port;
str2addr(local_ipstr, port, ipv, (struct sockaddr *)&local_addr);
str2addr(remote_ipstr, port, ipv, (struct sockaddr *)&remote_addr);
wait_until_everyone_is_ready((struct sockaddr *)&local_addr, (struct sockaddr *)&remote_addr, start_port);
DEBUG_TEST("both instances of selftest have started. beginning tests...");
long int selftest_start_time = get_now_ts();
subtest_expected_duration = 5;
#endif // __SELFTEST__
for (int i=0; i<num_repeats; i++)
@@ -2772,13 +2820,11 @@ for (int i=0; i<num_repeats; i++)
if (false) {
obscure_api_test(&passed);
}
// Test things like zts_start(), zts_stop(), zts_join(), etc
if (false) {
ZT_control_semantics_test(&passed);
exit(0);
}
// Spam a SOCK_DGRAM socket from many threads
if (false) {
ipv = 4;
@@ -2787,36 +2833,27 @@ for (int i=0; i<num_repeats; i++)
str2addr(remote_ipstr, port, ipv, (struct sockaddr *)&remote_addr);
multithread_udp_write((struct sockaddr_in *)&local_addr, (struct sockaddr_in *)&remote_addr, &passed);
}
//
// test thread safety
if (false) {
multithread_test(10, &passed);
}
// make sure the address sanitizer is available
if (false) {
trigger_address_sanitizer();
}
#endif // __SELFTEST__
port = start_port+(100*i); // arbitrary
cnt = 1024*3;
cnt = 64;
op = TEST_OP_N_BYTES;
/*
// Deliberately create a bad read to trigger address sanitizer
int stack_array[100];
stack_array[1] = 0;
return stack_array[argc + 100]; // BOOM
int mybuf[10];
mybuf[11] = 9;
memcpy(mybuf, "what the hell is this", 55);
*/
// set start time here since we aren't waiting for libzt to come online in NATIVETEST mode
#if defined(__NATIVETEST__)
long int selftest_start_time = get_now_ts();
subtest_expected_duration = 20; // initial value, wait for other instance to come online
#endif
#if defined(LIBZT_IPV4)
/*
// UDP 4 client/server
ipv = 4;
@@ -2989,39 +3026,12 @@ for (int i=0; i<num_repeats; i++)
}
RECORD_RESULTS(passed, details, &results);
port++;
// PERFORMANCE (between this library instance and a native non library instance (echo) )
// Client/Server mode isn't being tested here, so it isn't important, we'll just set it to client
// ipv4 echo test (TCP)
/*
ipv = 4;
if (me == "alice" || me == "ted") {
port=start_port+100; // e.g. 7100
str2addr(remote_echo_ipv4, port, ipv, (struct sockaddr *)&remote_addr);
tcp_perf_tx_echo_4((struct sockaddr_in *)&remote_addr, op, cnt, details, &passed);
RECORD_RESULTS(passed, details, &results);
tcp_perf_rx_echo_4((struct sockaddr_in *)&remote_addr, op, cnt, details, &passed);
RECORD_RESULTS(passed, details, &results);
}
if (me == "bob" || me == "carol") {
DEBUG_TEST("waiting (15s) for other selftest to complete before continuing...");
port=start_port+101; // e.g. 7101
str2addr(remote_echo_ipv4, port, ipv, (struct sockaddr *)&remote_addr);
tcp_perf_rx_echo_4((struct sockaddr_in *)&remote_addr, op, cnt, details, &passed);
RECORD_RESULTS(passed, details, &results);
tcp_perf_tx_echo_4((struct sockaddr_in *)&remote_addr, op, cnt, details, &passed);
RECORD_RESULTS(passed, details, &results);
}
*/
#endif // LIBZT_IPV4
*/
// IPV6
#if defined(LIBZT_IPV6)
/*
// UDP 6 client/server
ipv = 6;
@@ -3059,8 +3069,6 @@ for (int i=0; i<num_repeats; i++)
RECORD_RESULTS(passed, details, &results);
port++;
// UDP 6 sustained transfer
ipv = 6;
@@ -3131,7 +3139,7 @@ for (int i=0; i<num_repeats; i++)
}
RECORD_RESULTS(passed, details, &results);
port++;
*/
// TCP 6 sustained transfer
ipv = 6;
@@ -3164,7 +3172,6 @@ for (int i=0; i<num_repeats; i++)
}
RECORD_RESULTS(passed, details, &results);
port++;
#endif // LIBZT_IPV6
// Print results of all tests
printf("--------------------------------------------------------------------------------\n");