]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - tools/tools/netrate/netblast/netblast.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.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  * $FreeBSD$
27  */
28
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <sys/time.h>
32
33 #include <netinet/in.h>
34
35 #include <arpa/inet.h>
36
37 #include <signal.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41
42 static void
43 usage(void)
44 {
45
46         fprintf(stderr, "netblast [ip] [port] [payloadsize] [duration]\n");
47         exit(-1);
48 }
49
50 static int      global_stop_flag;
51
52 static void
53 signal_handler(int signum __unused)
54 {
55
56         global_stop_flag = 1;
57 }
58
59 /*
60  * Loop that blasts packets: begin by recording time information, resetting
61  * stats.  Set the interval timer for when we want to wake up.  Then go.
62  * SIGALRM will set a flag indicating it's time to stop.  Note that there's
63  * some overhead to the signal and timer setup, so the smaller the duration,
64  * the higher the relative overhead.
65  */
66 static int
67 blast_loop(int s, long duration, u_char *packet, u_int packet_len)
68 {
69         struct timespec starttime, tmptime;
70         struct itimerval it;
71         u_int32_t counter;
72         int send_errors, send_calls;
73
74         if (signal(SIGALRM, signal_handler) == SIG_ERR) {
75                 perror("signal");
76                 return (-1);
77         }
78
79         if (clock_getres(CLOCK_REALTIME, &tmptime) == -1) {
80                 perror("clock_getres");
81                 return (-1);
82         }
83
84         if (clock_gettime(CLOCK_REALTIME, &starttime) == -1) {
85                 perror("clock_gettime");
86                 return (-1);
87         }
88
89         it.it_interval.tv_sec = 0;
90         it.it_interval.tv_usec = 0;
91         it.it_value.tv_sec = duration;
92         it.it_value.tv_usec = 0;
93
94         if (setitimer(ITIMER_REAL, &it, NULL) < 0) {
95                 perror("setitimer");
96                 return (-1);
97         }
98
99         send_errors = send_calls = 0;
100         counter = 0;
101         while (global_stop_flag == 0) {
102                 /*
103                  * We maintain and, if there's room, send a counter.  Note
104                  * that even if the error is purely local, we still increment
105                  * the counter, so missing sequence numbers on the receive
106                  * side should not be assumed to be packets lost in transit.
107                  * For example, if the UDP socket gets back an ICMP from a
108                  * previous send, the error will turn up the current send
109                  * operation, causing the current sequence number also to be
110                  * skipped.
111                  *
112                  * XXXRW: Note alignment assumption.
113                  */
114                 if (packet_len >= 4) {
115                         *((u_int32_t *)packet) = htonl(counter);
116                         counter++;
117                 }
118                 if (send(s, packet, packet_len, 0) < 0)
119                         send_errors++;
120                 send_calls++;
121         }
122
123         if (clock_gettime(CLOCK_REALTIME, &tmptime) == -1) {
124                 perror("clock_gettime");
125                 return (-1);
126         }
127
128         printf("\n");
129         printf("start:             %zd.%09lu\n", starttime.tv_sec,
130             starttime.tv_nsec);
131         printf("finish:            %zd.%09lu\n", tmptime.tv_sec,
132             tmptime.tv_nsec);
133         printf("send calls:        %d\n", send_calls);
134         printf("send errors:       %d\n", send_errors);
135         printf("approx send rate:  %ld\n", (send_calls - send_errors) /
136             duration);
137         printf("approx error rate: %d\n", (send_errors / send_calls));
138
139         return (0);
140 }
141
142 int
143 main(int argc, char *argv[])
144 {
145         long payloadsize, port, duration;
146         struct sockaddr_in sin;
147         char *dummy, *packet;
148         int s;
149
150         if (argc != 5)
151                 usage();
152
153         bzero(&sin, sizeof(sin));
154         sin.sin_len = sizeof(sin);
155         sin.sin_family = AF_INET;
156         if (inet_aton(argv[1], &sin.sin_addr) == 0) {
157                 perror(argv[1]);
158                 return (-1);
159         }
160
161         port = strtoul(argv[2], &dummy, 10);
162         if (port < 1 || port > 65535 || *dummy != '\0')
163                 usage();
164         sin.sin_port = htons(port);
165
166         payloadsize = strtoul(argv[3], &dummy, 10);
167         if (payloadsize < 0 || *dummy != '\0')
168                 usage();
169         if (payloadsize > 32768) {
170                 fprintf(stderr, "payloadsize > 32768\n");
171                 return (-1);
172         }
173
174         duration = strtoul(argv[4], &dummy, 10);
175         if (duration < 0 || *dummy != '\0')
176                 usage();
177
178         packet = malloc(payloadsize);
179         if (packet == NULL) {
180                 perror("malloc");
181                 return (-1);
182         }
183         bzero(packet, payloadsize);
184
185         s = socket(PF_INET, SOCK_DGRAM, 0);
186         if (s == -1) {
187                 perror("socket");
188                 return (-1);
189         }
190
191         if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
192                 perror("connect");
193                 return (-1);
194         }
195
196         return (blast_loop(s, duration, packet, payloadsize));
197 }