tools: Add netblast
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Sat, 26 May 2012 15:05:01 +0000 (23:05 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Sat, 26 May 2012 15:05:01 +0000 (23:05 +0800)
Obtained-from: FreeBSD

tools/tools/netrate/netblast/Makefile [new file with mode: 0644]
tools/tools/netrate/netblast/netblast.c [new file with mode: 0644]

diff --git a/tools/tools/netrate/netblast/Makefile b/tools/tools/netrate/netblast/Makefile
new file mode 100644 (file)
index 0000000..e52649c
--- /dev/null
@@ -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 <bsd.prog.mk>
diff --git a/tools/tools/netrate/netblast/netblast.c b/tools/tools/netrate/netblast/netblast.c
new file mode 100644 (file)
index 0000000..60a07b7
--- /dev/null
@@ -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 <sys/endian.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+#include <netdb.h>                     /* getaddrinfo */
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>                    /* 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));
+
+}