2 * Copyright (c) 2004 Robert N. M. Watson
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/endian.h>
30 #include <sys/types.h>
31 #include <sys/socket.h>
34 #include <netinet/in.h>
35 #include <netdb.h> /* getaddrinfo */
41 #include <unistd.h> /* close */
47 fprintf(stderr, "netblast [ip] [port] [payloadsize] [duration]\n");
51 static int global_stop_flag;
54 signal_handler(int signum __unused)
61 * Loop that blasts packets: begin by recording time information, resetting
62 * stats. Set the interval timer for when we want to wake up. Then go.
63 * SIGALRM will set a flag indicating it's time to stop. Note that there's
64 * some overhead to the signal and timer setup, so the smaller the duration,
65 * the higher the relative overhead.
68 blast_loop(int s, long duration, u_char *packet, u_int packet_len)
70 struct timespec starttime, tmptime;
73 int send_errors, send_calls;
75 if (signal(SIGALRM, signal_handler) == SIG_ERR) {
80 if (clock_getres(CLOCK_REALTIME, &tmptime) == -1) {
81 perror("clock_getres");
85 if (clock_gettime(CLOCK_REALTIME, &starttime) == -1) {
86 perror("clock_gettime");
90 it.it_interval.tv_sec = 0;
91 it.it_interval.tv_usec = 0;
92 it.it_value.tv_sec = duration;
93 it.it_value.tv_usec = 0;
95 if (setitimer(ITIMER_REAL, &it, NULL) < 0) {
100 send_errors = send_calls = 0;
102 while (global_stop_flag == 0) {
104 * We maintain and, if there's room, send a counter. Note
105 * that even if the error is purely local, we still increment
106 * the counter, so missing sequence numbers on the receive
107 * side should not be assumed to be packets lost in transit.
108 * For example, if the UDP socket gets back an ICMP from a
109 * previous send, the error will turn up the current send
110 * operation, causing the current sequence number also to be
113 if (packet_len >= 4) {
114 be32enc(packet, counter);
117 if (send(s, packet, packet_len, 0) < 0)
122 if (clock_gettime(CLOCK_REALTIME, &tmptime) == -1) {
123 perror("clock_gettime");
128 printf("start: %zd.%09lu\n", starttime.tv_sec,
130 printf("finish: %zd.%09lu\n", tmptime.tv_sec,
132 printf("send calls: %d\n", send_calls);
133 printf("send errors: %d\n", send_errors);
134 printf("approx send rate: %ld\n", (send_calls - send_errors) /
136 printf("approx error rate: %d\n", (send_errors / send_calls));
142 main(int argc, char *argv[])
144 long payloadsize, duration;
145 struct addrinfo hints, *res, *res0;
146 char *dummy, *packet;
148 const char *cause = NULL;
153 memset(&hints, 0, sizeof(hints));
154 hints.ai_family = PF_UNSPEC;
155 hints.ai_socktype = SOCK_DGRAM;
157 port = strtoul(argv[2], &dummy, 10);
158 if (port < 1 || port > 65535 || *dummy != '\0') {
159 fprintf(stderr, "Invalid port number: %s\n", argv[2]);
164 payloadsize = strtoul(argv[3], &dummy, 10);
165 if (payloadsize < 0 || *dummy != '\0')
167 if (payloadsize > 32768) {
168 fprintf(stderr, "payloadsize > 32768\n");
173 duration = strtoul(argv[4], &dummy, 10);
174 if (duration < 0 || *dummy != '\0') {
175 fprintf(stderr, "Invalid duration time: %s\n", argv[4]);
180 packet = malloc(payloadsize);
181 if (packet == NULL) {
187 bzero(packet, payloadsize);
188 error = getaddrinfo(argv[1],argv[2], &hints, &res0);
190 perror(gai_strerror(error));
195 for (res = res0; res; res = res->ai_next) {
196 s = socket(res->ai_family, res->ai_socktype, 0);
202 if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
209 break; /* okay we got one */
219 return (blast_loop(s, duration, packet, payloadsize));