]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - tools/tools/kttcp/kttcp.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / tools / tools / kttcp / kttcp.c
1 /*      $FreeBSD$       */
2 /*      $NetBSD: kttcp.c,v 1.5 2002/07/11 23:32:35 simonb Exp $ */
3
4 /*
5  * Copyright (c) 2002 Wasabi Systems, Inc.
6  * All rights reserved.
7  *
8  * Written by Frank van der Linden and Jason R. Thorpe
9  * for Wasabi Systems, Inc.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *      This product includes software developed for the NetBSD Project by
22  *      Wasabi Systems, Inc.
23  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
24  *    or promote products derived from this software without specific prior
25  *    written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
28  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGE.
38  */
39
40 #include <sys/types.h>
41 #include <sys/param.h>
42 #include <sys/time.h>
43 #include <sys/resource.h>
44 #include <sys/socket.h>
45 #include <sys/ioctl.h>
46 #include <errno.h>
47 #include <netdb.h>
48 #include <unistd.h>
49 #include <stdio.h>
50 #include <err.h>
51 #include <fcntl.h>
52 #include <stdlib.h>
53 #include <limits.h>
54 #include <string.h>
55
56 #include "kttcpio.h"
57
58 #define KTTCP_PORT              "22222"
59 #define KTTCP_XMITSIZE          (10*1024*1024)
60 #define KTTCP_SOCKBUF_DEFAULT   65536
61
62 #define KTTCP_DEVICE            "/dev/kttcp"
63
64 static void
65 usage(void)
66 {
67         fprintf(stderr,
68             "usage: kttcp -r [-b sockbufsize] [-p port] [-q] [-v]\n"
69             "                [-4] [-6]\n"
70             "       kttcp -t [-b sockbufsize] [-n bytes] [-q] [-v] [-p port]\n"
71             "                [-4] [-6] host\n"
72         );
73         exit(1);
74 }
75
76 static unsigned long long
77 get_bytes(const char *str)
78 {
79         unsigned long long bytes;
80         char *cp;
81
82         bytes = strtoull(str, &cp, 10);
83         if (bytes == ULLONG_MAX && errno == ERANGE)
84                 err(1, "%s", str);
85
86         if (cp[0] != '\0') {
87                 if (cp[1] != '\0')
88                         errx(1, "invalid byte count: %s", str);
89                 if (cp[0] == 'k' || cp[0] == 'K')
90                         bytes *= 1024;
91                 else if (cp[0] == 'm' || cp[0] == 'M')
92                         bytes *= 1024 * 1024;
93                 else if (cp[0] == 'g' || cp[0] == 'G')
94                         bytes *= 1024 * 1024 * 1024;
95                 else
96                         errx(1, "invalid byte count modifier: %s", str);
97         }
98
99         return (bytes);
100 }
101
102 int
103 main(int argc, char *argv[])
104 {
105         int c, error, s, verbose, s2, kfd;
106         int xmitset, family;
107         int bufsize;
108         int ai_flag;
109         char *host;
110         char *portstr;
111         struct kttcp_io_args kio;
112         struct addrinfo hints, *addr, *res;
113         struct sockaddr_storage ss;
114         struct rusage rustart, ruend;
115         struct timeval tvtmp;
116         unsigned long long ull, usecs, bytespersec, bitspersec, xmitsize;
117         char connecthost[NI_MAXHOST];
118         socklen_t slen;
119         const int one = 1;
120         u_long cmd;
121
122         cmd = 0;
123         portstr = KTTCP_PORT;
124         verbose = 1;
125         xmitset = 0;
126         bufsize = KTTCP_SOCKBUF_DEFAULT;
127         xmitsize = KTTCP_XMITSIZE;
128         family = PF_UNSPEC;
129         while ((c = getopt(argc, argv, "46b:n:p:qrtvw:")) != -1) {
130                 switch (c) {
131                 case '4':
132                         if (family != PF_UNSPEC)
133                                 usage();
134                         family = PF_INET;
135                         break;
136                 case '6':
137                         if (family != PF_UNSPEC)
138                                 usage();
139                         family = PF_INET6;
140                         break;
141                 case 'b':
142                         ull = get_bytes(optarg);
143                         if (ull > INT_MAX)
144                                 errx(1,
145                                     "invalid socket buffer size: %s\n", optarg);
146                         bufsize = ull;
147                         break;
148                 case 'n':
149                         xmitsize = get_bytes(optarg);
150                         xmitset = 1;
151                         break;
152                 case 'p':
153                         portstr = optarg;
154                         break;
155                 case 'q':
156                         verbose = 0;
157                         break;
158                 case 'r':
159                         if (cmd != 0)
160                                 usage();
161                         cmd = KTTCP_IO_RECV;
162                         break;
163                 case 't':
164                         if (cmd != 0)
165                                 usage();
166                         cmd = KTTCP_IO_SEND;
167                         break;
168                 case 'v':
169                         verbose = 2;
170                         break;
171                 case '?':
172                 default:
173                         usage();
174                 }
175         }
176         if (cmd == 0)
177                 usage();
178
179         argc -= optind;
180         argv += optind;
181
182         if (cmd == KTTCP_IO_SEND) {
183                 if (xmitsize <= 0 || argc < 1)
184                         usage();
185                 host = argv[0];
186                 ai_flag = 0;
187         } else {
188                 if (xmitset == 0)
189                         xmitsize = KTTCP_MAX_XMIT;
190                 host = NULL;
191                 ai_flag = AI_PASSIVE;
192         }
193
194         if ((kfd = open(KTTCP_DEVICE, O_RDWR, 666)) == -1)
195                 err(2, "open %s", KTTCP_DEVICE);
196
197         memset(&hints, 0, sizeof hints);
198         hints.ai_flags = ai_flag;
199         hints.ai_socktype = SOCK_STREAM;
200         hints.ai_family = family;
201         error = getaddrinfo(host, portstr, &hints, &addr);
202
203         if (error != 0)
204                 errx(2, "%s", gai_strerror(error));
205
206         s = -1;
207         for (res = addr; res != NULL; res = res->ai_next) {
208                 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
209                 if (s >= 0)
210                         break;
211         }
212         if (res == NULL)
213                 err(2, "can't create socket");
214
215         printf("kttcp: socket buffer size: %d\n", bufsize);
216
217         if (cmd == KTTCP_IO_SEND) {
218                 if (connect(s, res->ai_addr, res->ai_addrlen) < 0)
219                         err(2, "connect");
220                 if (verbose) {
221                         getnameinfo(res->ai_addr, res->ai_addrlen,
222                             connecthost, sizeof connecthost, NULL, 0,
223                             NI_NUMERICHOST);
224                         printf("kttcp: connected to %s\n", connecthost);
225                 }
226                 if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof (int))
227                     < 0)
228                         err(2, "setsockopt sndbuf");
229                 kio.kio_socket = s;
230         } else {
231                 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one,
232                     sizeof (int)) < 0)
233                         err(2, "setsockopt reuseaddr");
234                 if (bind(s, res->ai_addr, res->ai_addrlen) < 0)
235                         err(2, "bind");
236                 if (listen(s, 1) < 0)
237                         err(2, "listen");
238                 if (verbose)
239                         printf("kttcp: listening on port %s\n", portstr);
240                 slen = sizeof ss;
241                 s2 = accept(s, (struct sockaddr *)&ss, &slen);
242                 if (s2 < 0)
243                         err(2, "accept");
244                 if (verbose) {
245                         getnameinfo((struct sockaddr *)&ss, ss.ss_len,
246                             connecthost, sizeof connecthost, NULL, 0,
247                             NI_NUMERICHOST);
248                         printf("kttcp: connect from %s\n", connecthost);
249                 }
250                 if (setsockopt(s2, SOL_SOCKET, SO_RCVBUF, &bufsize,
251                     sizeof (int)) < 0)
252                         err(2, "setsockopt rcvbuf");
253                 kio.kio_socket = s2;
254         }
255
256         kio.kio_totalsize = xmitsize;
257
258         getrusage(RUSAGE_SELF, &rustart);
259         if (ioctl(kfd, cmd, &kio) == -1)
260                 err(2, "kttcp i/o command");
261         getrusage(RUSAGE_SELF, &ruend);
262
263         usecs = (unsigned long long)kio.kio_elapsed.tv_sec * 1000000;
264         usecs += kio.kio_elapsed.tv_usec;
265
266         bytespersec = kio.kio_bytesdone * 1000000LL / usecs;
267         bitspersec = bytespersec * NBBY;
268         printf("kttcp: %llu bytes in %ld.%03ld real seconds ==> %llu bytes/sec\n",
269             kio.kio_bytesdone, kio.kio_elapsed.tv_sec,
270             kio.kio_elapsed.tv_usec / 1000, bytespersec);
271         if (verbose > 1) {
272                 timersub(&ruend.ru_stime, &rustart.ru_stime, &tvtmp);
273                 bytespersec = kio.kio_bytesdone * 1000000LL /
274                     (tvtmp.tv_sec * 1000000ULL + tvtmp.tv_usec);
275                 printf("kttcp: %llu bytes in %ld.%03ld CPU seconds ==> %llu bytes/CPU sec\n",
276                     kio.kio_bytesdone, tvtmp.tv_sec, tvtmp.tv_usec / 1000, bytespersec);
277         }
278         printf("       %g (%g) Megabits/sec\n",
279             ((double) bitspersec / 1024.0) / 1024.0,
280             ((double) bitspersec / 1000.0) / 1000.0);
281
282         timersub(&ruend.ru_utime, &rustart.ru_utime, &tvtmp);
283         /* XXX
284          * sometimes, this ends up as -1 * hz!?
285          */
286         if (tvtmp.tv_sec < 0)
287                 tvtmp.tv_sec = tvtmp.tv_usec = 0;
288         printf("  %ld.%02lduser", tvtmp.tv_sec, tvtmp.tv_usec / 10000);
289         ull = tvtmp.tv_sec * 1000000ULL + tvtmp.tv_usec;
290
291         timersub(&ruend.ru_stime, &rustart.ru_stime, &tvtmp);
292         printf(" %ld.%02ldsys", tvtmp.tv_sec, tvtmp.tv_usec / 10000);
293         ull += tvtmp.tv_sec * 1000000ULL + tvtmp.tv_usec;
294
295         printf(" %lld.%lldreal", usecs / 1000000, (usecs % 1000000) / 10000);
296         printf(" %lld%%", ull * 100 / usecs);
297         printf("\n");
298
299
300         close(kio.kio_socket);
301         if (cmd == KTTCP_IO_RECV)
302                 close(s);
303         close(kfd);
304         freeaddrinfo(addr);
305
306         return 0;
307 }