Merge pull request #2125 from RincewindsHat/refactor/check_icmp

Refactor check_icmp:

 - Far less global variables
 - Proper IPv6/legacy IP dual stack functionality (allowed mixed v4/v6 hosts)
 - Improved readability/understandability
 - General cleanup
This commit is contained in:
Lorenz Kästle 2025-06-20 11:29:07 +02:00 committed by GitHub
commit b8580c18e3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 1994 additions and 1349 deletions

View file

@ -4,7 +4,7 @@ TabWidth: 4
AllowShortIfStatementsOnASingleLine: false
BreakBeforeBraces: Attach
AlignConsecutiveMacros: true
ColumnLimit: 140
ColumnLimit: 100
IndentPPDirectives: AfterHash
SortIncludes: Never
AllowShortEnumsOnASingleLine: false

View file

@ -16,7 +16,8 @@ static mp_output_format output_format = MP_FORMAT_DEFAULT;
static mp_output_detail_level level_of_detail = MP_DETAIL_ALL;
// == Prototypes ==
static char *fmt_subcheck_output(mp_output_format output_format, mp_subcheck check, unsigned int indentation);
static char *fmt_subcheck_output(mp_output_format output_format, mp_subcheck check,
unsigned int indentation);
static inline cJSON *json_serialize_subcheck(mp_subcheck subcheck);
// == Implementation ==
@ -58,7 +59,9 @@ static inline char *fmt_subcheck_perfdata(mp_subcheck check) {
* It sets useful defaults
*/
mp_check mp_check_init(void) {
mp_check check = {0};
mp_check check = {
.evaluation_function = &mp_eval_check_default,
};
return check;
}
@ -121,7 +124,8 @@ void mp_add_perfdata_to_subcheck(mp_subcheck check[static 1], const mp_perfdata
*/
int mp_add_subcheck_to_subcheck(mp_subcheck check[static 1], mp_subcheck subcheck) {
if (subcheck.output == NULL) {
die(STATE_UNKNOWN, "%s - %s #%d: %s", __FILE__, __func__, __LINE__, "Sub check output is NULL");
die(STATE_UNKNOWN, "%s - %s #%d: %s", __FILE__, __func__, __LINE__,
"Sub check output is NULL");
}
mp_subcheck_list *tmp = NULL;
@ -194,18 +198,30 @@ char *get_subcheck_summary(mp_check check) {
return result;
}
mp_state_enum mp_compute_subcheck_state(const mp_subcheck subcheck) {
if (subcheck.evaluation_function == NULL) {
return mp_eval_subcheck_default(subcheck);
}
return subcheck.evaluation_function(subcheck);
}
/*
* Generate the result state of a mp_subcheck object based on it's own state and it's subchecks states
* Generate the result state of a mp_subcheck object based on its own state and its subchecks
* states
*/
mp_state_enum mp_compute_subcheck_state(const mp_subcheck check) {
if (check.state_set_explicitly) {
return check.state;
mp_state_enum mp_eval_subcheck_default(mp_subcheck subcheck) {
if (subcheck.evaluation_function != NULL) {
return subcheck.evaluation_function(subcheck);
}
mp_subcheck_list *scl = check.subchecks;
if (subcheck.state_set_explicitly) {
return subcheck.state;
}
mp_subcheck_list *scl = subcheck.subchecks;
if (scl == NULL) {
return check.default_state;
return subcheck.default_state;
}
mp_state_enum result = STATE_OK;
@ -218,10 +234,18 @@ mp_state_enum mp_compute_subcheck_state(const mp_subcheck check) {
return result;
}
mp_state_enum mp_compute_check_state(const mp_check check) {
// just a safety check
if (check.evaluation_function == NULL) {
return mp_eval_check_default(check);
}
return check.evaluation_function(check);
}
/*
* Generate the result state of a mp_check object based on it's own state and it's subchecks states
*/
mp_state_enum mp_compute_check_state(const mp_check check) {
mp_state_enum mp_eval_check_default(const mp_check check) {
assert(check.subchecks != NULL); // a mp_check without subchecks is invalid, die here
mp_subcheck_list *scl = check.subchecks;
@ -253,8 +277,10 @@ char *mp_fmt_output(mp_check check) {
mp_subcheck_list *subchecks = check.subchecks;
while (subchecks != NULL) {
if (level_of_detail == MP_DETAIL_ALL || mp_compute_subcheck_state(subchecks->subcheck) != STATE_OK) {
asprintf(&result, "%s\n%s", result, fmt_subcheck_output(MP_FORMAT_MULTI_LINE, subchecks->subcheck, 1));
if (level_of_detail == MP_DETAIL_ALL ||
mp_compute_subcheck_state(subchecks->subcheck) != STATE_OK) {
asprintf(&result, "%s\n%s", result,
fmt_subcheck_output(MP_FORMAT_MULTI_LINE, subchecks->subcheck, 1));
}
subchecks = subchecks->next;
}
@ -266,7 +292,8 @@ char *mp_fmt_output(mp_check check) {
if (pd_string == NULL) {
asprintf(&pd_string, "%s", fmt_subcheck_perfdata(subchecks->subcheck));
} else {
asprintf(&pd_string, "%s %s", pd_string, fmt_subcheck_perfdata(subchecks->subcheck));
asprintf(&pd_string, "%s %s", pd_string,
fmt_subcheck_perfdata(subchecks->subcheck));
}
subchecks = subchecks->next;
@ -335,19 +362,21 @@ static char *generate_indentation_string(unsigned int indentation) {
/*
* Helper function to generate the output string of mp_subcheck
*/
static inline char *fmt_subcheck_output(mp_output_format output_format, mp_subcheck check, unsigned int indentation) {
static inline char *fmt_subcheck_output(mp_output_format output_format, mp_subcheck check,
unsigned int indentation) {
char *result = NULL;
mp_subcheck_list *subchecks = NULL;
switch (output_format) {
case MP_FORMAT_MULTI_LINE:
asprintf(&result, "%s\\_[%s] - %s", generate_indentation_string(indentation), state_text(mp_compute_subcheck_state(check)),
check.output);
asprintf(&result, "%s\\_[%s] - %s", generate_indentation_string(indentation),
state_text(mp_compute_subcheck_state(check)), check.output);
subchecks = check.subchecks;
while (subchecks != NULL) {
asprintf(&result, "%s\n%s", result, fmt_subcheck_output(output_format, subchecks->subcheck, indentation + 1));
asprintf(&result, "%s\n%s", result,
fmt_subcheck_output(output_format, subchecks->subcheck, indentation + 1));
subchecks = subchecks->next;
}
return result;
@ -551,3 +580,23 @@ mp_output_format mp_get_format(void) { return output_format; }
void mp_set_level_of_detail(mp_output_detail_level level) { level_of_detail = level; }
mp_output_detail_level mp_get_level_of_detail(void) { return level_of_detail; }
mp_state_enum mp_eval_ok(mp_check overall) {
(void)overall;
return STATE_OK;
}
mp_state_enum mp_eval_warning(mp_check overall) {
(void)overall;
return STATE_WARNING;
}
mp_state_enum mp_eval_critical(mp_check overall) {
(void)overall;
return STATE_CRITICAL;
}
mp_state_enum mp_eval_unknown(mp_check overall) {
(void)overall;
return STATE_UNKNOWN;
}

View file

@ -7,15 +7,21 @@
/*
* A partial check result
*/
typedef struct {
typedef struct mp_subcheck mp_subcheck;
struct mp_subcheck {
mp_state_enum state; // OK, Warning, Critical ... set explicitly
mp_state_enum default_state; // OK, Warning, Critical .. if not set explicitly
bool state_set_explicitly; // was the state set explicitly (or should it be derived from subchecks)
bool state_set_explicitly; // was the state set explicitly (or should it be derived from
// subchecks)
char *output; // Text output for humans ("Filesystem xyz is fine", "Could not create TCP connection to..")
pd_list *perfdata; // Performance data for this check
char *output; // Text output for humans ("Filesystem xyz is fine", "Could not create TCP
// connection to..")
pd_list *perfdata; // Performance data for this check
struct subcheck_list *subchecks; // subchecks deeper in the hierarchy
} mp_subcheck;
// the evaluation_functions computes the state of subcheck
mp_state_enum (*evaluation_function)(mp_subcheck);
};
/*
* A list of subchecks, used in subchecks and the main check
@ -57,10 +63,14 @@ mp_output_detail_level mp_get_level_of_detail(void);
* The final result is always derived from the children and the "worst" state
* in the first layer of subchecks
*/
typedef struct {
typedef struct mp_check mp_check;
struct mp_check {
char *summary; // Overall summary, if not set a summary will be automatically generated
mp_subcheck_list *subchecks;
} mp_check;
// the evaluation_functions computes the state of check
mp_state_enum (*evaluation_function)(mp_check);
};
mp_check mp_check_init(void);
mp_subcheck mp_subcheck_init(void);
@ -78,6 +88,13 @@ void mp_add_summary(mp_check check[static 1], char *summary);
mp_state_enum mp_compute_check_state(mp_check);
mp_state_enum mp_compute_subcheck_state(mp_subcheck);
mp_state_enum mp_eval_ok(mp_check overall);
mp_state_enum mp_eval_warning(mp_check overall);
mp_state_enum mp_eval_critical(mp_check overall);
mp_state_enum mp_eval_unknown(mp_check overall);
mp_state_enum mp_eval_check_default(mp_check check);
mp_state_enum mp_eval_subcheck_default(mp_subcheck subcheck);
typedef struct {
bool parsing_success;
mp_output_format output_format;

View file

@ -257,6 +257,10 @@ mp_perfdata mp_set_pd_value_double(mp_perfdata pd, double value) {
return pd;
}
mp_perfdata mp_set_pd_value_char(mp_perfdata pd, char value) { return mp_set_pd_value_long_long(pd, (long long)value); }
mp_perfdata mp_set_pd_value_u_char(mp_perfdata pd, unsigned char value) { return mp_set_pd_value_u_long_long(pd, (unsigned long long)value); }
mp_perfdata mp_set_pd_value_int(mp_perfdata pd, int value) { return mp_set_pd_value_long_long(pd, (long long)value); }
mp_perfdata mp_set_pd_value_u_int(mp_perfdata pd, unsigned int value) { return mp_set_pd_value_u_long_long(pd, (unsigned long long)value); }
@ -288,6 +292,10 @@ mp_perfdata_value mp_create_pd_value_double(double value) {
mp_perfdata_value mp_create_pd_value_float(float value) { return mp_create_pd_value_double((double)value); }
mp_perfdata_value mp_create_pd_value_char(char value) { return mp_create_pd_value_long_long((long long)value); }
mp_perfdata_value mp_create_pd_value_u_char(unsigned char value) { return mp_create_pd_value_u_long_long((unsigned long long)value); }
mp_perfdata_value mp_create_pd_value_int(int value) { return mp_create_pd_value_long_long((long long)value); }
mp_perfdata_value mp_create_pd_value_u_int(unsigned int value) { return mp_create_pd_value_u_long_long((unsigned long long)value); }

View file

@ -155,6 +155,8 @@ mp_perfdata mp_set_pd_value_u_long_long(mp_perfdata, unsigned long long);
_Generic((V), \
float: mp_create_pd_value_float, \
double: mp_create_pd_value_double, \
char: mp_create_pd_value_char, \
unsigned char: mp_create_pd_value_u_char, \
int: mp_create_pd_value_int, \
unsigned int: mp_create_pd_value_u_int, \
long: mp_create_pd_value_long, \
@ -164,6 +166,8 @@ mp_perfdata mp_set_pd_value_u_long_long(mp_perfdata, unsigned long long);
mp_perfdata_value mp_create_pd_value_float(float);
mp_perfdata_value mp_create_pd_value_double(double);
mp_perfdata_value mp_create_pd_value_char(char);
mp_perfdata_value mp_create_pd_value_u_char(unsigned char);
mp_perfdata_value mp_create_pd_value_int(int);
mp_perfdata_value mp_create_pd_value_u_int(unsigned int);
mp_perfdata_value mp_create_pd_value_long(long);

View file

@ -24,7 +24,8 @@ noinst_PROGRAMS = check_dhcp check_icmp @EXTRAS_ROOT@
EXTRA_PROGRAMS = pst3
EXTRA_DIST = t pst3.c
EXTRA_DIST = t pst3.c \
check_icmp.d
BASEOBJS = ../plugins/utils.o ../lib/libmonitoringplug.a ../gl/libgnu.a
NETOBJS = ../plugins/netutils.o $(BASEOBJS) $(EXTRA_NETOBJS)
@ -82,6 +83,7 @@ install-exec-local: $(noinst_PROGRAMS)
# the actual targets
check_dhcp_LDADD = @LTLIBINTL@ $(NETLIBS) $(LIB_CRYPTO)
check_icmp_LDADD = @LTLIBINTL@ $(NETLIBS) $(SOCKETLIBS) $(LIB_CRYPTO)
check_icmp_SOURCES = check_icmp.c check_icmp.d/check_icmp_helpers.c
# -m64 needed at compiler and linker phase
pst3_CFLAGS = @PST3CFLAGS@
@ -89,7 +91,7 @@ pst3_LDFLAGS = @PST3CFLAGS@
# pst3 must not use monitoringplug/gnulib includes!
pst3_CPPFLAGS =
check_dhcp_DEPENDENCIES = check_dhcp.c $(NETOBJS) $(DEPLIBS)
check_dhcp_DEPENDENCIES = check_dhcp.c $(NETOBJS) $(DEPLIBS)
check_icmp_DEPENDENCIES = check_icmp.c $(NETOBJS)
clean-local:

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,134 @@
#include "./config.h"
#include <math.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include "./check_icmp_helpers.h"
#include "../../plugins/netutils.h"
// timeout as a global variable to make it available to the timeout handler
unsigned int timeout = DEFAULT_TIMEOUT;
check_icmp_config check_icmp_config_init() {
check_icmp_config tmp = {
.modes =
{
.order_mode = false,
.mos_mode = false,
.rta_mode = false,
.pl_mode = false,
.jitter_mode = false,
.score_mode = false,
},
.min_hosts_alive = -1,
.crit = {.pl = DEFAULT_CRIT_PL,
.rta = DEFAULT_CRIT_RTA,
.jitter = 50.0,
.mos = 3.0,
.score = 70.0},
.warn = {.pl = DEFAULT_WARN_PL,
.rta = DEFAULT_WARN_RTA,
.jitter = 40.0,
.mos = 3.5,
.score = 80.0},
.ttl = DEFAULT_TTL,
.icmp_data_size = DEFAULT_PING_DATA_SIZE,
.icmp_pkt_size = DEFAULT_PING_DATA_SIZE + ICMP_MINLEN,
.pkt_interval = DEFAULT_PKT_INTERVAL,
.target_interval = 0,
.number_of_packets = DEFAULT_NUMBER_OF_PACKETS,
.source_ip = NULL,
.need_v4 = false,
.need_v6 = false,
.sender_id = 0,
.mode = MODE_RTA,
.number_of_targets = 0,
.targets = NULL,
.number_of_hosts = 0,
.hosts = NULL,
};
return tmp;
}
ping_target ping_target_init() {
ping_target tmp = {
.rtmin = INFINITY,
.jitter_min = INFINITY,
.found_out_of_order_packets = false,
};
return tmp;
}
check_icmp_state check_icmp_state_init() {
check_icmp_state tmp = {.icmp_sent = 0, .icmp_lost = 0, .icmp_recv = 0, .targets_down = 0};
return tmp;
}
ping_target_create_wrapper ping_target_create(struct sockaddr_storage address) {
ping_target_create_wrapper result = {
.errorcode = OK,
};
struct sockaddr_storage *tmp_addr = &address;
/* disregard obviously stupid addresses
* (I didn't find an ipv6 equivalent to INADDR_NONE) */
if (((tmp_addr->ss_family == AF_INET &&
(((struct sockaddr_in *)tmp_addr)->sin_addr.s_addr == INADDR_NONE ||
((struct sockaddr_in *)tmp_addr)->sin_addr.s_addr == INADDR_ANY))) ||
(tmp_addr->ss_family == AF_INET6 &&
(((struct sockaddr_in6 *)tmp_addr)->sin6_addr.s6_addr == in6addr_any.s6_addr))) {
result.errorcode = ERROR;
return result;
}
/* add the fresh ip */
ping_target target = ping_target_init();
/* fill out the sockaddr_storage struct */
target.address = address;
result.host = target;
return result;
}
check_icmp_target_container check_icmp_target_container_init() {
check_icmp_target_container tmp = {
.name = NULL,
.number_of_targets = 0,
.target_list = NULL,
};
return tmp;
}
unsigned int ping_target_list_append(ping_target *list, ping_target *elem) {
if (elem == NULL || list == NULL) {
return 0;
}
while (list->next != NULL) {
list = list->next;
}
list->next = elem;
unsigned int result = 1;
while (elem->next != NULL) {
result++;
elem = elem->next;
}
return result;
}

View file

@ -0,0 +1,68 @@
#pragma once
#include "../../lib/states.h"
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
#include <netinet/ip_icmp.h>
#include <netinet/icmp6.h>
#include <arpa/inet.h>
typedef struct ping_target {
unsigned short id; /* id in **table, and icmp pkts */
char *msg; /* icmp error message, if any */
struct sockaddr_storage address; /* the address of this host */
struct sockaddr_storage error_addr; /* stores address of error replies */
time_t time_waited; /* total time waited, in usecs */
unsigned int icmp_sent, icmp_recv, icmp_lost; /* counters */
unsigned char icmp_type, icmp_code; /* type and code from errors */
unsigned short flags; /* control/status flags */
double rtmax; /* max rtt */
double rtmin; /* min rtt */
double jitter; /* measured jitter */
double jitter_max; /* jitter rtt maximum */
double jitter_min; /* jitter rtt minimum */
time_t last_tdiff;
unsigned int last_icmp_seq; /* Last ICMP_SEQ to check out of order pkts */
bool found_out_of_order_packets;
struct ping_target *next;
} ping_target;
ping_target ping_target_init();
typedef struct {
char *name;
ping_target *target_list;
unsigned int number_of_targets;
} check_icmp_target_container;
check_icmp_target_container check_icmp_target_container_init();
typedef struct {
unsigned int icmp_sent;
unsigned int icmp_recv;
unsigned int icmp_lost;
unsigned short targets_down;
} check_icmp_state;
check_icmp_state check_icmp_state_init();
typedef struct {
int errorcode;
ping_target host;
} ping_target_create_wrapper;
typedef struct {
int socket4;
int socket6;
} check_icmp_socket_set;
ping_target_create_wrapper ping_target_create(struct sockaddr_storage address);
unsigned int ping_target_list_append(ping_target *list, ping_target *elem);

View file

@ -0,0 +1,111 @@
#pragma once
#include "../../config.h"
#include "../../lib/states.h"
#include <stddef.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
#include <netinet/ip_icmp.h>
#include <netinet/icmp6.h>
#include <arpa/inet.h>
#include <stdint.h>
#include "./check_icmp_helpers.h"
/* threshold structure. all values are maximum allowed, exclusive */
typedef struct {
unsigned char pl; /* max allowed packet loss in percent */
time_t rta; /* roundtrip time average, microseconds */
double jitter; /* jitter time average, microseconds */
double mos; /* MOS */
double score; /* Score */
} check_icmp_threshold;
/* the different modes of this program are as follows:
* MODE_RTA: send all packets no matter what (mimic check_icmp and check_ping)
* MODE_HOSTCHECK: Return immediately upon any sign of life
* In addition, sends packets to ALL addresses assigned
* to this host (as returned by gethostbyname() or
* gethostbyaddr() and expects one host only to be checked at
* a time. Therefore, any packet response what so ever will
* count as a sign of life, even when received outside
* crit.rta limit. Do not misspell any additional IP's.
* MODE_ALL: Requires packets from ALL requested IP to return OK (default).
* MODE_ICMP: Default Mode
*/
typedef enum {
MODE_RTA,
MODE_HOSTCHECK,
MODE_ALL,
MODE_ICMP,
} check_icmp_execution_mode;
typedef struct {
bool order_mode;
bool mos_mode;
bool rta_mode;
bool pl_mode;
bool jitter_mode;
bool score_mode;
} check_icmp_mode_switches;
typedef struct {
check_icmp_mode_switches modes;
int min_hosts_alive;
check_icmp_threshold crit;
check_icmp_threshold warn;
unsigned long ttl;
unsigned short icmp_data_size;
unsigned short icmp_pkt_size;
time_t pkt_interval;
time_t target_interval;
unsigned short number_of_packets;
char *source_ip;
bool need_v4;
bool need_v6;
uint16_t sender_id; // PID of the main process, which is used as an ID in packets
check_icmp_execution_mode mode;
unsigned short number_of_targets;
ping_target *targets;
unsigned short number_of_hosts;
check_icmp_target_container *hosts;
} check_icmp_config;
check_icmp_config check_icmp_config_init();
/* the data structure */
typedef struct icmp_ping_data {
struct timeval stime; /* timestamp (saved in protocol struct as well) */
unsigned short ping_id;
} icmp_ping_data;
#define MAX_IP_PKT_SIZE 65536 /* (theoretical) max IP packet size */
#define IP_HDR_SIZE 20
#define MAX_PING_DATA (MAX_IP_PKT_SIZE - IP_HDR_SIZE - ICMP_MINLEN)
#define MIN_PING_DATA_SIZE sizeof(struct icmp_ping_data)
#define DEFAULT_PING_DATA_SIZE (MIN_PING_DATA_SIZE + 44)
/* 80 msec packet interval by default */
#define DEFAULT_PKT_INTERVAL 80000
#define DEFAULT_TARGET_INTERVAL 0
#define DEFAULT_WARN_RTA 200000
#define DEFAULT_CRIT_RTA 500000
#define DEFAULT_WARN_PL 40
#define DEFAULT_CRIT_PL 80
#define DEFAULT_TIMEOUT 10
#define DEFAULT_TTL 64
#define DEFAULT_NUMBER_OF_PACKETS 5
#define PACKET_BACKOFF_FACTOR 1.5
#define TARGET_BACKOFF_FACTOR 1.5

View file

@ -12,15 +12,12 @@ my $allow_sudo = getTestParameter( "NP_ALLOW_SUDO",
"no" );
if ($allow_sudo eq "yes" or $> == 0) {
plan tests => 40;
plan tests => 17;
} else {
plan skip_all => "Need sudo to test check_icmp";
}
my $sudo = $> == 0 ? '' : 'sudo';
my $successOutput = '/OK - .*? rta (?:[\d\.]+ms)|(?:nan), lost \d+%/';
my $failureOutput = '/(WARNING|CRITICAL) - .*? rta (?:[\d\.]+ms > [\d\.]+ms|nan)/';
my $host_responsive = getTestParameter( "NP_HOST_RESPONSIVE",
"The hostname of system responsive to network requests",
"localhost" );
@ -36,108 +33,85 @@ my $hostname_invalid = getTestParameter( "NP_HOSTNAME_INVALID",
my $res;
$res = NPTest->testCmd(
"$sudo ./check_icmp -H $host_responsive -w 10000ms,100% -c 10000ms,100%"
"$sudo ./check_icmp -H $host_responsive -w 100ms,100% -c 100ms,100%"
);
is( $res->return_code, 0, "Syntax ok" );
like( $res->output, $successOutput, "Output OK" );
$res = NPTest->testCmd(
"$sudo ./check_icmp -H $host_responsive -w 0ms,0% -c 10000ms,100%"
"$sudo ./check_icmp -H $host_responsive -w 0ms,0% -c 100ms,100%"
);
is( $res->return_code, 1, "Syntax ok, with forced warning" );
like( $res->output, $failureOutput, "Output OK" );
$res = NPTest->testCmd(
"$sudo ./check_icmp -H $host_responsive -w 0,0% -c 0,0%"
);
is( $res->return_code, 2, "Syntax ok, with forced critical" );
like( $res->output, $failureOutput, "Output OK" );
$res = NPTest->testCmd(
"$sudo ./check_icmp -H $host_nonresponsive -w 10000ms,100% -c 10000ms,100% -t 2"
"$sudo ./check_icmp -H $host_nonresponsive -w 100ms,100% -c 100ms,100%"
);
is( $res->return_code, 2, "Timeout - host nonresponsive" );
like( $res->output, '/pl=100%/', "Error contains 'pl=100%' string (for 100% packet loss)" );
like( $res->output, '/rta=U/', "Error contains 'rta=U' string" );
$res = NPTest->testCmd(
"$sudo ./check_icmp -w 10000ms,100% -c 10000ms,100%"
"$sudo ./check_icmp -w 100ms,100% -c 100ms,100%"
);
is( $res->return_code, 3, "No hostname" );
like( $res->output, '/No hosts to check/', "Output with appropriate error message");
$res = NPTest->testCmd(
"$sudo ./check_icmp -H $host_nonresponsive -w 10000ms,100% -c 10000ms,100% -n 1 -m 0 -t 2"
"$sudo ./check_icmp -H $host_nonresponsive -w 100ms,100% -c 100ms,100% -n 1 -m 0"
);
is( $res->return_code, 0, "One host nonresponsive - zero required" );
like( $res->output, $successOutput, "Output OK" );
$res = NPTest->testCmd(
"$sudo ./check_icmp -H $host_responsive -H $host_nonresponsive -w 10000ms,100% -c 10000ms,100% -n 1 -m 1 -t 2"
"$sudo ./check_icmp -H $host_responsive -H $host_nonresponsive -w 100ms,100% -c 100ms,100% -n 1 -m 1"
);
is( $res->return_code, 0, "One of two host nonresponsive - one required" );
like( $res->output, $successOutput, "Output OK" );
$res = NPTest->testCmd(
"$sudo ./check_icmp -H $host_responsive -H $host_nonresponsive -w 10000ms,100% -c 10000ms,100% -n 1 -m 2"
"$sudo ./check_icmp -H $host_responsive -H $host_nonresponsive -w 100ms,100% -c 100ms,100% -n 1 -m 2"
);
is( $res->return_code, 2, "One of two host nonresponsive - two required" );
like( $res->output, $failureOutput, "Output OK" );
$res = NPTest->testCmd(
"$sudo ./check_icmp -H $host_responsive -s 127.0.15.15 -w 10000ms,100% -c 10000ms,100% -n 1 -m 2"
"$sudo ./check_icmp -H $host_responsive -s 127.0.15.15 -w 100ms,100% -c 100ms,100% -n 1"
);
is( $res->return_code, 0, "IPv4 source_ip accepted" );
like( $res->output, $successOutput, "Output OK" );
$res = NPTest->testCmd(
"$sudo ./check_icmp -H $host_responsive -b 65507"
);
is( $res->return_code, 0, "Try max packet size" );
like( $res->output, $successOutput, "Output OK - Didn't overflow" );
$res = NPTest->testCmd(
"$sudo ./check_icmp -H $host_responsive -R 100,100 -n 1 -t 2"
"$sudo ./check_icmp -H $host_responsive -R 100,100 -n 1"
);
is( $res->return_code, 0, "rta works" );
like( $res->output, $successOutput, "Output OK" );
$res = NPTest->testCmd(
"$sudo ./check_icmp -H $host_responsive -P 80,90 -n 1 -t 2"
"$sudo ./check_icmp -H $host_responsive -P 80,90 -n 1"
);
is( $res->return_code, 0, "pl works" );
like( $res->output, '/lost 0%/', "Output OK" );
$res = NPTest->testCmd(
"$sudo ./check_icmp -H $host_responsive -J 80,90 -t 2"
"$sudo ./check_icmp -H $host_responsive -J 80,90"
);
is( $res->return_code, 0, "jitter works" );
like( $res->output, '/jitter \d/', "Output OK" );
$res = NPTest->testCmd(
"$sudo ./check_icmp -H $host_responsive -M 4,3 -t 2"
"$sudo ./check_icmp -H $host_responsive -M 4,3"
);
is( $res->return_code, 0, "mos works" );
like( $res->output, '/MOS \d/', "Output OK" );
$res = NPTest->testCmd(
"$sudo ./check_icmp -H $host_responsive -S 80,70 -t 2"
"$sudo ./check_icmp -H $host_responsive -S 80,70"
);
is( $res->return_code, 0, "score works" );
like( $res->output, '/Score \d/', "Output OK" );
$res = NPTest->testCmd(
"$sudo ./check_icmp -H $host_responsive -O -t 2"
"$sudo ./check_icmp -H $host_responsive -O"
);
is( $res->return_code, 0, "order works" );
like( $res->output, '/Packets in order/', "Output OK" );
$res = NPTest->testCmd(
"$sudo ./check_icmp -H $host_responsive -O -S 80,70 -M 4,3 -J 80,90 -P 80,90 -R 100,100 -t 2"
"$sudo ./check_icmp -H $host_responsive -O -S 80,70 -M 4,3 -J 80,90 -P 80,90 -R 100,100"
);
is( $res->return_code, 0, "order works" );
like( $res->output, '/Packets in order/', "Output OK" );
like( $res->output, '/Score \d/', "Output OK" );
like( $res->output, '/MOS \d/', "Output OK" );
like( $res->output, '/jitter \d/', "Output OK" );
like( $res->output, '/lost 0%/', "Output OK" );
like( $res->output, $successOutput, "Output OK" );

View file

@ -76,7 +76,7 @@ char *strnl(char *);
char *strpcpy(char *, const char *, const char *);
char *strpcat(char *, const char *, const char *);
int xvasprintf(char **strp, const char *fmt, va_list ap);
int xasprintf(char **strp, const char *fmt, ...);
int xasprintf(char **strp, const char *fmt, ...)__attribute__ ((format (printf, 2, 3)));
void usage(const char *) __attribute__((noreturn));
void usage2(const char *, const char *) __attribute__((noreturn));