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
338006f275SDima Dorfman #include <err.h>
34d021b6c0SThomas Graichen #include <stdio.h>
35d021b6c0SThomas Graichen #include <stdlib.h>
36d021b6c0SThomas Graichen #include <unistd.h>
37d021b6c0SThomas Graichen
38d021b6c0SThomas Graichen #include <rpc/rpc.h>
39d021b6c0SThomas Graichen #include <rpcsvc/spray.h>
40d021b6c0SThomas Graichen
41d021b6c0SThomas Graichen #ifndef SPRAYOVERHEAD
42d021b6c0SThomas Graichen #define SPRAYOVERHEAD 86
43d021b6c0SThomas Graichen #endif
44d021b6c0SThomas Graichen
45*a2cc93ecSAlfonso Gregory static void usage(void) __dead2;
4678978454SDima Dorfman static void print_xferstats(unsigned int, int, double);
47d021b6c0SThomas Graichen
48d021b6c0SThomas Graichen /* spray buffer */
493a01367aSEd Schouten static char spray_buffer[SPRAYMAX];
50d021b6c0SThomas Graichen
51d021b6c0SThomas Graichen /* RPC timeouts */
523a01367aSEd Schouten static struct timeval NO_DEFAULT = { -1, -1 };
533a01367aSEd Schouten static struct timeval ONE_WAY = { 0, 0 };
543a01367aSEd Schouten static struct timeval TIMEOUT = { 25, 0 };
55d021b6c0SThomas Graichen
56d021b6c0SThomas Graichen int
main(int argc,char * argv[])5778978454SDima Dorfman main(int argc, char *argv[])
58d021b6c0SThomas Graichen {
59d021b6c0SThomas Graichen spraycumul host_stats;
60d021b6c0SThomas Graichen sprayarr host_array;
61d021b6c0SThomas Graichen CLIENT *cl;
62d021b6c0SThomas Graichen int c;
6378978454SDima Dorfman u_int i;
6478978454SDima Dorfman u_int count = 0;
65d021b6c0SThomas Graichen int delay = 0;
66d021b6c0SThomas Graichen int length = 0;
67d021b6c0SThomas Graichen double xmit_time; /* time to receive data */
68d021b6c0SThomas Graichen
69d021b6c0SThomas Graichen while ((c = getopt(argc, argv, "c:d:l:")) != -1) {
70d021b6c0SThomas Graichen switch (c) {
71d021b6c0SThomas Graichen case 'c':
72d021b6c0SThomas Graichen count = atoi(optarg);
73d021b6c0SThomas Graichen break;
74d021b6c0SThomas Graichen case 'd':
75d021b6c0SThomas Graichen delay = atoi(optarg);
76d021b6c0SThomas Graichen break;
77d021b6c0SThomas Graichen case 'l':
78d021b6c0SThomas Graichen length = atoi(optarg);
79d021b6c0SThomas Graichen break;
80d021b6c0SThomas Graichen default:
81d021b6c0SThomas Graichen usage();
82d021b6c0SThomas Graichen /* NOTREACHED */
83d021b6c0SThomas Graichen }
84d021b6c0SThomas Graichen }
85d021b6c0SThomas Graichen argc -= optind;
86d021b6c0SThomas Graichen argv += optind;
87d021b6c0SThomas Graichen
88d021b6c0SThomas Graichen if (argc != 1) {
89d021b6c0SThomas Graichen usage();
90d021b6c0SThomas Graichen /* NOTREACHED */
91d021b6c0SThomas Graichen }
92d021b6c0SThomas Graichen
93d021b6c0SThomas Graichen
94d021b6c0SThomas Graichen /* Correct packet length. */
95d021b6c0SThomas Graichen if (length > SPRAYMAX) {
96d021b6c0SThomas Graichen length = SPRAYMAX;
97d021b6c0SThomas Graichen } else if (length < SPRAYOVERHEAD) {
98d021b6c0SThomas Graichen length = SPRAYOVERHEAD;
99d021b6c0SThomas Graichen } else {
100d021b6c0SThomas Graichen /* The RPC portion of the packet is a multiple of 32 bits. */
101d021b6c0SThomas Graichen length -= SPRAYOVERHEAD - 3;
102d021b6c0SThomas Graichen length &= ~3;
103d021b6c0SThomas Graichen length += SPRAYOVERHEAD;
104d021b6c0SThomas Graichen }
105d021b6c0SThomas Graichen
106d021b6c0SThomas Graichen
107d021b6c0SThomas Graichen /*
108d021b6c0SThomas Graichen * The default value of count is the number of packets required
109d021b6c0SThomas Graichen * to make the total stream size 100000 bytes.
110d021b6c0SThomas Graichen */
111d021b6c0SThomas Graichen if (!count) {
112d021b6c0SThomas Graichen count = 100000 / length;
113d021b6c0SThomas Graichen }
114d021b6c0SThomas Graichen
115d021b6c0SThomas Graichen /* Initialize spray argument */
116d021b6c0SThomas Graichen host_array.sprayarr_len = length - SPRAYOVERHEAD;
117d021b6c0SThomas Graichen host_array.sprayarr_val = spray_buffer;
118d021b6c0SThomas Graichen
119d021b6c0SThomas Graichen
120d021b6c0SThomas Graichen /* create connection with server */
121d021b6c0SThomas Graichen cl = clnt_create(*argv, SPRAYPROG, SPRAYVERS, "udp");
1227718805bSPhilippe Charnier if (cl == NULL)
1235a9d606dSAlfred Perlstein errx(1, "%s", clnt_spcreateerror(""));
124d021b6c0SThomas Graichen
125d021b6c0SThomas Graichen
126d021b6c0SThomas Graichen /*
127d021b6c0SThomas Graichen * For some strange reason, RPC 4.0 sets the default timeout,
128d021b6c0SThomas Graichen * thus timeouts specified in clnt_call() are always ignored.
129d021b6c0SThomas Graichen *
130d021b6c0SThomas Graichen * The following (undocumented) hack resets the internal state
131d021b6c0SThomas Graichen * of the client handle.
132d021b6c0SThomas Graichen */
133f249dbccSDag-Erling Smørgrav clnt_control(cl, CLSET_TIMEOUT, &NO_DEFAULT);
134d021b6c0SThomas Graichen
135d021b6c0SThomas Graichen
136d021b6c0SThomas Graichen /* Clear server statistics */
137f249dbccSDag-Erling Smørgrav if (clnt_call(cl, SPRAYPROC_CLEAR, (xdrproc_t)xdr_void, NULL,
138f249dbccSDag-Erling Smørgrav (xdrproc_t)xdr_void, NULL, TIMEOUT) != RPC_SUCCESS)
1395a9d606dSAlfred Perlstein errx(1, "%s", clnt_sperror(cl, ""));
140d021b6c0SThomas Graichen
141d021b6c0SThomas Graichen
142d021b6c0SThomas Graichen /* Spray server with packets */
14366a981f2SAlan Somers printf ("sending %u packets of length %d to %s ...", count, length,
14478978454SDima Dorfman *argv);
145d021b6c0SThomas Graichen fflush (stdout);
146d021b6c0SThomas Graichen
147d021b6c0SThomas Graichen for (i = 0; i < count; i++) {
148f249dbccSDag-Erling Smørgrav clnt_call(cl, SPRAYPROC_SPRAY, (xdrproc_t)xdr_sprayarr,
149f249dbccSDag-Erling Smørgrav &host_array, (xdrproc_t)xdr_void, NULL, ONE_WAY);
150d021b6c0SThomas Graichen
151d021b6c0SThomas Graichen if (delay) {
152d021b6c0SThomas Graichen usleep(delay);
153d021b6c0SThomas Graichen }
154d021b6c0SThomas Graichen }
155d021b6c0SThomas Graichen
156d021b6c0SThomas Graichen
157d021b6c0SThomas Graichen /* Collect statistics from server */
158f249dbccSDag-Erling Smørgrav if (clnt_call(cl, SPRAYPROC_GET, (xdrproc_t)xdr_void, NULL,
159f249dbccSDag-Erling Smørgrav (xdrproc_t)xdr_spraycumul, &host_stats, TIMEOUT) != RPC_SUCCESS)
1605a9d606dSAlfred Perlstein errx(1, "%s", clnt_sperror(cl, ""));
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
18978978454SDima Dorfman static void
print_xferstats(u_int packets,int packetlen,double xfertime)19078978454SDima Dorfman print_xferstats(u_int packets, int packetlen, double xfertime)
191d021b6c0SThomas Graichen {
192d021b6c0SThomas Graichen int datalen;
193d021b6c0SThomas Graichen double pps; /* packets per second */
194d021b6c0SThomas Graichen double bps; /* bytes per second */
195d021b6c0SThomas Graichen
196d021b6c0SThomas Graichen datalen = packets * packetlen;
197d021b6c0SThomas Graichen pps = packets / xfertime;
198d021b6c0SThomas Graichen bps = datalen / xfertime;
199d021b6c0SThomas Graichen
200d021b6c0SThomas Graichen printf("\t%.0f packets/sec, ", pps);
201d021b6c0SThomas Graichen
202d021b6c0SThomas Graichen if (bps >= 1024)
203d021b6c0SThomas Graichen printf ("%.1fK ", bps / 1024);
204d021b6c0SThomas Graichen else
205d021b6c0SThomas Graichen printf ("%.0f ", bps);
206d021b6c0SThomas Graichen
207d021b6c0SThomas Graichen printf("bytes/sec\n");
208d021b6c0SThomas Graichen }
209d021b6c0SThomas Graichen
210d021b6c0SThomas Graichen
21140d3f8a9SPhilippe Charnier static void
usage(void)21278978454SDima Dorfman usage(void)
213d021b6c0SThomas Graichen {
21440d3f8a9SPhilippe Charnier fprintf(stderr,
21540d3f8a9SPhilippe Charnier "usage: spray [-c count] [-l length] [-d delay] host\n");
216d021b6c0SThomas Graichen exit(1);
217d021b6c0SThomas Graichen }
218