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