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