1122592Ssam/* $FreeBSD$ */ 2122592Ssam/* $NetBSD: kttcp.c,v 1.5 2002/07/11 23:32:35 simonb Exp $ */ 3122592Ssam 4122592Ssam/* 5122592Ssam * Copyright (c) 2002 Wasabi Systems, Inc. 6122592Ssam * All rights reserved. 7122592Ssam * 8122592Ssam * Written by Frank van der Linden and Jason R. Thorpe 9122592Ssam * for Wasabi Systems, Inc. 10122592Ssam * 11122592Ssam * Redistribution and use in source and binary forms, with or without 12122592Ssam * modification, are permitted provided that the following conditions 13122592Ssam * are met: 14122592Ssam * 1. Redistributions of source code must retain the above copyright 15122592Ssam * notice, this list of conditions and the following disclaimer. 16122592Ssam * 2. Redistributions in binary form must reproduce the above copyright 17122592Ssam * notice, this list of conditions and the following disclaimer in the 18122592Ssam * documentation and/or other materials provided with the distribution. 19122592Ssam * 3. All advertising materials mentioning features or use of this software 20122592Ssam * must display the following acknowledgement: 21122592Ssam * This product includes software developed for the NetBSD Project by 22122592Ssam * Wasabi Systems, Inc. 23122592Ssam * 4. The name of Wasabi Systems, Inc. may not be used to endorse 24122592Ssam * or promote products derived from this software without specific prior 25122592Ssam * written permission. 26122592Ssam * 27122592Ssam * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 28122592Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29122592Ssam * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30122592Ssam * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 31122592Ssam * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32122592Ssam * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33122592Ssam * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34122592Ssam * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35122592Ssam * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36122592Ssam * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37122592Ssam * POSSIBILITY OF SUCH DAMAGE. 38122592Ssam */ 39122592Ssam 40122592Ssam#include <sys/types.h> 41122592Ssam#include <sys/param.h> 42122592Ssam#include <sys/time.h> 43122592Ssam#include <sys/resource.h> 44122592Ssam#include <sys/socket.h> 45122592Ssam#include <sys/ioctl.h> 46122592Ssam#include <errno.h> 47122592Ssam#include <netdb.h> 48122592Ssam#include <unistd.h> 49122592Ssam#include <stdio.h> 50122592Ssam#include <err.h> 51122592Ssam#include <fcntl.h> 52122592Ssam#include <stdlib.h> 53122592Ssam#include <limits.h> 54122592Ssam#include <string.h> 55122592Ssam 56122629Ssam#include "kttcpio.h" 57122592Ssam 58122592Ssam#define KTTCP_PORT "22222" 59122592Ssam#define KTTCP_XMITSIZE (10*1024*1024) 60122592Ssam#define KTTCP_SOCKBUF_DEFAULT 65536 61122592Ssam 62122592Ssam#define KTTCP_DEVICE "/dev/kttcp" 63122592Ssam 64122592Ssamstatic void 65122592Ssamusage(void) 66122592Ssam{ 67122592Ssam fprintf(stderr, 68122592Ssam "usage: kttcp -r [-b sockbufsize] [-p port] [-q] [-v]\n" 69122592Ssam " [-4] [-6]\n" 70122592Ssam " kttcp -t [-b sockbufsize] [-n bytes] [-q] [-v] [-p port]\n" 71122592Ssam " [-4] [-6] host\n" 72122592Ssam ); 73122592Ssam exit(1); 74122592Ssam} 75122592Ssam 76122592Ssamstatic unsigned long long 77122592Ssamget_bytes(const char *str) 78122592Ssam{ 79122592Ssam unsigned long long bytes; 80122592Ssam char *cp; 81122592Ssam 82122592Ssam bytes = strtoull(str, &cp, 10); 83122592Ssam if (bytes == ULLONG_MAX && errno == ERANGE) 84122592Ssam err(1, "%s", str); 85122592Ssam 86122592Ssam if (cp[0] != '\0') { 87122592Ssam if (cp[1] != '\0') 88122592Ssam errx(1, "invalid byte count: %s", str); 89122592Ssam if (cp[0] == 'k' || cp[0] == 'K') 90122592Ssam bytes *= 1024; 91122592Ssam else if (cp[0] == 'm' || cp[0] == 'M') 92122592Ssam bytes *= 1024 * 1024; 93122592Ssam else if (cp[0] == 'g' || cp[0] == 'G') 94122592Ssam bytes *= 1024 * 1024 * 1024; 95122592Ssam else 96122592Ssam errx(1, "invalid byte count modifier: %s", str); 97122592Ssam } 98122592Ssam 99122592Ssam return (bytes); 100122592Ssam} 101122592Ssam 102122592Ssamint 103122592Ssammain(int argc, char *argv[]) 104122592Ssam{ 105122592Ssam int c, error, s, verbose, s2, kfd; 106122592Ssam int xmitset, family; 107122592Ssam int bufsize; 108122592Ssam int ai_flag; 109122592Ssam char *host; 110122592Ssam char *portstr; 111122592Ssam struct kttcp_io_args kio; 112122592Ssam struct addrinfo hints, *addr, *res; 113122592Ssam struct sockaddr_storage ss; 114122592Ssam struct rusage rustart, ruend; 115122592Ssam struct timeval tvtmp; 116122592Ssam unsigned long long ull, usecs, bytespersec, bitspersec, xmitsize; 117122592Ssam char connecthost[NI_MAXHOST]; 118122592Ssam socklen_t slen; 119122592Ssam const int one = 1; 120122592Ssam u_long cmd; 121122592Ssam 122122592Ssam cmd = 0; 123122592Ssam portstr = KTTCP_PORT; 124122592Ssam verbose = 1; 125122592Ssam xmitset = 0; 126122592Ssam bufsize = KTTCP_SOCKBUF_DEFAULT; 127122592Ssam xmitsize = KTTCP_XMITSIZE; 128122592Ssam family = PF_UNSPEC; 129122592Ssam while ((c = getopt(argc, argv, "46b:n:p:qrtvw:")) != -1) { 130122592Ssam switch (c) { 131122592Ssam case '4': 132122592Ssam if (family != PF_UNSPEC) 133122592Ssam usage(); 134122592Ssam family = PF_INET; 135122592Ssam break; 136122592Ssam case '6': 137122592Ssam if (family != PF_UNSPEC) 138122592Ssam usage(); 139122592Ssam family = PF_INET6; 140122592Ssam break; 141122592Ssam case 'b': 142122592Ssam ull = get_bytes(optarg); 143122592Ssam if (ull > INT_MAX) 144122592Ssam errx(1, 145122592Ssam "invalid socket buffer size: %s\n", optarg); 146122592Ssam bufsize = ull; 147122592Ssam break; 148122592Ssam case 'n': 149122592Ssam xmitsize = get_bytes(optarg); 150122592Ssam xmitset = 1; 151122592Ssam break; 152122592Ssam case 'p': 153122592Ssam portstr = optarg; 154122592Ssam break; 155122592Ssam case 'q': 156122592Ssam verbose = 0; 157122592Ssam break; 158122592Ssam case 'r': 159122592Ssam if (cmd != 0) 160122592Ssam usage(); 161122592Ssam cmd = KTTCP_IO_RECV; 162122592Ssam break; 163122592Ssam case 't': 164122592Ssam if (cmd != 0) 165122592Ssam usage(); 166122592Ssam cmd = KTTCP_IO_SEND; 167122592Ssam break; 168122592Ssam case 'v': 169122592Ssam verbose = 2; 170122592Ssam break; 171122592Ssam case '?': 172122592Ssam default: 173122592Ssam usage(); 174122592Ssam } 175122592Ssam } 176122592Ssam if (cmd == 0) 177122592Ssam usage(); 178122592Ssam 179122592Ssam argc -= optind; 180122592Ssam argv += optind; 181122592Ssam 182122592Ssam if (cmd == KTTCP_IO_SEND) { 183122592Ssam if (xmitsize <= 0 || argc < 1) 184122592Ssam usage(); 185122592Ssam host = argv[0]; 186122592Ssam ai_flag = 0; 187122592Ssam } else { 188122592Ssam if (xmitset == 0) 189122592Ssam xmitsize = KTTCP_MAX_XMIT; 190122592Ssam host = NULL; 191122592Ssam ai_flag = AI_PASSIVE; 192122592Ssam } 193122592Ssam 194122592Ssam if ((kfd = open(KTTCP_DEVICE, O_RDWR, 666)) == -1) 195122592Ssam err(2, "open %s", KTTCP_DEVICE); 196122592Ssam 197122592Ssam memset(&hints, 0, sizeof hints); 198122592Ssam hints.ai_flags = ai_flag; 199122592Ssam hints.ai_socktype = SOCK_STREAM; 200122592Ssam hints.ai_family = family; 201122592Ssam error = getaddrinfo(host, portstr, &hints, &addr); 202122592Ssam 203122592Ssam if (error != 0) 204122592Ssam errx(2, "%s", gai_strerror(error)); 205122592Ssam 206122592Ssam s = -1; 207122592Ssam for (res = addr; res != NULL; res = res->ai_next) { 208122592Ssam s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 209122592Ssam if (s >= 0) 210122592Ssam break; 211122592Ssam } 212122592Ssam if (res == NULL) 213122592Ssam err(2, "can't create socket"); 214122592Ssam 215122592Ssam printf("kttcp: socket buffer size: %d\n", bufsize); 216122592Ssam 217122592Ssam if (cmd == KTTCP_IO_SEND) { 218122592Ssam if (connect(s, res->ai_addr, res->ai_addrlen) < 0) 219122592Ssam err(2, "connect"); 220122592Ssam if (verbose) { 221122592Ssam getnameinfo(res->ai_addr, res->ai_addrlen, 222122592Ssam connecthost, sizeof connecthost, NULL, 0, 223122592Ssam NI_NUMERICHOST); 224122592Ssam printf("kttcp: connected to %s\n", connecthost); 225122592Ssam } 226122592Ssam if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof (int)) 227122592Ssam < 0) 228122592Ssam err(2, "setsockopt sndbuf"); 229122592Ssam kio.kio_socket = s; 230122592Ssam } else { 231122592Ssam if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, 232122592Ssam sizeof (int)) < 0) 233122592Ssam err(2, "setsockopt reuseaddr"); 234122592Ssam if (bind(s, res->ai_addr, res->ai_addrlen) < 0) 235122592Ssam err(2, "bind"); 236122592Ssam if (listen(s, 1) < 0) 237122592Ssam err(2, "listen"); 238122592Ssam if (verbose) 239122592Ssam printf("kttcp: listening on port %s\n", portstr); 240122592Ssam slen = sizeof ss; 241122592Ssam s2 = accept(s, (struct sockaddr *)&ss, &slen); 242122592Ssam if (s2 < 0) 243122592Ssam err(2, "accept"); 244122592Ssam if (verbose) { 245122592Ssam getnameinfo((struct sockaddr *)&ss, ss.ss_len, 246122592Ssam connecthost, sizeof connecthost, NULL, 0, 247122592Ssam NI_NUMERICHOST); 248122592Ssam printf("kttcp: connect from %s\n", connecthost); 249122592Ssam } 250122592Ssam if (setsockopt(s2, SOL_SOCKET, SO_RCVBUF, &bufsize, 251122592Ssam sizeof (int)) < 0) 252122592Ssam err(2, "setsockopt rcvbuf"); 253122592Ssam kio.kio_socket = s2; 254122592Ssam } 255122592Ssam 256122592Ssam kio.kio_totalsize = xmitsize; 257122592Ssam 258122592Ssam getrusage(RUSAGE_SELF, &rustart); 259122592Ssam if (ioctl(kfd, cmd, &kio) == -1) 260122592Ssam err(2, "kttcp i/o command"); 261122592Ssam getrusage(RUSAGE_SELF, &ruend); 262122592Ssam 263122592Ssam usecs = (unsigned long long)kio.kio_elapsed.tv_sec * 1000000; 264122592Ssam usecs += kio.kio_elapsed.tv_usec; 265122592Ssam 266122592Ssam bytespersec = kio.kio_bytesdone * 1000000LL / usecs; 267122592Ssam bitspersec = bytespersec * NBBY; 268122592Ssam printf("kttcp: %llu bytes in %ld.%03ld real seconds ==> %llu bytes/sec\n", 269122592Ssam kio.kio_bytesdone, kio.kio_elapsed.tv_sec, 270122592Ssam kio.kio_elapsed.tv_usec / 1000, bytespersec); 271122592Ssam if (verbose > 1) { 272122592Ssam timersub(&ruend.ru_stime, &rustart.ru_stime, &tvtmp); 273122592Ssam bytespersec = kio.kio_bytesdone * 1000000LL / 274122592Ssam (tvtmp.tv_sec * 1000000ULL + tvtmp.tv_usec); 275122592Ssam printf("kttcp: %llu bytes in %ld.%03ld CPU seconds ==> %llu bytes/CPU sec\n", 276122592Ssam kio.kio_bytesdone, tvtmp.tv_sec, tvtmp.tv_usec / 1000, bytespersec); 277122592Ssam } 278122592Ssam printf(" %g (%g) Megabits/sec\n", 279122592Ssam ((double) bitspersec / 1024.0) / 1024.0, 280122592Ssam ((double) bitspersec / 1000.0) / 1000.0); 281122592Ssam 282122592Ssam timersub(&ruend.ru_utime, &rustart.ru_utime, &tvtmp); 283122592Ssam /* XXX 284122592Ssam * sometimes, this ends up as -1 * hz!? 285122592Ssam */ 286122592Ssam if (tvtmp.tv_sec < 0) 287122592Ssam tvtmp.tv_sec = tvtmp.tv_usec = 0; 288122592Ssam printf(" %ld.%02lduser", tvtmp.tv_sec, tvtmp.tv_usec / 10000); 289122592Ssam ull = tvtmp.tv_sec * 1000000ULL + tvtmp.tv_usec; 290122592Ssam 291122592Ssam timersub(&ruend.ru_stime, &rustart.ru_stime, &tvtmp); 292122592Ssam printf(" %ld.%02ldsys", tvtmp.tv_sec, tvtmp.tv_usec / 10000); 293122592Ssam ull += tvtmp.tv_sec * 1000000ULL + tvtmp.tv_usec; 294122592Ssam 295122592Ssam printf(" %lld.%lldreal", usecs / 1000000, (usecs % 1000000) / 10000); 296122592Ssam printf(" %lld%%", ull * 100 / usecs); 297122592Ssam printf("\n"); 298122592Ssam 299122592Ssam 300122592Ssam close(kio.kio_socket); 301122592Ssam if (cmd == KTTCP_IO_RECV) 302122592Ssam close(s); 303122592Ssam close(kfd); 304122592Ssam freeaddrinfo(addr); 305122592Ssam 306122592Ssam return 0; 307122592Ssam} 308