netblast.c revision 141761
1136274Srwatson/*-
2136274Srwatson * Copyright (c) 2004 Robert N. M. Watson
3136274Srwatson * All rights reserved.
4136274Srwatson *
5136274Srwatson * Redistribution and use in source and binary forms, with or without
6136274Srwatson * modification, are permitted provided that the following conditions
7136274Srwatson * are met:
8136274Srwatson * 1. Redistributions of source code must retain the above copyright
9136274Srwatson *    notice, this list of conditions and the following disclaimer.
10136274Srwatson * 2. Redistributions in binary form must reproduce the above copyright
11136274Srwatson *    notice, this list of conditions and the following disclaimer in the
12136274Srwatson *    documentation and/or other materials provided with the distribution.
13136274Srwatson *
14136274Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15136274Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16136274Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17136274Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18136274Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19136274Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20136274Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21136274Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22136274Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23136274Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24136274Srwatson * SUCH DAMAGE.
25136274Srwatson *
26136274Srwatson * $FreeBSD: head/tools/tools/netrate/netblast/netblast.c 141761 2005-02-12 20:03:30Z rwatson $
27136274Srwatson */
28136274Srwatson
29136274Srwatson#include <sys/types.h>
30136274Srwatson#include <sys/socket.h>
31136274Srwatson#include <sys/time.h>
32136274Srwatson
33136274Srwatson#include <netinet/in.h>
34136274Srwatson
35136274Srwatson#include <arpa/inet.h>
36136274Srwatson
37136274Srwatson#include <signal.h>
38136274Srwatson#include <stdio.h>
39136274Srwatson#include <stdlib.h>
40136274Srwatson#include <string.h>
41136274Srwatson
42136274Srwatsonstatic void
43136274Srwatsonusage(void)
44136274Srwatson{
45136274Srwatson
46136274Srwatson	fprintf(stderr, "netblast [ip] [port] [payloadsize] [duration]\n");
47136274Srwatson	exit(-1);
48136274Srwatson}
49136274Srwatson
50136274Srwatsonstatic int	global_stop_flag;
51136274Srwatson
52136274Srwatsonstatic void
53141761Srwatsonsignal_handler(int signum __unused)
54136274Srwatson{
55136274Srwatson
56136274Srwatson	global_stop_flag = 1;
57136274Srwatson}
58136274Srwatson
59136274Srwatson/*
60136274Srwatson * Loop that blasts packets: begin by recording time information, resetting
61136274Srwatson * stats.  Set the interval timer for when we want to wake up.  Then go.
62136274Srwatson * SIGALRM will set a flag indicating it's time to stop.  Note that there's
63136274Srwatson * some overhead to the signal and timer setup, so the smaller the duration,
64136274Srwatson * the higher the relative overhead.
65136274Srwatson */
66136274Srwatsonstatic int
67136274Srwatsonblast_loop(int s, long duration, u_char *packet, u_int packet_len)
68136274Srwatson{
69136274Srwatson	struct timespec starttime, tmptime;
70136274Srwatson	struct itimerval it;
71136274Srwatson	u_int32_t counter;
72136274Srwatson	int send_errors, send_calls;
73136274Srwatson
74136274Srwatson	if (signal(SIGALRM, signal_handler) == SIG_ERR) {
75136274Srwatson		perror("signal");
76136274Srwatson		return (-1);
77136274Srwatson	}
78136274Srwatson
79136274Srwatson	if (clock_getres(CLOCK_REALTIME, &tmptime) == -1) {
80136274Srwatson		perror("clock_getres");
81136274Srwatson		return (-1);
82136274Srwatson	}
83136274Srwatson
84136274Srwatson	if (clock_gettime(CLOCK_REALTIME, &starttime) == -1) {
85136274Srwatson		perror("clock_gettime");
86136274Srwatson		return (-1);
87136274Srwatson	}
88136274Srwatson
89136274Srwatson	it.it_interval.tv_sec = 0;
90136274Srwatson	it.it_interval.tv_usec = 0;
91136274Srwatson	it.it_value.tv_sec = duration;
92136274Srwatson	it.it_value.tv_usec = 0;
93136274Srwatson
94136274Srwatson	if (setitimer(ITIMER_REAL, &it, NULL) < 0) {
95136274Srwatson		perror("setitimer");
96136274Srwatson		return (-1);
97136274Srwatson	}
98136274Srwatson
99136274Srwatson	send_errors = send_calls = 0;
100136274Srwatson	counter = 0;
101136274Srwatson	while (global_stop_flag == 0) {
102136274Srwatson		/*
103136274Srwatson		 * We maintain and, if there's room, send a counter.  Note
104136274Srwatson		 * that even if the error is purely local, we still increment
105136274Srwatson		 * the counter, so missing sequence numbers on the receive
106136274Srwatson		 * side should not be assumed to be packets lost in transit.
107136274Srwatson		 * For example, if the UDP socket gets back an ICMP from a
108136274Srwatson		 * previous send, the error will turn up the current send
109136274Srwatson		 * operation, causing the current sequence number also to be
110136274Srwatson		 * skipped.
111136274Srwatson		 *
112136274Srwatson		 * XXXRW: Note alignment assumption.
113136274Srwatson		 */
114136274Srwatson		if (packet_len >= 4) {
115136274Srwatson			*((u_int32_t *)packet) = htonl(counter);
116136274Srwatson			counter++;
117136274Srwatson		}
118136274Srwatson		if (send(s, packet, packet_len, 0) < 0)
119136274Srwatson			send_errors++;
120136274Srwatson		send_calls++;
121136274Srwatson	}
122136274Srwatson
123136274Srwatson	if (clock_gettime(CLOCK_REALTIME, &tmptime) == -1) {
124136274Srwatson		perror("clock_gettime");
125136274Srwatson		return (-1);
126136274Srwatson	}
127136274Srwatson
128136274Srwatson	printf("\n");
129136274Srwatson	printf("start:             %d.%09lu\n", starttime.tv_sec,
130136274Srwatson	    starttime.tv_nsec);
131136274Srwatson	printf("finish:            %d.%09lu\n", tmptime.tv_sec,
132136274Srwatson	    tmptime.tv_nsec);
133136274Srwatson	printf("send calls:        %d\n", send_calls);
134136274Srwatson	printf("send errors:       %d\n", send_errors);
135136274Srwatson	printf("approx send rate:  %ld\n", (send_calls - send_errors) /
136136274Srwatson	    duration);
137136274Srwatson	printf("approx error rate: %d\n", (send_errors / send_calls));
138136274Srwatson
139136274Srwatson	return (0);
140136274Srwatson}
141136274Srwatson
142136274Srwatsonint
143136274Srwatsonmain(int argc, char *argv[])
144136274Srwatson{
145136274Srwatson	long payloadsize, port, duration;
146136274Srwatson	struct sockaddr_in sin;
147136274Srwatson	char *dummy, *packet;
148136274Srwatson	int s;
149136274Srwatson
150136274Srwatson	if (argc != 5)
151136274Srwatson		usage();
152136274Srwatson
153136274Srwatson	bzero(&sin, sizeof(sin));
154136274Srwatson	sin.sin_len = sizeof(sin);
155136274Srwatson	sin.sin_family = AF_INET;
156136274Srwatson	if (inet_aton(argv[1], &sin.sin_addr) == 0) {
157136274Srwatson		perror(argv[1]);
158136274Srwatson		return (-1);
159136274Srwatson	}
160136274Srwatson
161136274Srwatson	port = strtoul(argv[2], &dummy, 10);
162136274Srwatson	if (port < 1 || port > 65535 || *dummy != '\0')
163136274Srwatson		usage();
164136274Srwatson	sin.sin_port = htons(port);
165136274Srwatson
166136274Srwatson	payloadsize = strtoul(argv[3], &dummy, 10);
167136274Srwatson	if (payloadsize < 0 || *dummy != '\0')
168136274Srwatson		usage();
169136274Srwatson	if (payloadsize > 32768) {
170136274Srwatson		fprintf(stderr, "payloadsize > 32768\n");
171136274Srwatson		return (-1);
172136274Srwatson	}
173136274Srwatson
174136274Srwatson	duration = strtoul(argv[4], &dummy, 10);
175136274Srwatson	if (duration < 0 || *dummy != '\0')
176136274Srwatson		usage();
177136274Srwatson
178136274Srwatson	packet = malloc(payloadsize);
179136274Srwatson	if (packet == NULL) {
180136274Srwatson		perror("malloc");
181136274Srwatson		return (-1);
182136274Srwatson	}
183136274Srwatson	bzero(packet, payloadsize);
184136274Srwatson
185136274Srwatson	s = socket(PF_INET, SOCK_DGRAM, 0);
186136274Srwatson	if (s == -1) {
187136274Srwatson		perror("socket");
188136274Srwatson		return (-1);
189136274Srwatson	}
190136274Srwatson
191136274Srwatson	if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
192136274Srwatson		perror("connect");
193136274Srwatson		return (-1);
194136274Srwatson	}
195136274Srwatson
196136274Srwatson	return (blast_loop(s, duration, packet, payloadsize));
197136274Srwatson}
198