113242Sgraichen/* 213242Sgraichen * Copyright (c) 1993 Winning Strategies, Inc. 313242Sgraichen * All rights reserved. 413242Sgraichen * 513242Sgraichen * Redistribution and use in source and binary forms, with or without 613242Sgraichen * modification, are permitted provided that the following conditions 713242Sgraichen * are met: 813242Sgraichen * 1. Redistributions of source code must retain the above copyright 913242Sgraichen * notice, this list of conditions and the following disclaimer. 1013242Sgraichen * 2. Redistributions in binary form must reproduce the above copyright 1113242Sgraichen * notice, this list of conditions and the following disclaimer in the 1213242Sgraichen * documentation and/or other materials provided with the distribution. 1313242Sgraichen * 3. All advertising materials mentioning features or use of this software 1413242Sgraichen * must display the following acknowledgement: 1513242Sgraichen * This product includes software developed by Winning Strategies, Inc. 1613242Sgraichen * 4. The name of the author may not be used to endorse or promote products 1713242Sgraichen * derived from this software without specific prior written permission 1813242Sgraichen * 1913242Sgraichen * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2013242Sgraichen * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2113242Sgraichen * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2213242Sgraichen * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2313242Sgraichen * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2413242Sgraichen * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2513242Sgraichen * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2613242Sgraichen * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2713242Sgraichen * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2813242Sgraichen * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2913242Sgraichen */ 3013242Sgraichen 3130598Scharnier#ifndef lint 3230598Scharnierstatic const char rcsid[] = 3350479Speter "$FreeBSD$"; 3430598Scharnier#endif /* not lint */ 3530598Scharnier 3678722Sdd#include <err.h> 3713242Sgraichen#include <stdio.h> 3813242Sgraichen#include <stdlib.h> 3913242Sgraichen#include <unistd.h> 4013242Sgraichen 4113242Sgraichen#include <rpc/rpc.h> 4213242Sgraichen#include <rpcsvc/spray.h> 4313242Sgraichen 4413242Sgraichen#ifndef SPRAYOVERHEAD 4513242Sgraichen#define SPRAYOVERHEAD 86 4613242Sgraichen#endif 4713242Sgraichen 4878780Sddstatic void usage(void); 4978780Sddstatic void print_xferstats(unsigned int, int, double); 5013242Sgraichen 5113242Sgraichen/* spray buffer */ 52227261Sedstatic char spray_buffer[SPRAYMAX]; 5313242Sgraichen 5413242Sgraichen/* RPC timeouts */ 55227261Sedstatic struct timeval NO_DEFAULT = { -1, -1 }; 56227261Sedstatic struct timeval ONE_WAY = { 0, 0 }; 57227261Sedstatic struct timeval TIMEOUT = { 25, 0 }; 5813242Sgraichen 5913242Sgraichenint 6078780Sddmain(int argc, char *argv[]) 6113242Sgraichen{ 6213242Sgraichen spraycumul host_stats; 6313242Sgraichen sprayarr host_array; 6413242Sgraichen CLIENT *cl; 6513242Sgraichen int c; 6678780Sdd u_int i; 6778780Sdd u_int count = 0; 6813242Sgraichen int delay = 0; 6913242Sgraichen int length = 0; 7013242Sgraichen double xmit_time; /* time to receive data */ 7113242Sgraichen 7213242Sgraichen while ((c = getopt(argc, argv, "c:d:l:")) != -1) { 7313242Sgraichen switch (c) { 7413242Sgraichen case 'c': 7513242Sgraichen count = atoi(optarg); 7613242Sgraichen break; 7713242Sgraichen case 'd': 7813242Sgraichen delay = atoi(optarg); 7913242Sgraichen break; 8013242Sgraichen case 'l': 8113242Sgraichen length = atoi(optarg); 8213242Sgraichen break; 8313242Sgraichen default: 8413242Sgraichen usage(); 8513242Sgraichen /* NOTREACHED */ 8613242Sgraichen } 8713242Sgraichen } 8813242Sgraichen argc -= optind; 8913242Sgraichen argv += optind; 9013242Sgraichen 9113242Sgraichen if (argc != 1) { 9213242Sgraichen usage(); 9313242Sgraichen /* NOTREACHED */ 9413242Sgraichen } 9513242Sgraichen 9613242Sgraichen 9713242Sgraichen /* Correct packet length. */ 9813242Sgraichen if (length > SPRAYMAX) { 9913242Sgraichen length = SPRAYMAX; 10013242Sgraichen } else if (length < SPRAYOVERHEAD) { 10113242Sgraichen length = SPRAYOVERHEAD; 10213242Sgraichen } else { 10313242Sgraichen /* The RPC portion of the packet is a multiple of 32 bits. */ 10413242Sgraichen length -= SPRAYOVERHEAD - 3; 10513242Sgraichen length &= ~3; 10613242Sgraichen length += SPRAYOVERHEAD; 10713242Sgraichen } 10813242Sgraichen 10913242Sgraichen 11013242Sgraichen /* 11113242Sgraichen * The default value of count is the number of packets required 11213242Sgraichen * to make the total stream size 100000 bytes. 11313242Sgraichen */ 11413242Sgraichen if (!count) { 11513242Sgraichen count = 100000 / length; 11613242Sgraichen } 11713242Sgraichen 11813242Sgraichen /* Initialize spray argument */ 11913242Sgraichen host_array.sprayarr_len = length - SPRAYOVERHEAD; 12013242Sgraichen host_array.sprayarr_val = spray_buffer; 12113242Sgraichen 12213242Sgraichen 12313242Sgraichen /* create connection with server */ 12413242Sgraichen cl = clnt_create(*argv, SPRAYPROG, SPRAYVERS, "udp"); 12561027Scharnier if (cl == NULL) 126100121Salfred errx(1, "%s", clnt_spcreateerror("")); 12713242Sgraichen 12813242Sgraichen 12913242Sgraichen /* 13013242Sgraichen * For some strange reason, RPC 4.0 sets the default timeout, 13113242Sgraichen * thus timeouts specified in clnt_call() are always ignored. 13213242Sgraichen * 13313242Sgraichen * The following (undocumented) hack resets the internal state 13413242Sgraichen * of the client handle. 13513242Sgraichen */ 13695658Sdes clnt_control(cl, CLSET_TIMEOUT, &NO_DEFAULT); 13713242Sgraichen 13813242Sgraichen 13913242Sgraichen /* Clear server statistics */ 14095658Sdes if (clnt_call(cl, SPRAYPROC_CLEAR, (xdrproc_t)xdr_void, NULL, 14195658Sdes (xdrproc_t)xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) 142100121Salfred errx(1, "%s", clnt_sperror(cl, "")); 14313242Sgraichen 14413242Sgraichen 14513242Sgraichen /* Spray server with packets */ 14678780Sdd printf ("sending %u packets of lnth %d to %s ...", count, length, 14778780Sdd *argv); 14813242Sgraichen fflush (stdout); 14913242Sgraichen 15013242Sgraichen for (i = 0; i < count; i++) { 15195658Sdes clnt_call(cl, SPRAYPROC_SPRAY, (xdrproc_t)xdr_sprayarr, 15295658Sdes &host_array, (xdrproc_t)xdr_void, NULL, ONE_WAY); 15313242Sgraichen 15413242Sgraichen if (delay) { 15513242Sgraichen usleep(delay); 15613242Sgraichen } 15713242Sgraichen } 15813242Sgraichen 15913242Sgraichen 16013242Sgraichen /* Collect statistics from server */ 16195658Sdes if (clnt_call(cl, SPRAYPROC_GET, (xdrproc_t)xdr_void, NULL, 16295658Sdes (xdrproc_t)xdr_spraycumul, &host_stats, TIMEOUT) != RPC_SUCCESS) 163100121Salfred errx(1, "%s", clnt_sperror(cl, "")); 16413242Sgraichen 16513242Sgraichen xmit_time = host_stats.clock.sec + 16613242Sgraichen (host_stats.clock.usec / 1000000.0); 16713242Sgraichen 16813242Sgraichen printf ("\n\tin %.2f seconds elapsed time\n", xmit_time); 16913242Sgraichen 17013242Sgraichen 17113242Sgraichen /* report dropped packets */ 17213242Sgraichen if (host_stats.counter != count) { 17313242Sgraichen int packets_dropped = count - host_stats.counter; 17413242Sgraichen 17513242Sgraichen printf("\t%d packets (%.2f%%) dropped\n", 17613242Sgraichen packets_dropped, 17713242Sgraichen 100.0 * packets_dropped / count ); 17813242Sgraichen } else { 17913242Sgraichen printf("\tno packets dropped\n"); 18013242Sgraichen } 18113242Sgraichen 18213242Sgraichen printf("Sent:"); 18313242Sgraichen print_xferstats(count, length, xmit_time); 18413242Sgraichen 18513242Sgraichen printf("Rcvd:"); 18613242Sgraichen print_xferstats(host_stats.counter, length, xmit_time); 18713242Sgraichen 18813242Sgraichen exit (0); 18913242Sgraichen} 19013242Sgraichen 19113242Sgraichen 19278780Sddstatic void 19378780Sddprint_xferstats(u_int packets, int packetlen, double xfertime) 19413242Sgraichen{ 19513242Sgraichen int datalen; 19613242Sgraichen double pps; /* packets per second */ 19713242Sgraichen double bps; /* bytes per second */ 19813242Sgraichen 19913242Sgraichen datalen = packets * packetlen; 20013242Sgraichen pps = packets / xfertime; 20113242Sgraichen bps = datalen / xfertime; 20213242Sgraichen 20313242Sgraichen printf("\t%.0f packets/sec, ", pps); 20413242Sgraichen 20513242Sgraichen if (bps >= 1024) 20613242Sgraichen printf ("%.1fK ", bps / 1024); 20713242Sgraichen else 20813242Sgraichen printf ("%.0f ", bps); 20913242Sgraichen 21013242Sgraichen printf("bytes/sec\n"); 21113242Sgraichen} 21213242Sgraichen 21313242Sgraichen 21430598Scharnierstatic void 21578780Sddusage(void) 21613242Sgraichen{ 21730598Scharnier fprintf(stderr, 21830598Scharnier "usage: spray [-c count] [-l length] [-d delay] host\n"); 21913242Sgraichen exit(1); 22013242Sgraichen} 221