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