From 3a00cbb89fd0499062ffda96a3c02f54c42a7d26 Mon Sep 17 00:00:00 2001 From: Brendon Jones Date: Thu, 12 Sep 2019 11:58:38 +1200 Subject: [PATCH] Update tests to accept unresolved hostnames as destinations. See #4 --- src/common/debug.c | 13 ++ src/common/debug.h | 1 + src/common/testlib.c | 2 +- src/tests/dns/dns.c | 23 +++- src/tests/dns/test/Makefile.am | 7 +- .../dns/test/dns_unresolved_target_test.c | 111 ++++++++++++++++++ src/tests/fastping/fastping.c | 20 +++- src/tests/fastping/test/Makefile.am | 7 +- .../test/fastping_unresolved_target_test.c | 102 ++++++++++++++++ src/tests/http/http.c | 23 ++-- src/tests/http/test/Makefile.am | 7 +- .../http/test/http_unresolved_target_test.c | 102 ++++++++++++++++ src/tests/icmp/icmp.c | 15 +++ src/tests/icmp/test/Makefile.am | 7 +- .../icmp/test/icmp_unresolved_target_test.c | 100 ++++++++++++++++ src/tests/python/ampsave/tests/http.py | 16 +-- src/tests/python/ampsave/tests/icmp.py | 2 +- src/tests/python/ampsave/tests/tcpping.py | 2 +- src/tests/python/ampsave/tests/udpstream.py | 4 +- src/tests/tcpping/tcpping.c | 14 +++ src/tests/tcpping/test/Makefile.am | 7 +- .../test/tcpping_unresolved_target_test.c | 103 ++++++++++++++++ src/tests/throughput/test/Makefile.am | 7 +- .../test/throughput_unresolved_target_test.c | 102 ++++++++++++++++ src/tests/throughput/throughput_client.c | 85 ++++++++------ src/tests/throughput/throughput_common.c | 9 ++ src/tests/traceroute/test/Makefile.am | 7 +- .../test/traceroute_unresolved_target_test.c | 103 ++++++++++++++++ src/tests/traceroute/traceroute.c | 16 ++- src/tests/udpstream/test/Makefile.am | 7 +- .../test/udpstream_unresolved_target_test.c | 107 +++++++++++++++++ src/tests/udpstream/udpstream_client.c | 81 ++++++++----- 32 files changed, 1093 insertions(+), 119 deletions(-) create mode 100644 src/tests/dns/test/dns_unresolved_target_test.c create mode 100644 src/tests/fastping/test/fastping_unresolved_target_test.c create mode 100644 src/tests/http/test/http_unresolved_target_test.c create mode 100644 src/tests/icmp/test/icmp_unresolved_target_test.c create mode 100644 src/tests/tcpping/test/tcpping_unresolved_target_test.c create mode 100644 src/tests/throughput/test/throughput_unresolved_target_test.c create mode 100644 src/tests/traceroute/test/traceroute_unresolved_target_test.c create mode 100644 src/tests/udpstream/test/udpstream_unresolved_target_test.c diff --git a/src/common/debug.c b/src/common/debug.c index dc442d8..d816e1d 100644 --- a/src/common/debug.c +++ b/src/common/debug.c @@ -179,3 +179,16 @@ const char *amp_inet_ntop(struct addrinfo *addr, char *buffer) { return inet_ntop(addr->ai_family, addrptr, buffer, INET6_ADDRSTRLEN); } + + + +/* + * Convert an IP address family value into a short human readable string. + */ +const char *family_to_string(int family) { + switch ( family ) { + case AF_INET: return "ipv4"; + case AF_INET6: return "ipv6"; + default: return "unknown"; + }; +} diff --git a/src/common/debug.h b/src/common/debug.h index 70bf645..ed98857 100644 --- a/src/common/debug.h +++ b/src/common/debug.h @@ -52,6 +52,7 @@ extern int log_level_override; void Log(int priority, const char *fmt, ...); const char *amp_inet_ntop(struct addrinfo *addr, char *buffer); +const char *family_to_string(int family); #ifdef __cplusplus } diff --git a/src/common/testlib.c b/src/common/testlib.c index 9db153b..28decec 100644 --- a/src/common/testlib.c +++ b/src/common/testlib.c @@ -825,7 +825,7 @@ int copy_address_to_protobuf(ProtobufCBinaryData *dst, const struct addrinfo *src) { assert(dst); - if ( src == NULL ) { + if ( src == NULL || src->ai_addr == NULL ) { dst->data = 0; dst->len = 0; return 0; diff --git a/src/tests/dns/dns.c b/src/tests/dns/dns.c index e5f1cb2..aa80428 100644 --- a/src/tests/dns/dns.c +++ b/src/tests/dns/dns.c @@ -570,6 +570,11 @@ static void send_packet(wand_event_handler_t *ev_hdl, void *data) { */ info[seq].addr = dest; + if ( !dest->ai_addr ) { + Log(LOG_INFO, "No address for target %s, skipping", dest->ai_canonname); + goto next; + } + /* determine the appropriate socket to use and port field to set */ switch ( dest->ai_family ) { case AF_INET: @@ -1298,16 +1303,26 @@ void print_dns(amp_test_result_t *result) { for ( i=0; i < msg->n_reports; i++ ) { item = msg->reports[i]; - printf("SERVER: %s", item->name); - inet_ntop(item->family, item->address.data, addrstr, INET6_ADDRSTRLEN); + printf("SERVER: %s", item->name); + + if ( !item->has_address ) { + /* couldn't resolve the target, didn't test to it */ + snprintf(addrstr, INET6_ADDRSTRLEN, "unresolved %s", + family_to_string(item->family)); + printf(" (%s) not tested\n\n", addrstr); + continue; + } + + inet_ntop(item->family, item->address.data, addrstr, INET6_ADDRSTRLEN); + printf(" (%s)", addrstr); /* nothing further we can do if there is no rtt - no good response */ if ( !item->has_rtt ) { - printf(" (%s) no response\n\n", addrstr); + printf(" no response\n\n"); continue; } - printf(" (%s) %dus\n", addrstr, item->rtt); + printf(" %dus\n", item->rtt); /* if present, print instance name / nsid payload like dig does */ if ( item->instance.len > 0 ) { diff --git a/src/tests/dns/test/Makefile.am b/src/tests/dns/test/Makefile.am index 81cc033..1ad91ca 100644 --- a/src/tests/dns/test/Makefile.am +++ b/src/tests/dns/test/Makefile.am @@ -1,5 +1,5 @@ -TESTS=dns_register.test dns_encode.test dns_decode.test dns_report.test -check_PROGRAMS=dns_register.test dns_encode.test dns_decode.test dns_report.test +TESTS=dns_register.test dns_encode.test dns_decode.test dns_report.test dns_unresolved_target.test +check_PROGRAMS=dns_register.test dns_encode.test dns_decode.test dns_report.test dns_unresolved_target.test check_LTLIBRARIES=testdns.la testdns_la_SOURCES=../dns.c @@ -19,5 +19,8 @@ dns_decode_test_LDADD=testdns.la dns_report_test_SOURCES=dns_report_test.c dns_report_test_LDADD=testdns.la +dns_unresolved_target_test_SOURCES=dns_unresolved_target_test.c +dns_unresolved_target_test_LDADD=testdns.la + AM_CFLAGS=-g -Wall -W -rdynamic -DUNIT_TEST INCLUDES=-I../ -I../../ -I../../../common/ diff --git a/src/tests/dns/test/dns_unresolved_target_test.c b/src/tests/dns/test/dns_unresolved_target_test.c new file mode 100644 index 0000000..ca9d604 --- /dev/null +++ b/src/tests/dns/test/dns_unresolved_target_test.c @@ -0,0 +1,111 @@ +/* + * This file is part of amplet2. + * + * Copyright (c) 2013-2019 The University of Waikato, Hamilton, New Zealand. + * + * Author: Brendon Jones + * + * All rights reserved. + * + * This code has been developed by the University of Waikato WAND + * research group. For further information please see http://www.wand.net.nz/ + * + * amplet2 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations including + * the two. + * + * You must obey the GNU General Public License in all respects for all + * of the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do + * so, delete this exception statement from your version. If you delete + * this exception statement from all source files in the program, then + * also delete it here. + * + * amplet2 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with amplet2. If not, see . + */ + +#include +#include +#include +#include +#include + +#include "tests.h" +#include "dns.h" +#include "dns.pb-c.h" + +#define TEST_TARGET "doesnotexist.invalid" + +/* + * + */ +int main(void) { + amp_test_result_t *result; + struct addrinfo *target; + Amplet2__Dns__Report *msg; + Amplet2__Dns__Item *item; + int argc = 3; + char *argv[] = {"amp-dns", "-q", "example.com", NULL}; + + /* + * create a dummy addrinfo like the resolver does when it can't resolve + * the name + */ + target = calloc(1, sizeof(struct addrinfo)); + target->ai_family = AF_INET; + target->ai_addrlen = 0; + target->ai_addr = NULL; + target->ai_canonname = TEST_TARGET; + target->ai_next = NULL; + + /* run the test against the dummy target */ + result = run_dns(argc, argv, 1, &target); + + assert(result); + assert(result->data); + + /* check that the results are missing/empty in the right places */ + msg = amplet2__dns__report__unpack(NULL, result->len, result->data); + + assert(msg); + assert(msg->header); + assert(msg->n_reports == 1); + assert(msg->reports); + + item = msg->reports[0]; + + assert(!item->has_address); + assert(item->has_family); + assert(item->family == AF_INET); + assert(!item->has_rtt); + assert(!item->has_query_length); + assert(!item->has_response_size); + assert(!item->has_total_answer); + assert(!item->has_total_authority); + assert(!item->has_total_additional); + assert(!item->flags); + assert(!item->has_ttl); + assert(strcmp(item->name, TEST_TARGET) == 0); + assert(!item->has_instance); + assert(!item->has_rrsig); + + amplet2__dns__report__free_unpacked(msg, NULL); + free(result->data); + free(result); + free(target); + + return 0; +} diff --git a/src/tests/fastping/fastping.c b/src/tests/fastping/fastping.c index db97397..e0810f2 100644 --- a/src/tests/fastping/fastping.c +++ b/src/tests/fastping/fastping.c @@ -510,6 +510,15 @@ static amp_test_result_t* send_icmp_stream(struct addrinfo *dest, memset(&stop_time, 0, sizeof(struct timeval)); memset(&loss_timeout, 0, sizeof(struct timeval)); + if ( dest->ai_addr == NULL ) { + if ( gettimeofday(&start_time, NULL) != 0 ) { + Log(LOG_ERR, "Could not gettimeofday(), aborting test"); + exit(EXIT_FAILURE); + } + + return report_result(&start_time, dest, options, NULL, NULL); + } + /* extract the socket depending on the address family */ switch ( dest->ai_family ) { case AF_INET: sock = sockets->socket; break; @@ -641,7 +650,7 @@ static amp_test_result_t* send_icmp_stream(struct addrinfo *dest, if ( bytes > 0 ) { /* extract the sequence number from the icmp packet */ int64_t sequence = extract_data(dest, response, pid, &from); - if ( sequence >= 0 && sequence < options->count) { + if ( sequence >= 0 && sequence < (int64_t)options->count ) { memcpy(&(timing[sequence].time_received), &receive_time, sizeof(struct timeval)); received++; @@ -825,7 +834,14 @@ void print_fastping(amp_test_result_t *result) { samples = item->rtt ? item->rtt->samples : 0; percent = ((double) samples / (double) header->count) * 100; - inet_ntop(header->family, header->address.data, addrstr, INET6_ADDRSTRLEN); + + if ( header->has_address ) { + inet_ntop(header->family, header->address.data, addrstr, + INET6_ADDRSTRLEN); + } else { + snprintf(addrstr, INET6_ADDRSTRLEN, "unresolved %s", + family_to_string(header->family)); + } /* print basic stats */ printf("\n"); diff --git a/src/tests/fastping/test/Makefile.am b/src/tests/fastping/test/Makefile.am index 56e8882..6baeb4d 100644 --- a/src/tests/fastping/test/Makefile.am +++ b/src/tests/fastping/test/Makefile.am @@ -1,5 +1,5 @@ -TESTS=fastping_register.test -check_PROGRAMS=fastping_register.test +TESTS=fastping_register.test fastping_unresolved_target.test +check_PROGRAMS=fastping_register.test fastping_unresolved_target.test check_LTLIBRARIES=testfastping.la testfastping_la_SOURCES=../fastping.c @@ -10,5 +10,8 @@ testfastping_la_LDFLAGS=-module -avoid-version -L../../../common/ -lamp -lprotob fastping_register_test_SOURCES=fastping_register_test.c fastping_register_test_LDADD=testfastping.la +fastping_unresolved_target_test_SOURCES=fastping_unresolved_target_test.c +fastping_unresolved_target_test_LDADD=testfastping.la + AM_CFLAGS=-g -Wall -W -rdynamic -DUNIT_TEST INCLUDES=-I../ -I../../../common/ diff --git a/src/tests/fastping/test/fastping_unresolved_target_test.c b/src/tests/fastping/test/fastping_unresolved_target_test.c new file mode 100644 index 0000000..5599c5a --- /dev/null +++ b/src/tests/fastping/test/fastping_unresolved_target_test.c @@ -0,0 +1,102 @@ +/* + * This file is part of amplet2. + * + * Copyright (c) 2013-2019 The University of Waikato, Hamilton, New Zealand. + * + * Author: Brendon Jones + * + * All rights reserved. + * + * This code has been developed by the University of Waikato WAND + * research group. For further information please see http://www.wand.net.nz/ + * + * amplet2 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations including + * the two. + * + * You must obey the GNU General Public License in all respects for all + * of the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do + * so, delete this exception statement from your version. If you delete + * this exception statement from all source files in the program, then + * also delete it here. + * + * amplet2 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with amplet2. If not, see . + */ + +#include +#include +#include +#include +#include + +#include "tests.h" +#include "fastping.h" +#include "fastping.pb-c.h" + +#define TEST_TARGET "doesnotexist.invalid" + +/* + * + */ +int main(void) { + amp_test_result_t *result; + struct addrinfo *target; + Amplet2__Fastping__Report *msg; + Amplet2__Fastping__Item *item; + + /* + * create a dummy addrinfo like the resolver does when it can't resolve + * the name + */ + target = calloc(1, sizeof(struct addrinfo)); + target->ai_family = AF_INET; + target->ai_addrlen = 0; + target->ai_addr = NULL; + target->ai_canonname = TEST_TARGET; + target->ai_next = NULL; + + /* run the test against the dummy target */ + result = run_fastping(0, NULL, 1, &target); + + assert(result); + assert(result->data); + + /* check that the results are missing/empty in the right places */ + msg = amplet2__fastping__report__unpack(NULL, result->len, result->data); + + assert(msg); + assert(msg->header); + assert(!msg->header->has_address); + assert(msg->header->has_family); + assert(msg->header->family == AF_INET); + assert(strcmp(msg->header->name, TEST_TARGET) == 0); + assert(msg->n_reports == 1); + assert(msg->reports); + + item = msg->reports[0]; + + assert(!item->has_runtime); + assert(!item->rtt); + assert(!item->jitter); + + amplet2__fastping__report__free_unpacked(msg, NULL); + free(result->data); + free(result); + free(target); + + return 0; +} diff --git a/src/tests/http/http.c b/src/tests/http/http.c index 5e6ee6e..6aeba62 100644 --- a/src/tests/http/http.c +++ b/src/tests/http/http.c @@ -1117,19 +1117,19 @@ static void check_messages(CURLM *multi, int *running_handles) { curl_easy_getinfo(msg->easy_handle, CURLINFO_SIZE_DOWNLOAD, &bytes); if ( msg->data.result != 0 ) { - Log(LOG_WARNING, "R: %d - %s <%s> (%fb)\n", msg->data.result, + Log(LOG_WARNING, "%s <%s> (%fb)\n", curl_easy_strerror(msg->data.result), url, bytes); - //TODO should we break out of loop or anything here? /* - * If we fail to resolve the first host then don't record an - * object. Any test with one server and zero objects won't be - * reported (similar to other tests when they fail to resolve - * a destination). + * If we fail to resolve or connect to the first host then stop + * the test and don't record an object. */ - if ( msg->data.result == CURLE_COULDNT_RESOLVE_HOST && + if ( (msg->data.result == CURLE_COULDNT_RESOLVE_HOST || + msg->data.result == CURLE_COULDNT_RESOLVE_PROXY || + msg->data.result == CURLE_COULDNT_CONNECT || + msg->data.result == CURLE_SSL_CONNECT_ERROR) && server_list && server_list->next == NULL && server_list->finished == NULL ) { - continue; + break; } } @@ -1507,12 +1507,7 @@ amp_test_result_t* run_http(int argc, char *argv[], curl_global_cleanup(); /* send report */ - if ( global.servers > 0 && global.objects > 0 ) { - result = report_results(&global.start, server_list, &options); - } else { - Log(LOG_DEBUG, "Didn't attempt to fetch any objects, no results"); - result = NULL; - } + result = report_results(&global.start, server_list, &options); /* TODO, free everything */ //free(server_list); diff --git a/src/tests/http/test/Makefile.am b/src/tests/http/test/Makefile.am index 967f8a8..154b041 100644 --- a/src/tests/http/test/Makefile.am +++ b/src/tests/http/test/Makefile.am @@ -1,5 +1,5 @@ -TESTS=http_register.test http_split_url.test http_report.test -check_PROGRAMS=http_register.test http_split_url.test http_report.test +TESTS=http_register.test http_split_url.test http_report.test http_unresolved_target.test +check_PROGRAMS=http_register.test http_split_url.test http_report.test http_unresolved_target.test check_LTLIBRARIES=testhttp.la testhttp_la_SOURCES=../http.c ../servers.c ../parsers.c ../output.c ../lexer.c @@ -16,5 +16,8 @@ http_split_url_test_LDADD=testhttp.la http_report_test_SOURCES=http_report_test.c http_report_test_LDADD=testhttp.la +http_unresolved_target_test_SOURCES=http_unresolved_target_test.c +http_unresolved_target_test_LDADD=testhttp.la + AM_CFLAGS=-g -Wall -W -rdynamic -DUNIT_TEST INCLUDES=-I../ -I../../ -I../../../common/ diff --git a/src/tests/http/test/http_unresolved_target_test.c b/src/tests/http/test/http_unresolved_target_test.c new file mode 100644 index 0000000..f8080e8 --- /dev/null +++ b/src/tests/http/test/http_unresolved_target_test.c @@ -0,0 +1,102 @@ +/* + * This file is part of amplet2. + * + * Copyright (c) 2013-2019 The University of Waikato, Hamilton, New Zealand. + * + * Author: Brendon Jones + * + * All rights reserved. + * + * This code has been developed by the University of Waikato WAND + * research group. For further information please see http://www.wand.net.nz/ + * + * amplet2 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations including + * the two. + * + * You must obey the GNU General Public License in all respects for all + * of the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do + * so, delete this exception statement from your version. If you delete + * this exception statement from all source files in the program, then + * also delete it here. + * + * amplet2 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with amplet2. If not, see . + */ + +#include +#include +#include +#include +#include + +#include "tests.h" +#include "http.h" +#include "http.pb-c.h" + +#define TEST_HOST "http://doesnotexist.invalid" +#define TEST_URL TEST_HOST "/" + +/* + * + */ +int main(void) { + amp_test_result_t *result; + Amplet2__Http__Report *msg; + Amplet2__Http__Server *server; + int argc = 3; + char *argv[] = {"amp-http", "-u", TEST_URL, NULL}; + + /* run the test against the dummy target */ + result = run_http(argc, argv, 0, NULL); + + assert(result); + assert(result->data); + + /* check that the results are missing/empty in the right places */ + msg = amplet2__http__report__unpack(NULL, result->len, result->data); + + assert(msg); + assert(msg->header); + assert(strcmp(msg->header->url, TEST_URL) == 0); + assert(msg->header->has_duration); + assert(msg->header->duration == 0); + assert(msg->header->has_total_bytes); + assert(msg->header->total_bytes == 0); + assert(msg->header->has_total_objects); + assert(msg->header->total_objects == 0); + + assert(msg->n_servers == 1); + assert(msg->servers); + + server = msg->servers[0]; + + assert(strcmp(server->hostname, TEST_HOST) == 0); + assert(server->has_start); + assert(server->has_end); + assert(server->start == server->end); + assert(server->address); + assert(strcmp(server->address, "0.0.0.0") == 0); + assert(server->has_total_bytes); + assert(server->total_bytes == 0); + assert(server->n_objects == 0); + + amplet2__http__report__free_unpacked(msg, NULL); + free(result->data); + free(result); + + return 0; +} diff --git a/src/tests/icmp/icmp.c b/src/tests/icmp/icmp.c index daba34b..32effaf 100644 --- a/src/tests/icmp/icmp.c +++ b/src/tests/icmp/icmp.c @@ -435,6 +435,12 @@ static void send_packet(wand_event_handler_t *ev_hdl, void *data) { info[seq].addr = dest; info[seq].magic = rand(); + /* TODO should we try to send the next packet in this time slot? */ + if ( !dest->ai_addr ) { + Log(LOG_INFO, "No address for target %s, skipping", dest->ai_canonname); + goto next; + } + /* determine which socket we should use, ipv4 or ipv6 */ switch ( dest->ai_family ) { case AF_INET: sock = globals->sockets.socket; break; @@ -890,6 +896,15 @@ void print_icmp(amp_test_result_t *result) { item = msg->reports[i]; printf("%s", item->name); + + if ( !item->has_address ) { + /* couldn't resolve the target, didn't test to it */ + snprintf(addrstr, INET6_ADDRSTRLEN, "unresolved %s", + family_to_string(item->family)); + printf(" (%s) not tested\n", addrstr); + continue; + } + inet_ntop(item->family, item->address.data, addrstr, INET6_ADDRSTRLEN); printf(" (%s)", addrstr); diff --git a/src/tests/icmp/test/Makefile.am b/src/tests/icmp/test/Makefile.am index a82081a..2fe0e02 100644 --- a/src/tests/icmp/test/Makefile.am +++ b/src/tests/icmp/test/Makefile.am @@ -1,5 +1,5 @@ -TESTS=icmp_register.test icmp_process_ipv4.test icmp_report.test -check_PROGRAMS=icmp_register.test icmp_process_ipv4.test icmp_report.test +TESTS=icmp_register.test icmp_process_ipv4.test icmp_report.test icmp_unresolved_target.test +check_PROGRAMS=icmp_register.test icmp_process_ipv4.test icmp_report.test icmp_unresolved_target.test check_LTLIBRARIES=testicmp.la testicmp_la_SOURCES=../icmp.c @@ -16,5 +16,8 @@ icmp_process_ipv4_test_LDADD=testicmp.la icmp_report_test_SOURCES=icmp_report_test.c icmp_report_test_LDADD=testicmp.la +icmp_unresolved_target_test_SOURCES=icmp_unresolved_target_test.c +icmp_unresolved_target_test_LDADD=testicmp.la + AM_CFLAGS=-g -Wall -W -rdynamic -DUNIT_TEST INCLUDES=-I../ -I../../ -I../../../common/ diff --git a/src/tests/icmp/test/icmp_unresolved_target_test.c b/src/tests/icmp/test/icmp_unresolved_target_test.c new file mode 100644 index 0000000..b2f8170 --- /dev/null +++ b/src/tests/icmp/test/icmp_unresolved_target_test.c @@ -0,0 +1,100 @@ +/* + * This file is part of amplet2. + * + * Copyright (c) 2013-2019 The University of Waikato, Hamilton, New Zealand. + * + * Author: Brendon Jones + * + * All rights reserved. + * + * This code has been developed by the University of Waikato WAND + * research group. For further information please see http://www.wand.net.nz/ + * + * amplet2 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations including + * the two. + * + * You must obey the GNU General Public License in all respects for all + * of the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do + * so, delete this exception statement from your version. If you delete + * this exception statement from all source files in the program, then + * also delete it here. + * + * amplet2 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with amplet2. If not, see . + */ + +#include +#include +#include +#include +#include + +#include "tests.h" +#include "icmp.h" +#include "icmp.pb-c.h" + +#define TEST_TARGET "doesnotexist.invalid" + +/* + * + */ +int main(void) { + amp_test_result_t *result; + struct addrinfo *target; + Amplet2__Icmp__Report *msg; + Amplet2__Icmp__Item *item; + + /* + * create a dummy addrinfo like the resolver does when it can't resolve + * the name + */ + target = calloc(1, sizeof(struct addrinfo)); + target->ai_family = AF_INET; + target->ai_canonname = TEST_TARGET; + + /* run the test against the dummy target */ + result = run_icmp(0, NULL, 1, &target); + + assert(result); + assert(result->data); + + /* check that the results are missing/empty in the right places */ + msg = amplet2__icmp__report__unpack(NULL, result->len, result->data); + + assert(msg); + assert(msg->header); + assert(msg->n_reports == 1); + assert(msg->reports); + + item = msg->reports[0]; + + assert(!item->has_address); + assert(item->has_family); + assert(item->family == AF_INET); + assert(!item->has_rtt); + assert(!item->has_err_type); + assert(!item->has_err_code); + assert(!item->has_ttl); + assert(strcmp(item->name, TEST_TARGET) == 0); + + amplet2__icmp__report__free_unpacked(msg, NULL); + free(result->data); + free(result); + free(target); + + return 0; +} diff --git a/src/tests/python/ampsave/tests/http.py b/src/tests/python/ampsave/tests/http.py index 0c0dc63..0868c15 100644 --- a/src/tests/python/ampsave/tests/http.py +++ b/src/tests/python/ampsave/tests/http.py @@ -50,8 +50,8 @@ def get_data(data): results = { "url": msg.header.url, - "duration": msg.header.duration, - "bytes": msg.header.total_bytes, + "duration": msg.header.duration if msg.header.duration > 0 else None, + "bytes": msg.header.total_bytes if msg.header.total_bytes > 0 else None, "server_count": len(msg.servers), "object_count": msg.header.total_objects, "keep_alive": msg.header.persist, @@ -84,18 +84,6 @@ def get_data(data): for obj in s.objects: if obj.code == 0: results["failed_object_count"] += 1 - # XXX can we report properly to prevent this? - # If there is only one server, with one object and that object - # has a code of zero, then we failed to fetch anything at all. - # Change the duration to None so the graphs properly interrupt - # the line. - if ( len(msg.servers) == 1 and - msg.header.total_objects == 1 and obj.code == 0 ): - results["duration"] = None - # TODO should we still add the object? - #results["object_count"] = 0 - #server["object_count"] = 0 - #break # Append this object to the list for this server server["objects"].append({ diff --git a/src/tests/python/ampsave/tests/icmp.py b/src/tests/python/ampsave/tests/icmp.py index 2ae7c32..49f0f21 100644 --- a/src/tests/python/ampsave/tests/icmp.py +++ b/src/tests/python/ampsave/tests/icmp.py @@ -61,7 +61,7 @@ def get_data(data): "ttl": i.ttl if i.HasField("ttl") else None, "packet_size": msg.header.packet_size, "random": msg.header.random, - "loss": 0 if i.HasField("rtt") else 1, + "loss": None if not i.HasField("address") else 0 if i.HasField("rtt") else 1, "dscp": getPrintableDscp(msg.header.dscp), } ) diff --git a/src/tests/python/ampsave/tests/tcpping.py b/src/tests/python/ampsave/tests/tcpping.py index d0ae066..99e4bb0 100644 --- a/src/tests/python/ampsave/tests/tcpping.py +++ b/src/tests/python/ampsave/tests/tcpping.py @@ -68,7 +68,7 @@ def get_data(data): "icmpcode": i.icmpcode if i.HasField("icmpcode") else None, "packet_size": msg.header.packet_size, "random": msg.header.random, - "loss": 0 if i.HasField("rtt") or i.HasField("icmptype") or i.HasField("icmpcode") else 1, + "loss": None if not i.HasField("address") else 0 if i.HasField("rtt") or i.HasField("icmptype") or i.HasField("icmpcode") else 1, "dscp": getPrintableDscp(msg.header.dscp), } ) diff --git a/src/tests/python/ampsave/tests/udpstream.py b/src/tests/python/ampsave/tests/udpstream.py index 25ce084..e6628c5 100644 --- a/src/tests/python/ampsave/tests/udpstream.py +++ b/src/tests/python/ampsave/tests/udpstream.py @@ -105,9 +105,9 @@ def get_data(data): "rtt": build_summary(i.rtt) if i.HasField("rtt") else None, "jitter": build_summary(i.jitter) if i.HasField("jitter") else None, "percentiles": i.percentiles, - "packets_received": i.packets_received, + "packets_received": i.packets_received if i.HasField("packets_received") else None, "loss_periods": build_loss_periods(i.loss_periods), - "loss_percent": i.loss_percent, + "loss_percent": i.loss_percent if i.HasField("loss_percent") else None, "voip": build_voip(i.voip) if i.HasField("voip") else None, } ) diff --git a/src/tests/tcpping/tcpping.c b/src/tests/tcpping/tcpping.c index 536aa70..904e252 100644 --- a/src/tests/tcpping/tcpping.c +++ b/src/tests/tcpping/tcpping.c @@ -763,6 +763,11 @@ static void send_packet(wand_event_handler_t *ev_hdl, void *evdata) { tp->info[tp->destindex].icmptype = 0; tp->info[tp->destindex].icmpcode = 0; + if ( !dest->ai_addr ) { + Log(LOG_INFO, "No address for target %s, skipping", dest->ai_canonname); + goto nextdest; + } + if ( dest->ai_family == AF_INET ) { srcport = tp->sourceportv4; sock = tp->raw_sockets.socket; @@ -1198,6 +1203,15 @@ void print_tcpping(amp_test_result_t *result) { item = msg->reports[i]; printf("%s", item->name); + + if ( !item->has_address ) { + /* couldn't resolve the target, didn't test to it */ + snprintf(addrstr, INET6_ADDRSTRLEN, "unresolved %s", + family_to_string(item->family)); + printf(" (%s) not tested\n", addrstr); + continue; + } + inet_ntop(item->family, item->address.data, addrstr, INET6_ADDRSTRLEN); printf(" (%s)", addrstr); diff --git a/src/tests/tcpping/test/Makefile.am b/src/tests/tcpping/test/Makefile.am index d9dde09..4f03890 100644 --- a/src/tests/tcpping/test/Makefile.am +++ b/src/tests/tcpping/test/Makefile.am @@ -1,5 +1,5 @@ -TESTS=tcpping_register.test tcpping_report.test -check_PROGRAMS=tcpping_register.test tcpping_report.test +TESTS=tcpping_register.test tcpping_report.test tcpping_unresolved_target.test +check_PROGRAMS=tcpping_register.test tcpping_report.test tcpping_unresolved_target.test check_LTLIBRARIES=testtcpping.la testtcpping_la_SOURCES=../tcpping.c ../pcapcapture.c @@ -13,5 +13,8 @@ tcpping_register_test_LDADD=testtcpping.la tcpping_report_test_SOURCES=tcpping_report_test.c tcpping_report_test_LDADD=testtcpping.la +tcpping_unresolved_target_test_SOURCES=tcpping_unresolved_target_test.c +tcpping_unresolved_target_test_LDADD=testtcpping.la + AM_CFLAGS=-g -Wall -W -rdynamic -DUNIT_TEST INCLUDES=-I../ -I../../ -I../../../common/ diff --git a/src/tests/tcpping/test/tcpping_unresolved_target_test.c b/src/tests/tcpping/test/tcpping_unresolved_target_test.c new file mode 100644 index 0000000..07dc267 --- /dev/null +++ b/src/tests/tcpping/test/tcpping_unresolved_target_test.c @@ -0,0 +1,103 @@ +/* + * This file is part of amplet2. + * + * Copyright (c) 2013-2019 The University of Waikato, Hamilton, New Zealand. + * + * Author: Brendon Jones + * + * All rights reserved. + * + * This code has been developed by the University of Waikato WAND + * research group. For further information please see http://www.wand.net.nz/ + * + * amplet2 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations including + * the two. + * + * You must obey the GNU General Public License in all respects for all + * of the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do + * so, delete this exception statement from your version. If you delete + * this exception statement from all source files in the program, then + * also delete it here. + * + * amplet2 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with amplet2. If not, see . + */ + +#include +#include +#include +#include +#include + +#include "tests.h" +#include "tcpping.h" +#include "tcpping.pb-c.h" + +#define TEST_TARGET "doesnotexist.invalid" + +/* + * + */ +int main(void) { + amp_test_result_t *result; + struct addrinfo *target; + Amplet2__Tcpping__Report *msg; + Amplet2__Tcpping__Item *item; + + /* + * create a dummy addrinfo like the resolver does when it can't resolve + * the name + */ + target = calloc(1, sizeof(struct addrinfo)); + target->ai_family = AF_INET; + target->ai_addrlen = 0; + target->ai_addr = NULL; + target->ai_canonname = TEST_TARGET; + target->ai_next = NULL; + + /* run the test against the dummy target */ + result = run_tcpping(0, NULL, 1, &target); + + assert(result); + assert(result->data); + + /* check that the results are missing/empty in the right places */ + msg = amplet2__tcpping__report__unpack(NULL, result->len, result->data); + + assert(msg); + assert(msg->header); + assert(msg->n_reports == 1); + assert(msg->reports); + + item = msg->reports[0]; + + assert(!item->has_address); + assert(item->has_family); + assert(item->family == AF_INET); + assert(!item->has_rtt); + assert(!item->has_icmptype); + assert(!item->has_icmpcode); + assert(!item->flags); + assert(strcmp(item->name, TEST_TARGET) == 0); + + amplet2__tcpping__report__free_unpacked(msg, NULL); + free(result->data); + free(result); + free(target); + + return 0; +} diff --git a/src/tests/throughput/test/Makefile.am b/src/tests/throughput/test/Makefile.am index 9740233..168c682 100644 --- a/src/tests/throughput/test/Makefile.am +++ b/src/tests/throughput/test/Makefile.am @@ -1,5 +1,5 @@ -TESTS=throughput_register.test throughput_hello.test throughput_ready.test throughput_request.test throughput_report.test -check_PROGRAMS=throughput_register.test throughput_hello.test throughput_ready.test throughput_request.test throughput_report.test +TESTS=throughput_register.test throughput_hello.test throughput_ready.test throughput_request.test throughput_report.test throughput_unresolved_target.test +check_PROGRAMS=throughput_register.test throughput_hello.test throughput_ready.test throughput_request.test throughput_report.test throughput_unresolved_target.test check_LTLIBRARIES=testthroughput.la testthroughput_la_SOURCES=../throughput.c ../throughput_server.c ../throughput_client.c ../throughput_common.c @@ -22,5 +22,8 @@ throughput_request_test_LDADD=testthroughput.la throughput_report_test_SOURCES=throughput_report_test.c throughput_report_test_LDADD=testthroughput.la +throughput_unresolved_target_test_SOURCES=throughput_unresolved_target_test.c +throughput_unresolved_target_test_LDADD=testthroughput.la + AM_CFLAGS=-g -Wall -W -rdynamic -DUNIT_TEST INCLUDES=-I../ -I../../ -I../../../common/ diff --git a/src/tests/throughput/test/throughput_unresolved_target_test.c b/src/tests/throughput/test/throughput_unresolved_target_test.c new file mode 100644 index 0000000..b09b660 --- /dev/null +++ b/src/tests/throughput/test/throughput_unresolved_target_test.c @@ -0,0 +1,102 @@ +/* + * This file is part of amplet2. + * + * Copyright (c) 2013-2019 The University of Waikato, Hamilton, New Zealand. + * + * Author: Brendon Jones + * + * All rights reserved. + * + * This code has been developed by the University of Waikato WAND + * research group. For further information please see http://www.wand.net.nz/ + * + * amplet2 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations including + * the two. + * + * You must obey the GNU General Public License in all respects for all + * of the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do + * so, delete this exception statement from your version. If you delete + * this exception statement from all source files in the program, then + * also delete it here. + * + * amplet2 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with amplet2. If not, see . + */ + +#include +#include +#include +#include +#include + +#include "tests.h" +#include "throughput.h" +#include "throughput.pb-c.h" + +#define TEST_TARGET "doesnotexist.invalid" + +/* + * + */ +int main(void) { + amp_test_result_t *result; + struct addrinfo *target; + Amplet2__Throughput__Report *msg; + Amplet2__Throughput__Item *item; + + /* + * create a dummy addrinfo like the resolver does when it can't resolve + * the name + */ + target = calloc(1, sizeof(struct addrinfo)); + target->ai_family = AF_INET; + target->ai_addrlen = 0; + target->ai_addr = NULL; + target->ai_canonname = TEST_TARGET; + target->ai_next = NULL; + + /* run the test against the dummy target */ + result = run_throughput(0, NULL, 1, &target); + + assert(result); + assert(result->data); + + /* check that the results are missing/empty in the right places */ + msg = amplet2__throughput__report__unpack(NULL, result->len, result->data); + + assert(msg); + assert(msg->header); + assert(!msg->header->has_address); + assert(msg->header->has_family); + assert(msg->header->family == AF_INET); + assert(msg->n_reports == 1); + assert(msg->reports); + + item = msg->reports[0]; + + assert(!item->has_duration); + assert(!item->has_bytes); + assert(item->has_direction); + assert(!item->tcpinfo); + + amplet2__throughput__report__free_unpacked(msg, NULL); + free(result->data); + free(result); + free(target); + + return 0; +} diff --git a/src/tests/throughput/throughput_client.c b/src/tests/throughput/throughput_client.c index 2727f99..1fe7681 100644 --- a/src/tests/throughput/throughput_client.c +++ b/src/tests/throughput/throughput_client.c @@ -249,15 +249,11 @@ static amp_test_result_t* report_results(uint64_t start_time, /* build up the repeated reports section with each of the results */ for ( i = 0, item = options->schedule; item != NULL; item = item->next ) { - /* only report on schedule items that send data */ + /* only report on schedule items that can possibly send data */ if ( item->type != TPUT_2_CLIENT && item->type != TPUT_2_SERVER ) { continue; } - if ( item->result == NULL ) { - continue; - } - reports = realloc(reports, sizeof(Amplet2__Throughput__Item*) * (i+1)); reports[i] = report_schedule(item); i++; @@ -501,7 +497,7 @@ amp_test_result_t* run_throughput_client(int argc, char *argv[], int count, char *client; int duration = -1; enum tput_schedule_direction direction = DIRECTION_NOT_SET; - amp_test_result_t *result; + amp_test_result_t *result = NULL; BIO *ctrl; char *address_string; int forcev4 = 0; @@ -714,39 +710,49 @@ amp_test_result_t* run_throughput_client(int argc, char *argv[], int count, /* Print out our schedule */ printSchedule(test_options.schedule); - /* connect to the control server to start/configure the test */ - if ( (ctrl=connect_control_server(dests[0], test_options.cport, - &sockopts)) == NULL ) { - Log(LOG_WARNING, "Failed to connect control server"); - return NULL; - } + if ( dests[0]->ai_addr != NULL ) { + /* connect to the control server to start/configure the test */ + if ( (ctrl=connect_control_server(dests[0], test_options.cport, + &sockopts)) == NULL ) { + Log(LOG_WARNING, "Failed to connect control server"); + goto done; + } - /* start the server if required (connected to an amplet) */ - if ( ssl_ctx && client == NULL ) { - Amplet2__Measured__Response response; + /* start the server if required (connected to an amplet) */ + if ( ssl_ctx && client == NULL ) { + Amplet2__Measured__Response response; - if ( start_remote_server(ctrl, AMP_TEST_THROUGHPUT) < 0 ) { - Log(LOG_WARNING, "Failed to start remote server"); - return NULL; - } + if ( start_remote_server(ctrl, AMP_TEST_THROUGHPUT) < 0 ) { + Log(LOG_WARNING, "Failed to start remote server"); + goto done; + } - /* make sure the server was started properly */ - if ( read_measured_response(ctrl, &response) < 0 ) { - Log(LOG_WARNING, "Failed to read server control response"); - return NULL; + /* make sure the server was started properly */ + if ( read_measured_response(ctrl, &response) < 0 ) { + Log(LOG_WARNING, "Failed to read server control response"); + goto done; + } + + /* TODO return something useful if this was remotely triggered? */ + if ( response.code != MEASURED_CONTROL_OK ) { + Log(LOG_WARNING, "Failed to start server: %d %s", response.code, + response.message); + goto done; + } } - /* TODO return something useful if this was remotely triggered? */ - if ( response.code != MEASURED_CONTROL_OK ) { - Log(LOG_WARNING, "Failed to start server: %d %s", response.code, - response.message); - return NULL; + result = runSchedule(dests[0], &test_options, &sockopts, ctrl); +done: + if ( ctrl ) { + close_control_connection(ctrl); } } - result = runSchedule(dests[0], &test_options, &sockopts, ctrl); - - close_control_connection(ctrl); + if ( result == NULL ) { + /* no valid destination or other error, report an empty result */ + result = report_results(timeNanoseconds() / 1000000000, dests[0], + &test_options); + } if ( client != NULL ) { freeaddrinfo(dests[0]); @@ -808,10 +814,16 @@ static void printDuration(uint64_t time_ns) { * Mb = 1000 * Kb etc */ static void printSpeed(uint64_t bytes, uint64_t time_ns) { - double x_per_sec = ((double)bytes * 8.0) / ((double) time_ns / 1e9); + double x_per_sec; char *units[] = {"bits", "Kbits", "Mbits", "Gbits", NULL}; char **unit; + if ( bytes == 0 || time_ns == 0 ) { + x_per_sec = 0; + } else { + x_per_sec = ((double)bytes * 8.0) / ((double) time_ns / 1e9); + } + for ( unit = units; *unit != NULL; unit++ ) { if ( x_per_sec < 1000 ) { printf(" at %.02lf %s/sec", x_per_sec, *unit); @@ -848,8 +860,13 @@ void print_throughput(amp_test_result_t *result) { /* print global configuration options */ printf("\n"); - inet_ntop(msg->header->family, msg->header->address.data, addrstr, - INET6_ADDRSTRLEN); + if ( msg->header->has_address ) { + inet_ntop(msg->header->family, msg->header->address.data, addrstr, + INET6_ADDRSTRLEN); + } else { + snprintf(addrstr, INET6_ADDRSTRLEN, "unresolved %s", + family_to_string(msg->header->family)); + } printf("AMP throughput test to %s (%s)\n", msg->header->name, addrstr); printf("writesize:%" PRIu32 " schedule:%s ", msg->header->write_size, msg->header->schedule); diff --git a/src/tests/throughput/throughput_common.c b/src/tests/throughput/throughput_common.c index 9d8d37e..27e5b00 100644 --- a/src/tests/throughput/throughput_common.c +++ b/src/tests/throughput/throughput_common.c @@ -192,6 +192,15 @@ Amplet2__Throughput__Item* report_schedule(struct test_request_t *info) { amplet2__throughput__item__init(item); item->has_direction = 1; item->direction = info->type; + + if ( info->result == NULL ) { + Log(LOG_DEBUG, "tput result: test did not run to %s", + (item->direction == + AMPLET2__THROUGHPUT__ITEM__DIRECTION__SERVER_TO_CLIENT) ? + "client" : "server"); + return item; + } + item->has_duration = 1; item->duration = info->result->end_ns - info->result->start_ns; item->has_bytes = 1; diff --git a/src/tests/traceroute/test/Makefile.am b/src/tests/traceroute/test/Makefile.am index 27d6f07..2f6fb44 100644 --- a/src/tests/traceroute/test/Makefile.am +++ b/src/tests/traceroute/test/Makefile.am @@ -1,5 +1,5 @@ -TESTS=traceroute_register.test traceroute_ipv4probe.test traceroute_ipv6probe.test -check_PROGRAMS=traceroute_register.test traceroute_ipv4probe.test traceroute_ipv6probe.test +TESTS=traceroute_register.test traceroute_ipv4probe.test traceroute_ipv6probe.test traceroute_unresolved_target.test +check_PROGRAMS=traceroute_register.test traceroute_ipv4probe.test traceroute_ipv6probe.test traceroute_unresolved_target.test check_LTLIBRARIES=testtraceroute.la testtraceroute_la_SOURCES=../traceroute.c ../as.c @@ -16,5 +16,8 @@ traceroute_ipv4probe_test_LDADD=testtraceroute.la traceroute_ipv6probe_test_SOURCES=traceroute_ipv6probe_test.c traceroute_ipv6probe_test_LDADD=testtraceroute.la +traceroute_unresolved_target_test_SOURCES=traceroute_unresolved_target_test.c +traceroute_unresolved_target_test_LDADD=testtraceroute.la + AM_CFLAGS=-g -Wall -W -rdynamic -DUNIT_TEST INCLUDES=-I../ -I../../ -I../../../common/ diff --git a/src/tests/traceroute/test/traceroute_unresolved_target_test.c b/src/tests/traceroute/test/traceroute_unresolved_target_test.c new file mode 100644 index 0000000..c0e7df1 --- /dev/null +++ b/src/tests/traceroute/test/traceroute_unresolved_target_test.c @@ -0,0 +1,103 @@ +/* + * This file is part of amplet2. + * + * Copyright (c) 2013-2019 The University of Waikato, Hamilton, New Zealand. + * + * Author: Brendon Jones + * + * All rights reserved. + * + * This code has been developed by the University of Waikato WAND + * research group. For further information please see http://www.wand.net.nz/ + * + * amplet2 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations including + * the two. + * + * You must obey the GNU General Public License in all respects for all + * of the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do + * so, delete this exception statement from your version. If you delete + * this exception statement from all source files in the program, then + * also delete it here. + * + * amplet2 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with amplet2. If not, see . + */ + +#include +#include +#include +#include +#include + +#include "tests.h" +#include "traceroute.h" +#include "traceroute.pb-c.h" + +#define TEST_TARGET "doesnotexist.invalid" + +/* + * + */ +int main(void) { + amp_test_result_t *result; + struct addrinfo *target; + Amplet2__Traceroute__Report *msg; + Amplet2__Traceroute__Item *item; + + /* + * create a dummy addrinfo like the resolver does when it can't resolve + * the name + */ + target = calloc(1, sizeof(struct addrinfo)); + target->ai_family = AF_INET; + target->ai_addrlen = 0; + target->ai_addr = NULL; + target->ai_canonname = TEST_TARGET; + target->ai_next = NULL; + + /* run the test against the dummy target */ + result = run_traceroute(0, NULL, 1, &target); + + assert(result); + assert(result->data); + + /* extract the results */ + msg = amplet2__traceroute__report__unpack(NULL, result->len, result->data); + + assert(msg); + assert(msg->header); + assert(msg->n_reports == 1); + assert(msg->reports); + + item = msg->reports[0]; + + /* check that the results are missing/empty in the right places */ + assert(!item->has_address); + assert(item->has_family); + assert(item->family == AF_INET); + assert(!item->has_err_type); + assert(!item->has_err_code); + assert(strcmp(item->name, TEST_TARGET) == 0); + assert(item->n_path == 0); + + amplet2__traceroute__report__free_unpacked(msg, NULL); + free(result->data); + free(result); + free(target); + + return 0; +} diff --git a/src/tests/traceroute/traceroute.c b/src/tests/traceroute/traceroute.c index 8f9ae0b..23a5aeb 100644 --- a/src/tests/traceroute/traceroute.c +++ b/src/tests/traceroute/traceroute.c @@ -160,6 +160,12 @@ static int send_probe(struct socket_t *ip_sockets, uint16_t ident, assert(ip_sockets); assert(info); + if ( info->addr->ai_addr == NULL ) { + Log(LOG_INFO, "No address for target %s, skipping", + info->addr->ai_canonname); + return -1; + } + memset(packet, 0, sizeof(packet)); id = (info->ttl << 10) + info->id; @@ -1789,7 +1795,15 @@ void print_traceroute(amp_test_result_t *result) { item = msg->reports[i]; printf("%s", item->name); - inet_ntop(item->family, item->address.data, addrstr, INET6_ADDRSTRLEN); + + if ( item->has_address ) { + inet_ntop(item->family, item->address.data, addrstr, + INET6_ADDRSTRLEN); + } else { + snprintf(addrstr, INET6_ADDRSTRLEN, "unresolved %s", + family_to_string(item->family)); + } + printf(" (%s)", addrstr); if ( item->has_err_type && item->has_err_code ) { diff --git a/src/tests/udpstream/test/Makefile.am b/src/tests/udpstream/test/Makefile.am index 10b2c9d..4a37053 100644 --- a/src/tests/udpstream/test/Makefile.am +++ b/src/tests/udpstream/test/Makefile.am @@ -1,5 +1,5 @@ -TESTS=udpstream_register.test udpstream_hello.test udpstream_ready.test udpstream_request.test -check_PROGRAMS=udpstream_register.test udpstream_hello.test udpstream_ready.test udpstream_request.test +TESTS=udpstream_register.test udpstream_hello.test udpstream_ready.test udpstream_request.test udpstream_unresolved_target.test +check_PROGRAMS=udpstream_register.test udpstream_hello.test udpstream_ready.test udpstream_request.test udpstream_unresolved_target.test check_LTLIBRARIES=testudpstream.la testudpstream_la_SOURCES=../udpstream.c ../udpstream_server.c ../udpstream_client.c ../udpstream_common.c ../mos.c @@ -19,5 +19,8 @@ udpstream_ready_test_LDADD=testudpstream.la udpstream_request_test_SOURCES=udpstream_request_test.c udpstream_request_test_LDADD=testudpstream.la +udpstream_unresolved_target_test_SOURCES=udpstream_unresolved_target_test.c +udpstream_unresolved_target_test_LDADD=testudpstream.la + AM_CFLAGS=-g -Wall -W -rdynamic -DUNIT_TEST INCLUDES=-I../ -I../../ -I../../../common/ diff --git a/src/tests/udpstream/test/udpstream_unresolved_target_test.c b/src/tests/udpstream/test/udpstream_unresolved_target_test.c new file mode 100644 index 0000000..fc49c0a --- /dev/null +++ b/src/tests/udpstream/test/udpstream_unresolved_target_test.c @@ -0,0 +1,107 @@ +/* + * This file is part of amplet2. + * + * Copyright (c) 2013-2019 The University of Waikato, Hamilton, New Zealand. + * + * Author: Brendon Jones + * + * All rights reserved. + * + * This code has been developed by the University of Waikato WAND + * research group. For further information please see http://www.wand.net.nz/ + * + * amplet2 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations including + * the two. + * + * You must obey the GNU General Public License in all respects for all + * of the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do + * so, delete this exception statement from your version. If you delete + * this exception statement from all source files in the program, then + * also delete it here. + * + * amplet2 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with amplet2. If not, see . + */ + +#include +#include +#include +#include +#include + +#include "tests.h" +#include "udpstream.h" +#include "udpstream.pb-c.h" + +#define TEST_TARGET "doesnotexist.invalid" + +/* + * + */ +int main(void) { + amp_test_result_t *result; + struct addrinfo *target; + Amplet2__Udpstream__Report *msg; + Amplet2__Udpstream__Item *item; + + /* + * create a dummy addrinfo like the resolver does when it can't resolve + * the name + */ + target = calloc(1, sizeof(struct addrinfo)); + target->ai_family = AF_INET; + target->ai_addrlen = 0; + target->ai_addr = NULL; + target->ai_canonname = TEST_TARGET; + target->ai_next = NULL; + + /* run the test against the dummy target */ + result = run_udpstream(0, NULL, 1, &target); + + assert(result); + assert(result->data); + + /* check that the results are missing/empty in the right places */ + msg = amplet2__udpstream__report__unpack(NULL, result->len, result->data); + + assert(msg); + assert(msg->header); + assert(!msg->header->has_address); + assert(msg->header->has_family); + assert(msg->header->family == AF_INET); + assert(msg->n_reports == 2); + assert(msg->reports); + + // TODO check both directions + item = msg->reports[0]; + + assert(item->has_direction); + assert(!item->rtt); + assert(!item->jitter); + assert(!item->percentiles); + assert(!item->has_packets_received); + assert(item->n_loss_periods == 0); + assert(!item->has_loss_percent); + assert(!item->voip); + + amplet2__udpstream__report__free_unpacked(msg, NULL); + free(result->data); + free(result); + free(target); + + return 0; +} diff --git a/src/tests/udpstream/udpstream_client.c b/src/tests/udpstream/udpstream_client.c index 65a6632..32da34f 100644 --- a/src/tests/udpstream/udpstream_client.c +++ b/src/tests/udpstream/udpstream_client.c @@ -356,7 +356,7 @@ amp_test_result_t* run_udpstream_client(int argc, char *argv[], int count, struct sockopt_t sockopts; char *client; extern struct option long_options[]; - amp_test_result_t *result; + amp_test_result_t *result = NULL; BIO *ctrl; char *address_string; int forcev4 = 0; @@ -521,39 +521,56 @@ amp_test_result_t* run_udpstream_client(int argc, char *argv[], int count, } #endif - /* connect to the control server to start/configure the test */ - if ( (ctrl=connect_control_server( - dests[0], test_options.cport, &sockopts)) == NULL ) { - Log(LOG_WARNING, "Failed to connect control server"); - return NULL; - } - - /* start the server if required (connected to an amplet) */ - if ( ssl_ctx && client == NULL ) { - Amplet2__Measured__Response response; - - if ( start_remote_server(ctrl, AMP_TEST_UDPSTREAM) < 0 ) { - Log(LOG_WARNING, "Failed to start remote server"); - return NULL; + if ( dests[0]->ai_addr != NULL ) { + /* connect to the control server to start/configure the test */ + if ( (ctrl=connect_control_server( + dests[0], test_options.cport, &sockopts)) == NULL ) { + Log(LOG_WARNING, "Failed to connect control server"); + goto end; } - /* make sure the server was started properly */ - if ( read_measured_response(ctrl, &response) < 0 ) { - Log(LOG_WARNING, "Failed to read server control response"); - return NULL; + /* start the server if required (connected to an amplet) */ + if ( ssl_ctx && client == NULL ) { + Amplet2__Measured__Response response; + + if ( start_remote_server(ctrl, AMP_TEST_UDPSTREAM) < 0 ) { + Log(LOG_WARNING, "Failed to start remote server"); + goto end; + } + + /* make sure the server was started properly */ + if ( read_measured_response(ctrl, &response) < 0 ) { + Log(LOG_WARNING, "Failed to read server control response"); + goto end; + } + + /* TODO return something useful if this was remotely triggered? */ + if ( response.code != MEASURED_CONTROL_OK ) { + Log(LOG_WARNING, "Failed to start server: %d %s", response.code, + response.message); + goto end; + } } - /* TODO return something useful if this was remotely triggered? */ - if ( response.code != MEASURED_CONTROL_OK ) { - Log(LOG_WARNING, "Failed to start server: %d %s", response.code, - response.message); - return NULL; + result = run_test(dests[0], &test_options, ctrl); +end: + if ( ctrl ) { + close_control_connection(ctrl); } } - result = run_test(dests[0], &test_options, ctrl); - - close_control_connection(ctrl); + if ( result == NULL ) { + Amplet2__Udpstream__Item *remote_results = NULL, *local_results = NULL; + struct timeval start_time; + gettimeofday(&start_time, NULL); + /* no valid destination, report an empty result */ + local_results = report_stream(UDPSTREAM_TO_CLIENT, NULL, NULL, + &test_options); + remote_results = report_stream(UDPSTREAM_TO_SERVER, NULL, NULL, + &test_options); + result = report_results(&start_time, dests[0], &test_options, + local_results, remote_results); + } if ( client != NULL ) { freeaddrinfo(dests[0]); @@ -597,6 +614,7 @@ static void print_item(Amplet2__Udpstream__Item *item, uint32_t packet_count) { return; } + /* TODO actually report number of packets sent not the expected value */ printf(" %d packets transmitted, %d received, %.02f%% packet loss\n", packet_count, item->packets_received, 100 - ((double)item->packets_received / (double)packet_count*100)); @@ -664,8 +682,13 @@ void print_udpstream(amp_test_result_t *result) { /* print global configuration options */ printf("\n"); - inet_ntop(msg->header->family, msg->header->address.data, addrstr, - INET6_ADDRSTRLEN); + if ( msg->header->has_address ) { + inet_ntop(msg->header->family, msg->header->address.data, addrstr, + INET6_ADDRSTRLEN); + } else { + snprintf(addrstr, INET6_ADDRSTRLEN, "unresolved %s", + family_to_string(msg->header->family)); + } printf("AMP udpstream test to %s (%s)\n", msg->header->name, addrstr); printf("packet count:%" PRIu32 ", size:%" PRIu32 " bytes, spacing:%" PRIu32 "us, DSCP:%s(0x%x)\n",