X-Git-Url: https://git.verplant.org/?a=blobdiff_plain;f=src%2Foping.c;h=37f5fa91bc27c3e658ce06fd6b399c9f58ea9f8e;hb=da49de54bda467c696f4446e6cdfdd8960ca78ed;hp=84d97afdb7206fbded38f47fa898769519fecbad;hpb=8192d9020a3299f3e8ada094ba8b95fb776d0b56;p=liboping.git diff --git a/src/oping.c b/src/oping.c index 84d97af..37f5fa9 100644 --- a/src/oping.c +++ b/src/oping.c @@ -1,6 +1,6 @@ /** * Object oriented C module to send ICMP and ICMPv6 `echo's. - * Copyright (C) 2006-2010 Florian octo Forster + * Copyright (C) 2006-2011 Florian octo Forster * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -89,6 +89,11 @@ # define _POSIX_SAVED_IDS 0 #endif +/* Remove GNU specific __attribute__ settings when using another compiler */ +#if !__GNUC__ +# define __attribute__(x) /**/ +#endif + typedef struct ping_context { char host[NI_MAXHOST]; @@ -116,6 +121,7 @@ static char *opt_filename = NULL; static int opt_count = -1; static int opt_send_ttl = 64; static uint8_t opt_send_qos = 0; +static double opt_exit_status_threshold = 1.0; static int host_num = 0; @@ -247,10 +253,6 @@ static int ping_initialize_contexts (pingobj_t *ping) /* {{{ */ static void usage_exit (const char *name, int status) /* {{{ */ { - int name_length; - - name_length = (int) strlen (name); - fprintf (stderr, "Usage: %s [OPTIONS] " "-f filename | host [host [host ...]]\n" @@ -264,6 +266,8 @@ static void usage_exit (const char *name, int status) /* {{{ */ " -I srcaddr source address\n" " -D device outgoing interface name\n" " -f filename filename to read hosts from\n" + " -Z percent Exit with non-zero exit status if more than this percentage of\n" + " probes timed out. (default: never)\n" "\noping "PACKAGE_VERSION", http://verplant.org/liboping/\n" "by Florian octo Forster \n" @@ -272,6 +276,7 @@ static void usage_exit (const char *name, int status) /* {{{ */ exit (status); } /* }}} void usage_exit */ +__attribute__((noreturn)) static void usage_qos_exit (const char *arg, int status) /* {{{ */ { if (arg != 0) @@ -284,6 +289,8 @@ static void usage_qos_exit (const char *arg, int status) /* {{{ */ " be Best Effort (BE, default PHB).\n" " ef Expedited Forwarding (EF) PHB group (RFC 3246).\n" " (low delay, low loss, low jitter)\n" + " va Voice Admit (VA) DSCP (RFC 5865).\n" + " (capacity-admitted traffic)\n" " af[1-4][1-3] Assured Forwarding (AF) PHB group (RFC 2597).\n" " For example: \"af12\" (class 1, precedence 2)\n" " cs[0-7] Class Selector (CS) PHB group (RFC 2474).\n" @@ -323,13 +330,16 @@ static int set_opt_send_qos (const char *opt) /* {{{ */ /* - Expedited Forwarding (EF, RFC 3246) */ else if (strcasecmp ("ef", opt) == 0) opt_send_qos = 0xB8; /* == 0x2E << 2 */ + /* - Voice Admit (VA, RFC 5865) */ + else if (strcasecmp ("va", opt) == 0) + opt_send_qos = 0xB0; /* == 0x2D << 2 */ /* - Assured Forwarding (AF, RFC 2597) */ else if ((strncasecmp ("af", opt, strlen ("af")) == 0) && (strlen (opt) == 4)) { uint8_t dscp; - uint8_t class; - uint8_t prec; + uint8_t class = 0; + uint8_t prec = 0; /* There are four classes, AF1x, AF2x, AF3x, and AF4x. */ if (opt[2] == '1') @@ -414,6 +424,7 @@ static char *format_qos (uint8_t qos, char *buffer, size_t buffer_size) /* {{{ * { case 0x00: dscp_str = "be"; break; case 0x2e: dscp_str = "ef"; break; + case 0x2d: dscp_str = "va"; break; case 0x0a: dscp_str = "af11"; break; case 0x0c: dscp_str = "af12"; break; case 0x0e: dscp_str = "af13"; break; @@ -459,7 +470,7 @@ static int read_options (int argc, char **argv) /* {{{ */ while (1) { - optchar = getopt (argc, argv, "46c:hi:I:t:Q:f:D:"); + optchar = getopt (argc, argv, "46c:hi:I:t:Q:f:D:Z:"); if (optchar == -1) break; @@ -530,6 +541,24 @@ static int read_options (int argc, char **argv) /* {{{ */ set_opt_send_qos (optarg); break; + case 'Z': + { + char *endptr = NULL; + double tmp; + + errno = 0; + tmp = strtod (optarg, &endptr); + if ((errno != 0) || (endptr == NULL) || (*endptr != 0) || (tmp < 0.0) || (tmp > 100.0)) + { + fprintf (stderr, "Ignoring invalid -Z argument: %s\n", optarg); + fprintf (stderr, "The \"-Z\" option requires a numeric argument between 0 and 100.\n"); + } + else + opt_exit_status_threshold = tmp / 100.0; + + break; + } + case 'h': usage_exit (argv[0], 0); break; @@ -615,7 +644,7 @@ static int update_stats_from_context (ping_context_t *ctx) /* {{{ */ average = context_get_average (ctx); deviation = context_get_stddev (ctx); - + mvwprintw (ctx->window, /* y = */ 2, /* x = */ 2, "rtt min/avg/max/sdev = %.3f/%.3f/%.3f/%.3f ms", ctx->latency_min, @@ -665,7 +694,7 @@ static int on_resize (pingobj_t *ping) /* {{{ */ context->window = NULL; } context->window = newwin (/* height = */ 4, - /* width = */ 0, + /* width = */ width, /* y = */ main_win_height + (4 * context->index), /* x = */ 0); } @@ -718,7 +747,7 @@ static int pre_loop_hook (pingobj_t *ping) /* {{{ */ main_win_height = height - (4 * host_num); main_win = newwin (/* height = */ main_win_height, - /* width = */ 0, + /* width = */ width, /* y = */ 0, /* x = */ 0); /* Allow scrolling */ scrollok (main_win, TRUE); @@ -744,7 +773,7 @@ static int pre_loop_hook (pingobj_t *ping) /* {{{ */ context->window = NULL; } context->window = newwin (/* height = */ 4, - /* width = */ 0, + /* width = */ width, /* y = */ main_win_height + (4 * context->index), /* x = */ 0); } @@ -812,7 +841,7 @@ static int post_sleep_hook (__attribute__((unused)) pingobj_t *ping) /* {{{ */ #endif static void update_host_hook (pingobj_iter_t *iter, /* {{{ */ - int index) + __attribute__((unused)) int index) { double latency; unsigned int sequence; @@ -881,11 +910,16 @@ static void update_host_hook (pingobj_iter_t *iter, /* {{{ */ || (latency > (average + stddev))) color = OPING_YELLOW; - HOST_PRINTF ("%zu bytes from %s (%s): icmp_seq=%u ttl=%i qos=%s" - " time=", + HOST_PRINTF ("%zu bytes from %s (%s): icmp_seq=%u ttl=%i ", data_len, context->host, context->addr, sequence, recv_ttl, format_qos (recv_qos, recv_qos_str, sizeof (recv_qos_str))); + if ((recv_qos != 0) || (opt_send_qos != 0)) + { + HOST_PRINTF ("qos=%s ", + format_qos (recv_qos, recv_qos_str, sizeof (recv_qos_str))); + } + HOST_PRINTF ("time="); wattron (main_win, COLOR_PAIR(color)); HOST_PRINTF ("%.2f", latency); wattroff (main_win, COLOR_PAIR(color)); @@ -894,13 +928,16 @@ static void update_host_hook (pingobj_iter_t *iter, /* {{{ */ else { #endif - HOST_PRINTF ("%zu bytes from %s (%s): icmp_seq=%u ttl=%i qos=%s" - " time=%.2f ms\n", + HOST_PRINTF ("%zu bytes from %s (%s): icmp_seq=%u ttl=%i ", data_len, context->host, context->addr, - sequence, recv_ttl, - format_qos (recv_qos, recv_qos_str, sizeof (recv_qos_str)), - latency); + sequence, recv_ttl); + if ((recv_qos != 0) || (opt_send_qos != 0)) + { + HOST_PRINTF ("qos=%s ", + format_qos (recv_qos, recv_qos_str, sizeof (recv_qos_str))); + } + HOST_PRINTF ("time=%.2f ms\n", latency); #if USE_NCURSES } #endif @@ -935,9 +972,12 @@ static void update_host_hook (pingobj_iter_t *iter, /* {{{ */ #endif } /* }}} void update_host_hook */ +/* Returns the number of hosts which failed to return more than the + fraction opt_exit_status_threshold of pings */ static int post_loop_hook (pingobj_t *ping) /* {{{ */ { pingobj_iter_t *iter; + int failure_count = 0; #if USE_NCURSES endwin (); @@ -957,6 +997,13 @@ static int post_loop_hook (pingobj_t *ping) /* {{{ */ context_get_packet_loss (context), context->latency_total); + { + double pct_failed = 1.0 - (((double) context->req_rcvd) + / ((double) context->req_sent)); + if (pct_failed > opt_exit_status_threshold) + failure_count++; + } + if (context->req_rcvd != 0) { double average; @@ -976,7 +1023,7 @@ static int post_loop_hook (pingobj_t *ping) /* {{{ */ context_destroy (context); } - return (0); + return (failure_count); } /* }}} int post_loop_hook */ int main (int argc, char **argv) /* {{{ */ @@ -1265,11 +1312,14 @@ int main (int argc, char **argv) /* {{{ */ opt_count--; } /* while (opt_count != 0) */ - post_loop_hook (ping); + status = post_loop_hook (ping); ping_destroy (ping); - return (0); + if (status) + return (EXIT_FAILURE + status); + else + return (EXIT_SUCCESS); } /* }}} int main */ /* vim: set fdm=marker : */