]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tools/tools/netrate/netblast/netblast.c
OpenSSL: Vendor import of OpenSSL 3.0.13
[FreeBSD/FreeBSD.git] / tools / tools / netrate / netblast / netblast.c
1 /*-
2  * Copyright (c) 2004 Robert N. M. Watson
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
13  *
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
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/endian.h>
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <sys/time.h>
31
32 #include <netinet/in.h>
33 #include <netdb.h>                      /* getaddrinfo */
34
35 #include <signal.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>                     /* close */
40
41 static void
42 usage(void)
43 {
44
45         fprintf(stderr, "netblast [ip] [port] [payloadsize] [duration]\n");
46         exit(-1);
47 }
48
49 static int      global_stop_flag;
50
51 static void
52 signal_handler(int signum __unused)
53 {
54
55         global_stop_flag = 1;
56 }
57
58 /*
59  * Loop that blasts packets: begin by recording time information, resetting
60  * stats.  Set the interval timer for when we want to wake up.  Then go.
61  * SIGALRM will set a flag indicating it's time to stop.  Note that there's
62  * some overhead to the signal and timer setup, so the smaller the duration,
63  * the higher the relative overhead.
64  */
65 static int
66 blast_loop(int s, long duration, u_char *packet, u_int packet_len)
67 {
68         struct timespec starttime, tmptime;
69         struct itimerval it;
70         u_int32_t counter;
71         int send_errors, send_calls;
72
73         if (signal(SIGALRM, signal_handler) == SIG_ERR) {
74                 perror("signal");
75                 return (-1);
76         }
77
78         if (clock_getres(CLOCK_REALTIME, &tmptime) == -1) {
79                 perror("clock_getres");
80                 return (-1);
81         }
82
83         if (clock_gettime(CLOCK_REALTIME, &starttime) == -1) {
84                 perror("clock_gettime");
85                 return (-1);
86         }
87
88         it.it_interval.tv_sec = 0;
89         it.it_interval.tv_usec = 0;
90         it.it_value.tv_sec = duration;
91         it.it_value.tv_usec = 0;
92
93         if (setitimer(ITIMER_REAL, &it, NULL) < 0) {
94                 perror("setitimer");
95                 return (-1);
96         }
97
98         send_errors = send_calls = 0;
99         counter = 0;
100         while (global_stop_flag == 0) {
101                 /*
102                  * We maintain and, if there's room, send a counter.  Note
103                  * that even if the error is purely local, we still increment
104                  * the counter, so missing sequence numbers on the receive
105                  * side should not be assumed to be packets lost in transit.
106                  * For example, if the UDP socket gets back an ICMP from a
107                  * previous send, the error will turn up the current send
108                  * operation, causing the current sequence number also to be
109                  * skipped.
110                  */
111                 if (packet_len >= 4) {
112                         be32enc(packet, counter);
113                         counter++;
114                 }
115                 if (send(s, packet, packet_len, 0) < 0)
116                         send_errors++;
117                 send_calls++;
118         }
119
120         if (clock_gettime(CLOCK_REALTIME, &tmptime) == -1) {
121                 perror("clock_gettime");
122                 return (-1);
123         }
124
125         printf("\n");
126         printf("start:             %zd.%09lu\n", starttime.tv_sec,
127             starttime.tv_nsec);
128         printf("finish:            %zd.%09lu\n", tmptime.tv_sec,
129             tmptime.tv_nsec);
130         printf("send calls:        %d\n", send_calls);
131         printf("send errors:       %d\n", send_errors);
132         printf("approx send rate:  %ld\n", (send_calls - send_errors) /
133             duration);
134         printf("approx error rate: %d\n", (send_errors / send_calls));
135
136         return (0);
137 }
138
139 int
140 main(int argc, char *argv[])
141 {
142         long payloadsize, duration;
143         struct addrinfo hints, *res, *res0;
144         char *dummy, *packet;
145         int port, s, error;
146         const char *cause = NULL;
147
148         if (argc != 5)
149                 usage();
150
151         memset(&hints, 0, sizeof(hints));
152         hints.ai_family = PF_UNSPEC;
153         hints.ai_socktype = SOCK_DGRAM;
154
155         port = strtoul(argv[2], &dummy, 10);
156         if (port < 1 || port > 65535 || *dummy != '\0') {
157                 fprintf(stderr, "Invalid port number: %s\n", argv[2]);
158                 usage();
159                 /*NOTREACHED*/
160         }
161
162         payloadsize = strtoul(argv[3], &dummy, 10);
163         if (payloadsize < 0 || *dummy != '\0')
164                 usage();
165         if (payloadsize > 32768) {
166                 fprintf(stderr, "payloadsize > 32768\n");
167                 return (-1);
168                 /*NOTREACHED*/
169         }
170
171         duration = strtoul(argv[4], &dummy, 10);
172         if (duration < 0 || *dummy != '\0') {
173                 fprintf(stderr, "Invalid duration time: %s\n", argv[4]);
174                 usage();
175                 /*NOTREACHED*/
176         }
177
178         packet = malloc(payloadsize);
179         if (packet == NULL) {
180                 perror("malloc");
181                 return (-1);
182                 /*NOTREACHED*/
183         }
184
185         bzero(packet, payloadsize);
186         error = getaddrinfo(argv[1],argv[2], &hints, &res0);
187         if (error) {
188                 perror(gai_strerror(error));
189                 return (-1);
190                 /*NOTREACHED*/
191         }
192         s = -1;
193         for (res = res0; res; res = res->ai_next) {
194                 s = socket(res->ai_family, res->ai_socktype, 0);
195                 if (s < 0) {
196                         cause = "socket";
197                         continue;
198                 }
199
200                 if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
201                         cause = "connect";
202                         close(s);
203                         s = -1;
204                         continue;
205                 }
206
207                 break;  /* okay we got one */
208         }
209         if (s < 0) {
210                 perror(cause);
211                 return (-1);
212                 /*NOTREACHED*/
213         }
214
215         freeaddrinfo(res0);
216
217         return (blast_loop(s, duration, packet, payloadsize));
218
219 }