netblast.c revision 225334
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 225334 2011-09-02 16:40:18Z marius $
27136274Srwatson */
28136274Srwatson
29225334Smarius#include <sys/endian.h>
30136274Srwatson#include <sys/types.h>
31136274Srwatson#include <sys/socket.h>
32136274Srwatson#include <sys/time.h>
33136274Srwatson
34136274Srwatson#include <netinet/in.h>
35136274Srwatson
36136274Srwatson#include <arpa/inet.h>
37136274Srwatson
38136274Srwatson#include <signal.h>
39136274Srwatson#include <stdio.h>
40136274Srwatson#include <stdlib.h>
41136274Srwatson#include <string.h>
42136274Srwatson
43136274Srwatsonstatic void
44136274Srwatsonusage(void)
45136274Srwatson{
46136274Srwatson
47136274Srwatson	fprintf(stderr, "netblast [ip] [port] [payloadsize] [duration]\n");
48136274Srwatson	exit(-1);
49136274Srwatson}
50136274Srwatson
51136274Srwatsonstatic int	global_stop_flag;
52136274Srwatson
53136274Srwatsonstatic void
54141761Srwatsonsignal_handler(int signum __unused)
55136274Srwatson{
56136274Srwatson
57136274Srwatson	global_stop_flag = 1;
58136274Srwatson}
59136274Srwatson
60136274Srwatson/*
61136274Srwatson * Loop that blasts packets: begin by recording time information, resetting
62136274Srwatson * stats.  Set the interval timer for when we want to wake up.  Then go.
63136274Srwatson * SIGALRM will set a flag indicating it's time to stop.  Note that there's
64136274Srwatson * some overhead to the signal and timer setup, so the smaller the duration,
65136274Srwatson * the higher the relative overhead.
66136274Srwatson */
67136274Srwatsonstatic int
68136274Srwatsonblast_loop(int s, long duration, u_char *packet, u_int packet_len)
69136274Srwatson{
70136274Srwatson	struct timespec starttime, tmptime;
71136274Srwatson	struct itimerval it;
72136274Srwatson	u_int32_t counter;
73136274Srwatson	int send_errors, send_calls;
74136274Srwatson
75136274Srwatson	if (signal(SIGALRM, signal_handler) == SIG_ERR) {
76136274Srwatson		perror("signal");
77136274Srwatson		return (-1);
78136274Srwatson	}
79136274Srwatson
80136274Srwatson	if (clock_getres(CLOCK_REALTIME, &tmptime) == -1) {
81136274Srwatson		perror("clock_getres");
82136274Srwatson		return (-1);
83136274Srwatson	}
84136274Srwatson
85136274Srwatson	if (clock_gettime(CLOCK_REALTIME, &starttime) == -1) {
86136274Srwatson		perror("clock_gettime");
87136274Srwatson		return (-1);
88136274Srwatson	}
89136274Srwatson
90136274Srwatson	it.it_interval.tv_sec = 0;
91136274Srwatson	it.it_interval.tv_usec = 0;
92136274Srwatson	it.it_value.tv_sec = duration;
93136274Srwatson	it.it_value.tv_usec = 0;
94136274Srwatson
95136274Srwatson	if (setitimer(ITIMER_REAL, &it, NULL) < 0) {
96136274Srwatson		perror("setitimer");
97136274Srwatson		return (-1);
98136274Srwatson	}
99136274Srwatson
100136274Srwatson	send_errors = send_calls = 0;
101136274Srwatson	counter = 0;
102136274Srwatson	while (global_stop_flag == 0) {
103136274Srwatson		/*
104136274Srwatson		 * We maintain and, if there's room, send a counter.  Note
105136274Srwatson		 * that even if the error is purely local, we still increment
106136274Srwatson		 * the counter, so missing sequence numbers on the receive
107136274Srwatson		 * side should not be assumed to be packets lost in transit.
108136274Srwatson		 * For example, if the UDP socket gets back an ICMP from a
109136274Srwatson		 * previous send, the error will turn up the current send
110136274Srwatson		 * operation, causing the current sequence number also to be
111136274Srwatson		 * skipped.
112136274Srwatson		 */
113136274Srwatson		if (packet_len >= 4) {
114225334Smarius			be32enc(packet, counter);
115136274Srwatson			counter++;
116136274Srwatson		}
117136274Srwatson		if (send(s, packet, packet_len, 0) < 0)
118136274Srwatson			send_errors++;
119136274Srwatson		send_calls++;
120136274Srwatson	}
121136274Srwatson
122136274Srwatson	if (clock_gettime(CLOCK_REALTIME, &tmptime) == -1) {
123136274Srwatson		perror("clock_gettime");
124136274Srwatson		return (-1);
125136274Srwatson	}
126136274Srwatson
127136274Srwatson	printf("\n");
128153470Sscottl	printf("start:             %zd.%09lu\n", starttime.tv_sec,
129136274Srwatson	    starttime.tv_nsec);
130153470Sscottl	printf("finish:            %zd.%09lu\n", tmptime.tv_sec,
131136274Srwatson	    tmptime.tv_nsec);
132136274Srwatson	printf("send calls:        %d\n", send_calls);
133136274Srwatson	printf("send errors:       %d\n", send_errors);
134136274Srwatson	printf("approx send rate:  %ld\n", (send_calls - send_errors) /
135136274Srwatson	    duration);
136136274Srwatson	printf("approx error rate: %d\n", (send_errors / send_calls));
137136274Srwatson
138136274Srwatson	return (0);
139136274Srwatson}
140136274Srwatson
141136274Srwatsonint
142136274Srwatsonmain(int argc, char *argv[])
143136274Srwatson{
144136274Srwatson	long payloadsize, port, duration;
145136274Srwatson	struct sockaddr_in sin;
146136274Srwatson	char *dummy, *packet;
147136274Srwatson	int s;
148136274Srwatson
149136274Srwatson	if (argc != 5)
150136274Srwatson		usage();
151136274Srwatson
152136274Srwatson	bzero(&sin, sizeof(sin));
153136274Srwatson	sin.sin_len = sizeof(sin);
154136274Srwatson	sin.sin_family = AF_INET;
155136274Srwatson	if (inet_aton(argv[1], &sin.sin_addr) == 0) {
156136274Srwatson		perror(argv[1]);
157136274Srwatson		return (-1);
158136274Srwatson	}
159136274Srwatson
160136274Srwatson	port = strtoul(argv[2], &dummy, 10);
161136274Srwatson	if (port < 1 || port > 65535 || *dummy != '\0')
162136274Srwatson		usage();
163136274Srwatson	sin.sin_port = htons(port);
164136274Srwatson
165136274Srwatson	payloadsize = strtoul(argv[3], &dummy, 10);
166136274Srwatson	if (payloadsize < 0 || *dummy != '\0')
167136274Srwatson		usage();
168136274Srwatson	if (payloadsize > 32768) {
169136274Srwatson		fprintf(stderr, "payloadsize > 32768\n");
170136274Srwatson		return (-1);
171136274Srwatson	}
172136274Srwatson
173136274Srwatson	duration = strtoul(argv[4], &dummy, 10);
174136274Srwatson	if (duration < 0 || *dummy != '\0')
175136274Srwatson		usage();
176136274Srwatson
177136274Srwatson	packet = malloc(payloadsize);
178136274Srwatson	if (packet == NULL) {
179136274Srwatson		perror("malloc");
180136274Srwatson		return (-1);
181136274Srwatson	}
182136274Srwatson	bzero(packet, payloadsize);
183136274Srwatson
184136274Srwatson	s = socket(PF_INET, SOCK_DGRAM, 0);
185136274Srwatson	if (s == -1) {
186136274Srwatson		perror("socket");
187136274Srwatson		return (-1);
188136274Srwatson	}
189136274Srwatson
190136274Srwatson	if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
191136274Srwatson		perror("connect");
192136274Srwatson		return (-1);
193136274Srwatson	}
194136274Srwatson
195136274Srwatson	return (blast_loop(s, duration, packet, payloadsize));
196136274Srwatson}
197