From c9a52017be63be24e8684d243005379496fb9a71 Mon Sep 17 00:00:00 2001 From: Sepherosa Ziehau Date: Sat, 26 May 2012 23:05:01 +0800 Subject: [PATCH] tools: Add netblast Obtained-from: FreeBSD --- tools/tools/netrate/netblast/Makefile | 9 ++ tools/tools/netrate/netblast/netblast.c | 221 +++++++++++++++++++++++++++++++ 2 files changed, 230 insertions(+), 0 deletions(-) create mode 100644 tools/tools/netrate/netblast/Makefile create mode 100644 tools/tools/netrate/netblast/netblast.c diff --git a/tools/tools/netrate/netblast/Makefile b/tools/tools/netrate/netblast/Makefile new file mode 100644 index 0000000..e52649c --- /dev/null +++ b/tools/tools/netrate/netblast/Makefile @@ -0,0 +1,9 @@ +# +# $FreeBSD: src/tools/tools/netrate/netblast/Makefile,v 1.3 2004/12/21 08:47:27 ru Exp $ +# + +PROG= netblast +BINDIR= /usr/bin +NOMAN= + +.include diff --git a/tools/tools/netrate/netblast/netblast.c b/tools/tools/netrate/netblast/netblast.c new file mode 100644 index 0000000..60a07b7 --- /dev/null +++ b/tools/tools/netrate/netblast/netblast.c @@ -0,0 +1,221 @@ +/*- + * Copyright (c) 2004 Robert N. M. Watson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/tools/tools/netrate/netblast/netblast.c,v 1.5 2011/11/08 17:23:43 cognet Exp $ + */ + +#include +#include +#include +#include + +#include +#include /* getaddrinfo */ + +#include +#include +#include +#include +#include /* close */ + +static void +usage(void) +{ + + fprintf(stderr, "netblast [ip] [port] [payloadsize] [duration]\n"); + exit(-1); +} + +static int global_stop_flag; + +static void +signal_handler(int signum __unused) +{ + + global_stop_flag = 1; +} + +/* + * Loop that blasts packets: begin by recording time information, resetting + * stats. Set the interval timer for when we want to wake up. Then go. + * SIGALRM will set a flag indicating it's time to stop. Note that there's + * some overhead to the signal and timer setup, so the smaller the duration, + * the higher the relative overhead. + */ +static int +blast_loop(int s, long duration, u_char *packet, u_int packet_len) +{ + struct timespec starttime, tmptime; + struct itimerval it; + u_int32_t counter; + int send_errors, send_calls; + + if (signal(SIGALRM, signal_handler) == SIG_ERR) { + perror("signal"); + return (-1); + } + + if (clock_getres(CLOCK_REALTIME, &tmptime) == -1) { + perror("clock_getres"); + return (-1); + } + + if (clock_gettime(CLOCK_REALTIME, &starttime) == -1) { + perror("clock_gettime"); + return (-1); + } + + it.it_interval.tv_sec = 0; + it.it_interval.tv_usec = 0; + it.it_value.tv_sec = duration; + it.it_value.tv_usec = 0; + + if (setitimer(ITIMER_REAL, &it, NULL) < 0) { + perror("setitimer"); + return (-1); + } + + send_errors = send_calls = 0; + counter = 0; + while (global_stop_flag == 0) { + /* + * We maintain and, if there's room, send a counter. Note + * that even if the error is purely local, we still increment + * the counter, so missing sequence numbers on the receive + * side should not be assumed to be packets lost in transit. + * For example, if the UDP socket gets back an ICMP from a + * previous send, the error will turn up the current send + * operation, causing the current sequence number also to be + * skipped. + */ + if (packet_len >= 4) { + be32enc(packet, counter); + counter++; + } + if (send(s, packet, packet_len, 0) < 0) + send_errors++; + send_calls++; + } + + if (clock_gettime(CLOCK_REALTIME, &tmptime) == -1) { + perror("clock_gettime"); + return (-1); + } + + printf("\n"); + printf("start: %zd.%09lu\n", starttime.tv_sec, + starttime.tv_nsec); + printf("finish: %zd.%09lu\n", tmptime.tv_sec, + tmptime.tv_nsec); + printf("send calls: %d\n", send_calls); + printf("send errors: %d\n", send_errors); + printf("approx send rate: %ld\n", (send_calls - send_errors) / + duration); + printf("approx error rate: %d\n", (send_errors / send_calls)); + + return (0); +} + +int +main(int argc, char *argv[]) +{ + long payloadsize, duration; + struct addrinfo hints, *res, *res0; + char *dummy, *packet; + int port, s, error; + const char *cause = NULL; + + if (argc != 5) + usage(); + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + + port = strtoul(argv[2], &dummy, 10); + if (port < 1 || port > 65535 || *dummy != '\0') { + fprintf(stderr, "Invalid port number: %s\n", argv[2]); + usage(); + /*NOTREACHED*/ + } + + payloadsize = strtoul(argv[3], &dummy, 10); + if (payloadsize < 0 || *dummy != '\0') + usage(); + if (payloadsize > 32768) { + fprintf(stderr, "payloadsize > 32768\n"); + return (-1); + /*NOTREACHED*/ + } + + duration = strtoul(argv[4], &dummy, 10); + if (duration < 0 || *dummy != '\0') { + fprintf(stderr, "Invalid duration time: %s\n", argv[4]); + usage(); + /*NOTREACHED*/ + } + + packet = malloc(payloadsize); + if (packet == NULL) { + perror("malloc"); + return (-1); + /*NOTREACHED*/ + } + + bzero(packet, payloadsize); + error = getaddrinfo(argv[1],argv[2], &hints, &res0); + if (error) { + perror(gai_strerror(error)); + return (-1); + /*NOTREACHED*/ + } + s = -1; + for (res = res0; res; res = res->ai_next) { + s = socket(res->ai_family, res->ai_socktype, 0); + if (s < 0) { + cause = "socket"; + continue; + } + + if (connect(s, res->ai_addr, res->ai_addrlen) < 0) { + cause = "connect"; + close(s); + s = -1; + continue; + } + + break; /* okay we got one */ + } + if (s < 0) { + perror(cause); + return (-1); + /*NOTREACHED*/ + } + + freeaddrinfo(res0); + + return (blast_loop(s, duration, packet, payloadsize)); + +} -- 1.7.7.2