1 1.7 joerg /* $NetBSD: spray.c,v 1.7 2011/08/30 20:45:31 joerg Exp $ */ 2 1.4 thorpej 3 1.1 jtc /* 4 1.1 jtc * Copyright (c) 1993 Winning Strategies, Inc. 5 1.1 jtc * All rights reserved. 6 1.1 jtc * 7 1.1 jtc * Redistribution and use in source and binary forms, with or without 8 1.1 jtc * modification, are permitted provided that the following conditions 9 1.1 jtc * are met: 10 1.1 jtc * 1. Redistributions of source code must retain the above copyright 11 1.1 jtc * notice, this list of conditions and the following disclaimer. 12 1.1 jtc * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 jtc * notice, this list of conditions and the following disclaimer in the 14 1.1 jtc * documentation and/or other materials provided with the distribution. 15 1.1 jtc * 3. All advertising materials mentioning features or use of this software 16 1.1 jtc * must display the following acknowledgement: 17 1.1 jtc * This product includes software developed by Winning Strategies, Inc. 18 1.1 jtc * 4. The name of the author may not be used to endorse or promote products 19 1.2 jtc * derived from this software without specific prior written permission 20 1.1 jtc * 21 1.1 jtc * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 1.1 jtc * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 1.1 jtc * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 1.1 jtc * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 1.1 jtc * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 1.1 jtc * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 1.1 jtc * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 1.1 jtc * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 1.1 jtc * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 1.1 jtc * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 1.1 jtc */ 32 1.1 jtc 33 1.5 lukem #include <sys/cdefs.h> 34 1.5 lukem #ifndef lint 35 1.7 joerg __RCSID("$NetBSD: spray.c,v 1.7 2011/08/30 20:45:31 joerg Exp $"); 36 1.5 lukem #endif 37 1.5 lukem 38 1.1 jtc #include <stdio.h> 39 1.1 jtc #include <stdlib.h> 40 1.1 jtc #include <unistd.h> 41 1.1 jtc 42 1.1 jtc #include <rpc/rpc.h> 43 1.1 jtc #include <rpcsvc/spray.h> 44 1.1 jtc 45 1.1 jtc #ifndef SPRAYOVERHEAD 46 1.1 jtc #define SPRAYOVERHEAD 86 47 1.1 jtc #endif 48 1.1 jtc 49 1.7 joerg static void print_xferstats(int, int, double); 50 1.7 joerg __dead static void usage(void); 51 1.1 jtc 52 1.1 jtc /* spray buffer */ 53 1.7 joerg static char spray_buffer[SPRAYMAX]; 54 1.1 jtc 55 1.1 jtc /* RPC timeouts */ 56 1.7 joerg static struct timeval NO_DEFAULT = { -1, -1 }; 57 1.7 joerg static struct timeval ONE_WAY = { 0, 0 }; 58 1.7 joerg static struct timeval TIMEOUT = { 25, 0 }; 59 1.1 jtc 60 1.1 jtc int 61 1.7 joerg main(int argc, char **argv) 62 1.1 jtc { 63 1.1 jtc char *progname; 64 1.1 jtc spraycumul host_stats; 65 1.1 jtc sprayarr host_array; 66 1.1 jtc CLIENT *cl; 67 1.1 jtc int c; 68 1.1 jtc int i; 69 1.1 jtc int count = 0; 70 1.1 jtc int delay = 0; 71 1.1 jtc int length = 0; 72 1.1 jtc double xmit_time; /* time to receive data */ 73 1.1 jtc 74 1.1 jtc progname = *argv; 75 1.1 jtc while ((c = getopt(argc, argv, "c:d:l:")) != -1) { 76 1.1 jtc switch (c) { 77 1.1 jtc case 'c': 78 1.1 jtc count = atoi(optarg); 79 1.1 jtc break; 80 1.1 jtc case 'd': 81 1.1 jtc delay = atoi(optarg); 82 1.1 jtc break; 83 1.1 jtc case 'l': 84 1.1 jtc length = atoi(optarg); 85 1.1 jtc break; 86 1.1 jtc default: 87 1.1 jtc usage(); 88 1.1 jtc /* NOTREACHED */ 89 1.1 jtc } 90 1.1 jtc } 91 1.1 jtc argc -= optind; 92 1.1 jtc argv += optind; 93 1.1 jtc 94 1.1 jtc if (argc != 1) { 95 1.1 jtc usage(); 96 1.1 jtc /* NOTREACHED */ 97 1.1 jtc } 98 1.1 jtc 99 1.1 jtc 100 1.1 jtc /* Correct packet length. */ 101 1.1 jtc if (length > SPRAYMAX) { 102 1.1 jtc length = SPRAYMAX; 103 1.1 jtc } else if (length < SPRAYOVERHEAD) { 104 1.1 jtc length = SPRAYOVERHEAD; 105 1.1 jtc } else { 106 1.1 jtc /* The RPC portion of the packet is a multiple of 32 bits. */ 107 1.1 jtc length -= SPRAYOVERHEAD - 3; 108 1.1 jtc length &= ~3; 109 1.1 jtc length += SPRAYOVERHEAD; 110 1.1 jtc } 111 1.1 jtc 112 1.1 jtc 113 1.1 jtc /* 114 1.1 jtc * The default value of count is the number of packets required 115 1.1 jtc * to make the total stream size 100000 bytes. 116 1.1 jtc */ 117 1.1 jtc if (!count) { 118 1.1 jtc count = 100000 / length; 119 1.1 jtc } 120 1.1 jtc 121 1.1 jtc /* Initialize spray argument */ 122 1.1 jtc host_array.sprayarr_len = length - SPRAYOVERHEAD; 123 1.1 jtc host_array.sprayarr_val = spray_buffer; 124 1.1 jtc 125 1.1 jtc 126 1.1 jtc /* create connection with server */ 127 1.1 jtc cl = clnt_create(*argv, SPRAYPROG, SPRAYVERS, "udp"); 128 1.1 jtc if (cl == NULL) { 129 1.1 jtc clnt_pcreateerror(progname); 130 1.1 jtc exit(1); 131 1.1 jtc } 132 1.1 jtc 133 1.1 jtc 134 1.1 jtc /* 135 1.1 jtc * For some strange reason, RPC 4.0 sets the default timeout, 136 1.1 jtc * thus timeouts specified in clnt_call() are always ignored. 137 1.1 jtc * 138 1.1 jtc * The following (undocumented) hack resets the internal state 139 1.1 jtc * of the client handle. 140 1.1 jtc */ 141 1.3 cgd clnt_control(cl, CLSET_TIMEOUT, (caddr_t)&NO_DEFAULT); 142 1.1 jtc 143 1.1 jtc 144 1.1 jtc /* Clear server statistics */ 145 1.1 jtc if (clnt_call(cl, SPRAYPROC_CLEAR, xdr_void, NULL, xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) { 146 1.1 jtc clnt_perror(cl, progname); 147 1.1 jtc exit(1); 148 1.1 jtc } 149 1.1 jtc 150 1.1 jtc 151 1.1 jtc /* Spray server with packets */ 152 1.1 jtc printf ("sending %d packets of lnth %d to %s ...", count, length, *argv); 153 1.1 jtc fflush (stdout); 154 1.1 jtc 155 1.1 jtc for (i = 0; i < count; i++) { 156 1.1 jtc clnt_call(cl, SPRAYPROC_SPRAY, xdr_sprayarr, &host_array, xdr_void, NULL, ONE_WAY); 157 1.1 jtc 158 1.1 jtc if (delay) { 159 1.1 jtc usleep(delay); 160 1.1 jtc } 161 1.1 jtc } 162 1.1 jtc 163 1.1 jtc 164 1.1 jtc /* Collect statistics from server */ 165 1.1 jtc if (clnt_call(cl, SPRAYPROC_GET, xdr_void, NULL, xdr_spraycumul, &host_stats, TIMEOUT) != RPC_SUCCESS) { 166 1.1 jtc clnt_perror(cl, progname); 167 1.1 jtc exit(1); 168 1.1 jtc } 169 1.1 jtc 170 1.1 jtc xmit_time = host_stats.clock.sec + 171 1.1 jtc (host_stats.clock.usec / 1000000.0); 172 1.1 jtc 173 1.1 jtc printf ("\n\tin %.2f seconds elapsed time\n", xmit_time); 174 1.1 jtc 175 1.1 jtc 176 1.1 jtc /* report dropped packets */ 177 1.6 lukem if (host_stats.counter != (unsigned)count) { 178 1.1 jtc int packets_dropped = count - host_stats.counter; 179 1.1 jtc 180 1.1 jtc printf("\t%d packets (%.2f%%) dropped\n", 181 1.1 jtc packets_dropped, 182 1.1 jtc 100.0 * packets_dropped / count ); 183 1.1 jtc } else { 184 1.1 jtc printf("\tno packets dropped\n"); 185 1.1 jtc } 186 1.1 jtc 187 1.1 jtc printf("Sent:"); 188 1.1 jtc print_xferstats(count, length, xmit_time); 189 1.1 jtc 190 1.1 jtc printf("Rcvd:"); 191 1.1 jtc print_xferstats(host_stats.counter, length, xmit_time); 192 1.1 jtc 193 1.1 jtc exit (0); 194 1.1 jtc } 195 1.1 jtc 196 1.1 jtc 197 1.7 joerg static void 198 1.7 joerg print_xferstats(int packets, int packetlen, double xfertime) 199 1.1 jtc { 200 1.1 jtc int datalen; 201 1.1 jtc double pps; /* packets per second */ 202 1.1 jtc double bps; /* bytes per second */ 203 1.1 jtc 204 1.1 jtc datalen = packets * packetlen; 205 1.1 jtc pps = packets / xfertime; 206 1.1 jtc bps = datalen / xfertime; 207 1.1 jtc 208 1.1 jtc printf("\t%.0f packets/sec, ", pps); 209 1.1 jtc 210 1.1 jtc if (bps >= 1024) 211 1.1 jtc printf ("%.1fK ", bps / 1024); 212 1.1 jtc else 213 1.1 jtc printf ("%.0f ", bps); 214 1.1 jtc 215 1.1 jtc printf("bytes/sec\n"); 216 1.1 jtc } 217 1.1 jtc 218 1.7 joerg static void 219 1.7 joerg usage(void) 220 1.1 jtc { 221 1.1 jtc fprintf(stderr, "usage: spray [-c count] [-l length] [-d delay] host\n"); 222 1.1 jtc exit(1); 223 1.1 jtc } 224