1*c9a52017SSepherosa Ziehau /*-
2*c9a52017SSepherosa Ziehau * Copyright (c) 2004 Robert N. M. Watson
3*c9a52017SSepherosa Ziehau * All rights reserved.
4*c9a52017SSepherosa Ziehau *
5*c9a52017SSepherosa Ziehau * Redistribution and use in source and binary forms, with or without
6*c9a52017SSepherosa Ziehau * modification, are permitted provided that the following conditions
7*c9a52017SSepherosa Ziehau * are met:
8*c9a52017SSepherosa Ziehau * 1. Redistributions of source code must retain the above copyright
9*c9a52017SSepherosa Ziehau * notice, this list of conditions and the following disclaimer.
10*c9a52017SSepherosa Ziehau * 2. Redistributions in binary form must reproduce the above copyright
11*c9a52017SSepherosa Ziehau * notice, this list of conditions and the following disclaimer in the
12*c9a52017SSepherosa Ziehau * documentation and/or other materials provided with the distribution.
13*c9a52017SSepherosa Ziehau *
14*c9a52017SSepherosa Ziehau * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*c9a52017SSepherosa Ziehau * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*c9a52017SSepherosa Ziehau * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*c9a52017SSepherosa Ziehau * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*c9a52017SSepherosa Ziehau * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*c9a52017SSepherosa Ziehau * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*c9a52017SSepherosa Ziehau * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*c9a52017SSepherosa Ziehau * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*c9a52017SSepherosa Ziehau * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*c9a52017SSepherosa Ziehau * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*c9a52017SSepherosa Ziehau * SUCH DAMAGE.
25*c9a52017SSepherosa Ziehau *
26*c9a52017SSepherosa Ziehau * $FreeBSD: src/tools/tools/netrate/netblast/netblast.c,v 1.5 2011/11/08 17:23:43 cognet Exp $
27*c9a52017SSepherosa Ziehau */
28*c9a52017SSepherosa Ziehau
29*c9a52017SSepherosa Ziehau #include <sys/endian.h>
30*c9a52017SSepherosa Ziehau #include <sys/types.h>
31*c9a52017SSepherosa Ziehau #include <sys/socket.h>
32*c9a52017SSepherosa Ziehau #include <sys/time.h>
33*c9a52017SSepherosa Ziehau
34*c9a52017SSepherosa Ziehau #include <netinet/in.h>
35*c9a52017SSepherosa Ziehau #include <netdb.h> /* getaddrinfo */
36*c9a52017SSepherosa Ziehau
37*c9a52017SSepherosa Ziehau #include <signal.h>
38*c9a52017SSepherosa Ziehau #include <stdio.h>
39*c9a52017SSepherosa Ziehau #include <stdlib.h>
40*c9a52017SSepherosa Ziehau #include <string.h>
41*c9a52017SSepherosa Ziehau #include <unistd.h> /* close */
42*c9a52017SSepherosa Ziehau
43*c9a52017SSepherosa Ziehau static void
usage(void)44*c9a52017SSepherosa Ziehau usage(void)
45*c9a52017SSepherosa Ziehau {
46*c9a52017SSepherosa Ziehau
47*c9a52017SSepherosa Ziehau fprintf(stderr, "netblast [ip] [port] [payloadsize] [duration]\n");
48*c9a52017SSepherosa Ziehau exit(-1);
49*c9a52017SSepherosa Ziehau }
50*c9a52017SSepherosa Ziehau
51*c9a52017SSepherosa Ziehau static int global_stop_flag;
52*c9a52017SSepherosa Ziehau
53*c9a52017SSepherosa Ziehau static void
signal_handler(int signum __unused)54*c9a52017SSepherosa Ziehau signal_handler(int signum __unused)
55*c9a52017SSepherosa Ziehau {
56*c9a52017SSepherosa Ziehau
57*c9a52017SSepherosa Ziehau global_stop_flag = 1;
58*c9a52017SSepherosa Ziehau }
59*c9a52017SSepherosa Ziehau
60*c9a52017SSepherosa Ziehau /*
61*c9a52017SSepherosa Ziehau * Loop that blasts packets: begin by recording time information, resetting
62*c9a52017SSepherosa Ziehau * stats. Set the interval timer for when we want to wake up. Then go.
63*c9a52017SSepherosa Ziehau * SIGALRM will set a flag indicating it's time to stop. Note that there's
64*c9a52017SSepherosa Ziehau * some overhead to the signal and timer setup, so the smaller the duration,
65*c9a52017SSepherosa Ziehau * the higher the relative overhead.
66*c9a52017SSepherosa Ziehau */
67*c9a52017SSepherosa Ziehau static int
blast_loop(int s,long duration,u_char * packet,u_int packet_len)68*c9a52017SSepherosa Ziehau blast_loop(int s, long duration, u_char *packet, u_int packet_len)
69*c9a52017SSepherosa Ziehau {
70*c9a52017SSepherosa Ziehau struct timespec starttime, tmptime;
71*c9a52017SSepherosa Ziehau struct itimerval it;
72*c9a52017SSepherosa Ziehau u_int32_t counter;
73*c9a52017SSepherosa Ziehau int send_errors, send_calls;
74*c9a52017SSepherosa Ziehau
75*c9a52017SSepherosa Ziehau if (signal(SIGALRM, signal_handler) == SIG_ERR) {
76*c9a52017SSepherosa Ziehau perror("signal");
77*c9a52017SSepherosa Ziehau return (-1);
78*c9a52017SSepherosa Ziehau }
79*c9a52017SSepherosa Ziehau
80*c9a52017SSepherosa Ziehau if (clock_getres(CLOCK_REALTIME, &tmptime) == -1) {
81*c9a52017SSepherosa Ziehau perror("clock_getres");
82*c9a52017SSepherosa Ziehau return (-1);
83*c9a52017SSepherosa Ziehau }
84*c9a52017SSepherosa Ziehau
85*c9a52017SSepherosa Ziehau if (clock_gettime(CLOCK_REALTIME, &starttime) == -1) {
86*c9a52017SSepherosa Ziehau perror("clock_gettime");
87*c9a52017SSepherosa Ziehau return (-1);
88*c9a52017SSepherosa Ziehau }
89*c9a52017SSepherosa Ziehau
90*c9a52017SSepherosa Ziehau it.it_interval.tv_sec = 0;
91*c9a52017SSepherosa Ziehau it.it_interval.tv_usec = 0;
92*c9a52017SSepherosa Ziehau it.it_value.tv_sec = duration;
93*c9a52017SSepherosa Ziehau it.it_value.tv_usec = 0;
94*c9a52017SSepherosa Ziehau
95*c9a52017SSepherosa Ziehau if (setitimer(ITIMER_REAL, &it, NULL) < 0) {
96*c9a52017SSepherosa Ziehau perror("setitimer");
97*c9a52017SSepherosa Ziehau return (-1);
98*c9a52017SSepherosa Ziehau }
99*c9a52017SSepherosa Ziehau
100*c9a52017SSepherosa Ziehau send_errors = send_calls = 0;
101*c9a52017SSepherosa Ziehau counter = 0;
102*c9a52017SSepherosa Ziehau while (global_stop_flag == 0) {
103*c9a52017SSepherosa Ziehau /*
104*c9a52017SSepherosa Ziehau * We maintain and, if there's room, send a counter. Note
105*c9a52017SSepherosa Ziehau * that even if the error is purely local, we still increment
106*c9a52017SSepherosa Ziehau * the counter, so missing sequence numbers on the receive
107*c9a52017SSepherosa Ziehau * side should not be assumed to be packets lost in transit.
108*c9a52017SSepherosa Ziehau * For example, if the UDP socket gets back an ICMP from a
109*c9a52017SSepherosa Ziehau * previous send, the error will turn up the current send
110*c9a52017SSepherosa Ziehau * operation, causing the current sequence number also to be
111*c9a52017SSepherosa Ziehau * skipped.
112*c9a52017SSepherosa Ziehau */
113*c9a52017SSepherosa Ziehau if (packet_len >= 4) {
114*c9a52017SSepherosa Ziehau be32enc(packet, counter);
115*c9a52017SSepherosa Ziehau counter++;
116*c9a52017SSepherosa Ziehau }
117*c9a52017SSepherosa Ziehau if (send(s, packet, packet_len, 0) < 0)
118*c9a52017SSepherosa Ziehau send_errors++;
119*c9a52017SSepherosa Ziehau send_calls++;
120*c9a52017SSepherosa Ziehau }
121*c9a52017SSepherosa Ziehau
122*c9a52017SSepherosa Ziehau if (clock_gettime(CLOCK_REALTIME, &tmptime) == -1) {
123*c9a52017SSepherosa Ziehau perror("clock_gettime");
124*c9a52017SSepherosa Ziehau return (-1);
125*c9a52017SSepherosa Ziehau }
126*c9a52017SSepherosa Ziehau
127*c9a52017SSepherosa Ziehau printf("\n");
128*c9a52017SSepherosa Ziehau printf("start: %zd.%09lu\n", starttime.tv_sec,
129*c9a52017SSepherosa Ziehau starttime.tv_nsec);
130*c9a52017SSepherosa Ziehau printf("finish: %zd.%09lu\n", tmptime.tv_sec,
131*c9a52017SSepherosa Ziehau tmptime.tv_nsec);
132*c9a52017SSepherosa Ziehau printf("send calls: %d\n", send_calls);
133*c9a52017SSepherosa Ziehau printf("send errors: %d\n", send_errors);
134*c9a52017SSepherosa Ziehau printf("approx send rate: %ld\n", (send_calls - send_errors) /
135*c9a52017SSepherosa Ziehau duration);
136*c9a52017SSepherosa Ziehau printf("approx error rate: %d\n", (send_errors / send_calls));
137*c9a52017SSepherosa Ziehau
138*c9a52017SSepherosa Ziehau return (0);
139*c9a52017SSepherosa Ziehau }
140*c9a52017SSepherosa Ziehau
141*c9a52017SSepherosa Ziehau int
main(int argc,char * argv[])142*c9a52017SSepherosa Ziehau main(int argc, char *argv[])
143*c9a52017SSepherosa Ziehau {
144*c9a52017SSepherosa Ziehau long payloadsize, duration;
145*c9a52017SSepherosa Ziehau struct addrinfo hints, *res, *res0;
146*c9a52017SSepherosa Ziehau char *dummy, *packet;
147*c9a52017SSepherosa Ziehau int port, s, error;
148*c9a52017SSepherosa Ziehau const char *cause = NULL;
149*c9a52017SSepherosa Ziehau
150*c9a52017SSepherosa Ziehau if (argc != 5)
151*c9a52017SSepherosa Ziehau usage();
152*c9a52017SSepherosa Ziehau
153*c9a52017SSepherosa Ziehau memset(&hints, 0, sizeof(hints));
154*c9a52017SSepherosa Ziehau hints.ai_family = PF_UNSPEC;
155*c9a52017SSepherosa Ziehau hints.ai_socktype = SOCK_DGRAM;
156*c9a52017SSepherosa Ziehau
157*c9a52017SSepherosa Ziehau port = strtoul(argv[2], &dummy, 10);
158*c9a52017SSepherosa Ziehau if (port < 1 || port > 65535 || *dummy != '\0') {
159*c9a52017SSepherosa Ziehau fprintf(stderr, "Invalid port number: %s\n", argv[2]);
160*c9a52017SSepherosa Ziehau usage();
161*c9a52017SSepherosa Ziehau /*NOTREACHED*/
162*c9a52017SSepherosa Ziehau }
163*c9a52017SSepherosa Ziehau
164*c9a52017SSepherosa Ziehau payloadsize = strtoul(argv[3], &dummy, 10);
165*c9a52017SSepherosa Ziehau if (payloadsize < 0 || *dummy != '\0')
166*c9a52017SSepherosa Ziehau usage();
167*c9a52017SSepherosa Ziehau if (payloadsize > 32768) {
168*c9a52017SSepherosa Ziehau fprintf(stderr, "payloadsize > 32768\n");
169*c9a52017SSepherosa Ziehau return (-1);
170*c9a52017SSepherosa Ziehau /*NOTREACHED*/
171*c9a52017SSepherosa Ziehau }
172*c9a52017SSepherosa Ziehau
173*c9a52017SSepherosa Ziehau duration = strtoul(argv[4], &dummy, 10);
174*c9a52017SSepherosa Ziehau if (duration < 0 || *dummy != '\0') {
175*c9a52017SSepherosa Ziehau fprintf(stderr, "Invalid duration time: %s\n", argv[4]);
176*c9a52017SSepherosa Ziehau usage();
177*c9a52017SSepherosa Ziehau /*NOTREACHED*/
178*c9a52017SSepherosa Ziehau }
179*c9a52017SSepherosa Ziehau
180*c9a52017SSepherosa Ziehau packet = malloc(payloadsize);
181*c9a52017SSepherosa Ziehau if (packet == NULL) {
182*c9a52017SSepherosa Ziehau perror("malloc");
183*c9a52017SSepherosa Ziehau return (-1);
184*c9a52017SSepherosa Ziehau /*NOTREACHED*/
185*c9a52017SSepherosa Ziehau }
186*c9a52017SSepherosa Ziehau
187*c9a52017SSepherosa Ziehau bzero(packet, payloadsize);
188*c9a52017SSepherosa Ziehau error = getaddrinfo(argv[1],argv[2], &hints, &res0);
189*c9a52017SSepherosa Ziehau if (error) {
190*c9a52017SSepherosa Ziehau perror(gai_strerror(error));
191*c9a52017SSepherosa Ziehau return (-1);
192*c9a52017SSepherosa Ziehau /*NOTREACHED*/
193*c9a52017SSepherosa Ziehau }
194*c9a52017SSepherosa Ziehau s = -1;
195*c9a52017SSepherosa Ziehau for (res = res0; res; res = res->ai_next) {
196*c9a52017SSepherosa Ziehau s = socket(res->ai_family, res->ai_socktype, 0);
197*c9a52017SSepherosa Ziehau if (s < 0) {
198*c9a52017SSepherosa Ziehau cause = "socket";
199*c9a52017SSepherosa Ziehau continue;
200*c9a52017SSepherosa Ziehau }
201*c9a52017SSepherosa Ziehau
202*c9a52017SSepherosa Ziehau if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
203*c9a52017SSepherosa Ziehau cause = "connect";
204*c9a52017SSepherosa Ziehau close(s);
205*c9a52017SSepherosa Ziehau s = -1;
206*c9a52017SSepherosa Ziehau continue;
207*c9a52017SSepherosa Ziehau }
208*c9a52017SSepherosa Ziehau
209*c9a52017SSepherosa Ziehau break; /* okay we got one */
210*c9a52017SSepherosa Ziehau }
211*c9a52017SSepherosa Ziehau if (s < 0) {
212*c9a52017SSepherosa Ziehau perror(cause);
213*c9a52017SSepherosa Ziehau return (-1);
214*c9a52017SSepherosa Ziehau /*NOTREACHED*/
215*c9a52017SSepherosa Ziehau }
216*c9a52017SSepherosa Ziehau
217*c9a52017SSepherosa Ziehau freeaddrinfo(res0);
218*c9a52017SSepherosa Ziehau
219*c9a52017SSepherosa Ziehau return (blast_loop(s, duration, packet, payloadsize));
220*c9a52017SSepherosa Ziehau
221*c9a52017SSepherosa Ziehau }
222