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