From grymoire.crd.ge.com!barnett Tue Aug 30 14:42:41 1994
Return-Path: <barnett@grymoire.crd.ge.com>
Received: from crdems.ge.com by iifeak.swan.ac.uk  with smtp
	(Linux Smail3.1.28.1 #1) id m0qfTSN-00014JC; Tue, 30 Aug 94 14:42 BST
Received:  from grymoire.crd.ge.com by crdems.ge.com (5.65/GE 1.77) id AA09915; Tue, 30 Aug 94 09:37:44 -0400
Received: by grymoire.crd.ge.com (5.0/SMI-SVR4)id AA01710; Tue, 30 Aug 1994 09:37:02 +0500
Date: Tue, 30 Aug 1994 09:37:02 +0500
From: barnett@grymoire.crd.ge.com (Bruce Barnett)
Message-Id: <9408301337.AA01710@grymoire.crd.ge.com>
To: iialan@www.linux.org.uk
Subject: ttcp-source
Content-Length: 23440
Status: RO

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  README ttcp.c
# Wrapped by barnett@grymoire on Tue Aug 30 09:36:35 1994
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f README -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"README\"
else
echo shar: Extracting \"README\" \(781 characters\)
sed "s/^X//" >README <<'END_OF_README'
XTTCP is a benchmarking tool for determining TCP and UDP performance 
Xbetween 2 systems.
X
XThe program was created at the US Army Ballistics Research Lab (BRL)
Xand is in the public domain. Feel free to distribute this program
Xbut please do leave the credit notices in the source and man page intact.
X
XContents of this directory:
X
Xttcp.c		Source that runs on IRIX 3.3.x and 4.0.x systems
X		and BSD-based systems.  This version also uses getopt(3) 
X		and has 2 new options: -f and -T.
X
Xttcp.c-brl	Original source from BRL.
X
Xttcp.1		Manual page (describes ttcp.c options, which are a 
X		superset of the other version).
X
X
XHow to get TCP performance numbers:
X
X	receiver				sender
X
Xhost1%  ttcp -r -s			host2% ttcp -t -s host1
X
X-n and -l options change the number and size of the buffers.
END_OF_README
if test 781 -ne `wc -c <README`; then
    echo shar: \"README\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ttcp.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"ttcp.c\"
else
echo shar: Extracting \"ttcp.c\" \(20532 characters\)
sed "s/^X//" >ttcp.c <<'END_OF_ttcp.c'
X/*
X *	T T C P . C
X *
X * Test TCP connection.  Makes a connection on port 5001
X * and transfers fabricated buffers or data copied from stdin.
X *
X * Usable on 4.2, 4.3, and 4.1a systems by defining one of
X * BSD42 BSD43 (BSD41a)
X * Machines using System V with BSD sockets should define SYSV.
X *
X * Modified for operation under 4.2BSD, 18 Dec 84
X *      T.C. Slattery, USNA
X * Minor improvements, Mike Muuss and Terry Slattery, 16-Oct-85.
X * Modified in 1989 at Silicon Graphics, Inc.
X *	catch SIGPIPE to be able to print stats when receiver has died 
X *	for tcp, don't look for sentinel during reads to allow small transfers
X *	increased default buffer size to 8K, nbuf to 2K to transfer 16MB
X *	moved default port to 5001, beyond IPPORT_USERRESERVED
X *	make sinkmode default because it is more popular, 
X *		-s now means don't sink/source 
X *	count number of read/write system calls to see effects of 
X *		blocking from full socket buffers
X *	for tcp, -D option turns off buffered writes (sets TCP_NODELAY sockopt)
X *	buffer alignment options, -A and -O
X *	print stats in a format that's a bit easier to use with grep & awk
X *	for SYSV, mimic BSD routines to use most of the existing timing code
X * Modified by Steve Miller of the University of Maryland, College Park
X *	-b sets the socket buffer size (SO_SNDBUF/SO_RCVBUF)
X * Modified Sept. 1989 at Silicon Graphics, Inc.
X *	restored -s sense at request of tcs@brl
X * Modified Oct. 1991 at Silicon Graphics, Inc.
X *	use getopt(3) for option processing, add -f and -T options.
X *	SGI IRIX 3.3 and 4.0 releases don't need #define SYSV.
X * Modified August 1994 by Bruce Barnett <barnett@crd.ge.com>
X *      Solaris 2.3 (which needs -DSOLARIS -lsocket -lnsl)
X *	Removed some lint errors.
X *	Added HAVE_bcopy macros - which will hopefully simplify porting
X *
X * Distribution Status -
X *      Public Domain.  Distribution Unlimited.
X */
X#ifndef lint
Xstatic char RCSid[] = "ttcp.c $Revision: 1.12 (bgb patches 8/30/95) $";
X#endif
X
X#define BSD43  /* */
X/* #define BSD42 */
X/* #define BSD41a */
X/* #define SYSV /* required on SGI IRIX releases before 3.3 */
X/* #define SOLARIS /* needed for SunOS 5.3 */
X
X#ifdef SOLARIS
X#define SYSV
X#endif
X
X#ifdef hpux
X#define SYSV
X#endif
X
X#ifndef SYSV
X#define HAVE_bcopy
X#define HAVE_bzero
X#endif
X
X#ifndef HAVE_bcopy
X#define bcopy(s,d,h) memcpy((d),(s),(h))
X#endif
X#ifndef HAVE_bzero
X#define bzero(p,h) memset((p),0,(h))
X#endif
X
X#include <stdio.h>
X#include <signal.h>
X#include <ctype.h>
X#include <errno.h>
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X#include <netinet/tcp.h>
X#include <arpa/inet.h>
X#include <netdb.h>
X#include <sys/time.h>		/* struct timeval */
X
X#if defined(SYSV)
X#include <sys/times.h>
X#include <sys/param.h>
Xstruct rusage {
X    struct timeval ru_utime, ru_stime;
X};
X#define RUSAGE_SELF 0
X#else
X#include <sys/resource.h>
X#endif
X
Xstruct sockaddr_in sinme;
Xstruct sockaddr_in sinhim;
Xstruct sockaddr_in frominet;
Xstruct sockaddr *psock;
X
Xint domain, fromlen;
Xint fd;				/* fd of network socket */
Xint newfd;			/* fd of network socket */
X
Xint buflen = 8 * 1024;		/* length of buffer */
Xchar *buf;			/* ptr to dynamic buffer */
Xint nbuf = 2 * 1024;		/* number of buffers to send in sinkmode */
X
Xint bufoffset = 0;		/* align buffer to this */
Xint bufalign = 16*1024;		/* modulo this */
X
Xint udp = 0;			/* 0 = tcp, !0 = udp */
Xint options = 0;		/* socket options */
Xint one = 1;                    /* for 4.3 BSD style setsockopt() */
Xshort port = 5001;		/* TCP port number */
Xchar *host;			/* ptr to name of host */
Xint trans;			/* 0=receive, !0=transmit mode */
Xint sinkmode = 0;		/* 0=normal I/O, !0=sink/source mode */
Xint verbose = 0;		/* 0=print basic info, 1=print cpu rate, proc
X				 * resource usage. */
Xint nodelay = 0;		/* set TCP_NODELAY socket option */
Xint b_flag = 0;			/* use mread() */
Xint sockbufsize = 0;		/* socket buffer size to use */
Xchar fmt = 'K';			/* output format: k = kilobits, K = kilobytes,
X				 *  m = megabits, M = megabytes, 
X				 *  g = gigabits, G = gigabytes */
Xint touchdata = 0;		/* access data after reading */
X
Xstruct hostent *addr;
Xextern int errno;
Xextern int optind;
Xextern char *optarg;
X
Xchar Usage[] = "\
XUsage: ttcp -t [-options] host [ < in ]\n\
X       ttcp -r [-options > out]\n\
XCommon options:\n\
X	-l ##	length of bufs read from or written to network (default 8192)\n\
X	-u	use UDP instead of TCP\n\
X	-p ##	port number to send to or listen at (default 5001)\n\
X	-s	-t: source a pattern to network\n\
X		-r: sink (discard) all data from network\n\
X	-A	align the start of buffers to this modulus (default 16384)\n\
X	-O	start buffers at this offset from the modulus (default 0)\n\
X	-v	verbose: print more statistics\n\
X	-d	set SO_DEBUG socket option\n\
X	-b ##	set socket buffer size (if supported)\n\
X	-f X	format for rate: k,K = kilo{bit,byte}; m,M = mega; g,G = giga\n\
XOptions specific to -t:\n\
X	-n##	number of source bufs written to network (default 2048)\n\
X	-D	don't buffer TCP writes (sets TCP_NODELAY socket option)\n\
XOptions specific to -r:\n\
X	-B	for -s, only output full blocks as specified by -l (for TAR)\n\
X	-T	\"touch\": access each byte as it's read\n\
X";	
X
Xchar stats[128];
Xdouble nbytes;			/* bytes on net */
Xunsigned long numCalls;		/* # of I/O system calls */
Xdouble cput, realt;		/* user, real time (seconds) */
X
Xvoid err();
Xvoid mes();
Xvoid pattern();
Xvoid prep_timer();
Xdouble read_timer();
Xint Nread();
Xint Nwrite();
Xvoid delay();
Xint mread();
Xchar *outfmt();
X
Xvoid
Xsigpipe()
X{
X}
X
Xmain(argc,argv)
Xint argc;
Xchar **argv;
X{
X	unsigned long addr_tmp;
X	int c;
X
X	if (argc < 2) goto usage;
X
X	while ((c = getopt(argc, argv, "drstuvBDTb:f:l:n:p:A:O:")) != -1) {
X		switch (c) {
X
X		case 'B':
X			b_flag = 1;
X			break;
X		case 't':
X			trans = 1;
X			break;
X		case 'r':
X			trans = 0;
X			break;
X		case 'd':
X			options |= SO_DEBUG;
X			break;
X		case 'D':
X#ifdef TCP_NODELAY
X			nodelay = 1;
X#else
X			fprintf(stderr, 
X	"ttcp: -D option ignored: TCP_NODELAY socket option not supported\n");
X#endif
X			break;
X		case 'n':
X			nbuf = atoi(optarg);
X			break;
X		case 'l':
X			buflen = atoi(optarg);
X			break;
X		case 's':
X			sinkmode = !sinkmode;
X			break;
X		case 'p':
X			port = atoi(optarg);
X			break;
X		case 'u':
X			udp = 1;
X			break;
X		case 'v':
X			verbose = 1;
X			break;
X		case 'A':
X			bufalign = atoi(optarg);
X			break;
X		case 'O':
X			bufoffset = atoi(optarg);
X			break;
X		case 'b':
X#if defined(SO_SNDBUF) || defined(SO_RCVBUF)
X			sockbufsize = atoi(optarg);
X#else
X			fprintf(stderr, 
X"ttcp: -b option ignored: SO_SNDBUF/SO_RCVBUF socket options not supported\n");
X#endif
X			break;
X		case 'f':
X			fmt = *optarg;
X			break;
X		case 'T':
X			touchdata = 1;
X			break;
X
X		default:
X			goto usage;
X		}
X	}
X	if(trans)  {
X		/* xmitr */
X		if (optind == argc)
X			goto usage;
X		bzero((char *)&sinhim, sizeof(sinhim));
X		host = argv[optind];
X		if (atoi(host) > 0 )  {
X			/* Numeric */
X			sinhim.sin_family = AF_INET;
X#if defined(cray)
X			addr_tmp = inet_addr(host);
X			sinhim.sin_addr = addr_tmp;
X#else
X			sinhim.sin_addr.s_addr = inet_addr(host);
X#endif
X		} else {
X			if ((addr=gethostbyname(host)) == NULL)
X				err("bad hostname");
X			sinhim.sin_family = addr->h_addrtype;
X			bcopy(addr->h_addr,(char*)&addr_tmp, addr->h_length);
X#if defined(cray)
X			sinhim.sin_addr = addr_tmp;
X#else
X			sinhim.sin_addr.s_addr = addr_tmp;
X#endif /* cray */
X		}
X		sinhim.sin_port = htons(port);
X#ifdef SOLARIS
X		sinme.sin_family = AF_INET;	/* Solaris needs this */
X#endif /* SOLARIS */
X		sinme.sin_port = 0;		/* free choice */
X	} else {
X		/* rcvr */
X		sinme.sin_port =  htons(port);
X/*		sinme.sin_addr.s_addr = htonl(INADDR_ANY); */
X	}
X
X
X	if (udp && buflen < 5) {
X	    buflen = 5;		/* send more than the sentinel size */
X	}
X
X	if ( (buf = (char *)malloc((unsigned)(buflen+bufalign))) == (char *)NULL)
X		err("malloc");
X	if (bufalign != 0)
X		buf +=(bufalign - ((int)buf % bufalign) + bufoffset) % bufalign;
X
X	if (trans) {
X	    fprintf(stdout,
X	    "ttcp-t: buflen=%d, nbuf=%d, align=%d/%d, port=%d",
X		buflen, nbuf, bufalign, bufoffset, port);
X 	    if (sockbufsize)
X 		fprintf(stdout, ", sockbufsize=%d", sockbufsize);
X 	    fprintf(stdout, "  %s  -> %s\n", udp?"udp":"tcp", host);
X	} else {
X	    fprintf(stdout,
X 	    "ttcp-r: buflen=%d, nbuf=%d, align=%d/%d, port=%d",
X 		buflen, nbuf, bufalign, bufoffset, port);
X 	    if (sockbufsize)
X 		fprintf(stdout, ", sockbufsize=%d", sockbufsize);
X 	    fprintf(stdout, "  %s\n", udp?"udp":"tcp");
X	}
X
X	if ((fd = socket(AF_INET, udp?SOCK_DGRAM:SOCK_STREAM, 0)) < 0)
X		err("socket");
X	mes("socket");
X
X	if (bind(fd, (struct sockaddr *)&sinme, sizeof(sinme)) < 0)
X	      err("bind");
X
X#if defined(SO_SNDBUF) || defined(SO_RCVBUF)
X	if (sockbufsize) {
X	    if (trans) {
X		if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const char *) &sockbufsize,
X		    sizeof sockbufsize) < 0)
X			err("setsockopt: sndbuf");
X		mes("sndbuf");
X	    } else {
X		if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF,(const char *)  &sockbufsize,
X		    sizeof sockbufsize) < 0)
X			err("setsockopt: rcvbuf");
X		mes("rcvbuf");
X	    }
X	}
X#endif
X
X	if (!udp)  {
X	    signal(SIGPIPE, (void (*)(int)) sigpipe);
X	    if (trans) {
X		/* We are the client if transmitting */
X		if (options)  {
X#if defined(BSD42)
X			if( setsockopt(fd, SOL_SOCKET, options, 0, 0) < 0)
X#else /* BSD43 */
X			if( setsockopt(fd, SOL_SOCKET, options, (const char *)&one, sizeof(one)) < 0)
X#endif
X				err("setsockopt");
X		}
X#ifdef TCP_NODELAY
X		if (nodelay) {
X			struct protoent *p;
X			p = getprotobyname("tcp");
X			if( p && setsockopt(fd, p->p_proto, TCP_NODELAY, 
X			    (const char *)&one, sizeof(one)) < 0)
X				err("setsockopt: nodelay");
X			mes("nodelay");
X		}
X#endif
X		if(connect(fd, (struct sockaddr *)&sinhim, sizeof(sinhim) ) < 0)
X			err("connect");
X		mes("connect");
X	    } else {
X		/* otherwise, we are the server and 
X	         * should listen for the connections
X	         */
X#if defined(ultrix) || defined(sgi) || defined(SOLARIS)
X		listen(fd,1);   /* workaround for alleged u4.2 bug */
X#else
X		listen(fd,0);   /* allow a queue of 0 */
X#endif
X		if(options)  {
X#if defined(BSD42)
X			if( setsockopt(fd, SOL_SOCKET, options, 0, 0) < 0)
X#else /* BSD43 */
X			if( setsockopt(fd, SOL_SOCKET, options, (const char *)&one, sizeof(one)) < 0)
X#endif
X				err("setsockopt");
X		}
X		fromlen = sizeof(frominet);
X		domain = AF_INET;
X/* generally it's not a good idea to reuse the same file descriptor. 
X * typically it's 
X *           newfd=accept(fd,.....)
X * But in this case, we are only using it once - so it's all right - bgb
X */
X		if((fd=accept(fd, (struct sockaddr *)&frominet, &fromlen) ) < 0)
X			err("accept");
X		{ struct sockaddr_in peer;
X		  int peerlen = sizeof(peer);
X		  if (getpeername(fd, (struct sockaddr *) &peer, 
X				&peerlen) < 0) {
X			err("getpeername");
X		  }
X		  fprintf(stderr,"ttcp-r: accept from %s\n", 
X			inet_ntoa(peer.sin_addr));
X		}
X	    }
X	}
X	prep_timer();
X	errno = 0;
X	if (sinkmode) {      
X		register int cnt;
X		if (trans)  {
X			pattern( buf, buflen );
X			if(udp)  (void)Nwrite( fd, buf, 4 ); /* rcvr start */
X			while (nbuf-- && Nwrite(fd,buf,buflen) == buflen)
X				nbytes += buflen;
X			if(udp)  (void)Nwrite( fd, buf, 4 ); /* rcvr end */
X		} else {
X			if (udp) {
X			    while ((cnt=Nread(fd,buf,buflen)) > 0)  {
X				    static int going = 0;
X				    if( cnt <= 4 )  {
X					    if( going )
X						    break;	/* "EOF" */
X					    going = 1;
X					    prep_timer();
X				    } else {
X					    nbytes += cnt;
X				    }
X			    }
X			} else {
X			    while ((cnt=Nread(fd,buf,buflen)) > 0)  {
X				    nbytes += cnt;
X			    }
X			}
X		}
X	} else {
X		register int cnt;
X		if (trans)  {
X			while((cnt=read(0,buf,(unsigned)buflen)) > 0 &&
X			    Nwrite(fd,buf,cnt) == cnt)
X				nbytes += cnt;
X		}  else  {
X			while((cnt=Nread(fd,buf,buflen)) > 0 &&
X			    write(1,buf,(unsigned)cnt) == cnt)
X				nbytes += cnt;
X		}
X	}
X	if(errno) err("IO");
X	(void)read_timer(stats,sizeof(stats));
X	if(udp&&trans)  {
X		(void)Nwrite( fd, buf, 4 ); /* rcvr end */
X		(void)Nwrite( fd, buf, 4 ); /* rcvr end */
X		(void)Nwrite( fd, buf, 4 ); /* rcvr end */
X		(void)Nwrite( fd, buf, 4 ); /* rcvr end */
X	}
X	if( cput <= 0.0 )  cput = 0.001;
X	if( realt <= 0.0 )  realt = 0.001;
X	fprintf(stdout,
X		"ttcp%s: %.0f bytes in %.2f real seconds = %s/sec +++\n",
X		trans?"-t":"-r",
X		nbytes, realt, outfmt(nbytes/realt));
X	if (verbose) {
X	    fprintf(stdout,
X		"ttcp%s: %.0f bytes in %.2f CPU seconds = %s/cpu sec\n",
X		trans?"-t":"-r",
X		nbytes, cput, outfmt(nbytes/cput));
X	}
X	fprintf(stdout,
X		"ttcp%s: %d I/O calls, msec/call = %.2f, calls/sec = %.2f\n",
X		trans?"-t":"-r",
X		(int) numCalls,
X		1024.0 * realt/((double)numCalls),
X		((double)numCalls)/realt);
X	fprintf(stdout,"ttcp%s: %s\n", trans?"-t":"-r", stats);
X	if (verbose) {
X	    fprintf(stdout,
X		"ttcp%s: buffer address %#x\n",
X		trans?"-t":"-r",
X		(int) buf);
X	}
X	exit(0);
Xusage:
X	fprintf(stderr,Usage);
X	exit(1);
X	/* NOTREACHED */
X}
X
Xvoid
Xerr(s)
Xchar *s;
X{
X	fprintf(stderr,"ttcp%s: ", trans?"-t":"-r");
X	perror(s);
X	fprintf(stderr,"errno=%d\n",errno);
X	exit(1);
X}
X
Xvoid
Xmes(s)
Xchar *s;
X{
X	fprintf(stderr,"ttcp%s: %s\n", trans?"-t":"-r", s);
X}
X
Xvoid pattern( cp, cnt )
Xregister char *cp;
Xregister int cnt;
X{
X	register char c;
X	c = 0;
X	while( cnt-- > 0 )  {
X		while( !isprint((c&0x7F)) )  c++;
X		*cp++ = (c++&0x7F);
X	}
X}
X
Xchar *
Xoutfmt(b)
Xdouble b;
X{
X    static char obuf[50];
X    switch (fmt) {
X	case 'G':
X	    sprintf(obuf, "%.2f GB", b / 1024.0 / 1024.0 / 1024.0);
X	    break;
X	default:
X	case 'K':
X	    sprintf(obuf, "%.2f KB", b / 1024.0);
X	    break;
X	case 'M':
X	    sprintf(obuf, "%.2f MB", b / 1024.0 / 1024.0);
X	    break;
X	case 'g':
X	    sprintf(obuf, "%.2f Gbit", b * 8.0 / 1024.0 / 1024.0 / 1024.0);
X	    break;
X	case 'k':
X	    sprintf(obuf, "%.2f Kbit", b * 8.0 / 1024.0);
X	    break;
X	case 'm':
X	    sprintf(obuf, "%.2f Mbit", b * 8.0 / 1024.0 / 1024.0);
X	    break;
X    }
X    return obuf;
X}
X
Xstatic struct	timeval time0;	/* Time at which timing started */
Xstatic struct	rusage ru0;	/* Resource utilization at the start */
X
Xstatic void prusage();
Xstatic void tvadd();
Xstatic void tvsub();
Xstatic void psecs();
X
X#if defined(SYSV)
X/*ARGSUSED*/
Xstatic void
Xgetrusage(ignored, ru)
X    int ignored;
X    register struct rusage *ru;
X{
X    struct tms buf;
X
X    times(&buf);
X
X    /* Assumption: HZ <= 2147 (LONG_MAX/1000000) */
X    ru->ru_stime.tv_sec  = buf.tms_stime / HZ;
X    ru->ru_stime.tv_usec = ((buf.tms_stime % HZ) * 1000000) / HZ;
X    ru->ru_utime.tv_sec  = buf.tms_utime / HZ;
X    ru->ru_utime.tv_usec = ((buf.tms_utime % HZ) * 1000000) / HZ;
X}
X
X/*ARGSUSED*/
Xstatic  void
Xgettimeofday(tp, zp)
X    struct timeval *tp;
X    struct timezone *zp;
X{
X    tp->tv_sec = time(0);
X    tp->tv_usec = 0;
X}
X#endif /* SYSV */
X
X/*
X *			P R E P _ T I M E R
X */
Xvoid
Xprep_timer()
X{
X	gettimeofday(&time0, (struct timezone *)0);
X	getrusage(RUSAGE_SELF, &ru0);
X}
X
X/*
X *			R E A D _ T I M E R
X * 
X */
Xdouble
Xread_timer(str,len)
Xchar *str;
X{
X	struct timeval timedol;
X	struct rusage ru1;
X	struct timeval td;
X	struct timeval tend, tstart;
X	char line[132];
X
X	getrusage(RUSAGE_SELF, &ru1);
X	gettimeofday(&timedol, (struct timezone *)0);
X	prusage(&ru0, &ru1, &timedol, &time0, line);
X	(void)strncpy( str, line, (unsigned)len );
X
X	/* Get real time */
X	tvsub( &td, &timedol, &time0 );
X	realt = td.tv_sec + ((double)td.tv_usec) / 1000000;
X
X	/* Get CPU time (user+sys) */
X	tvadd( &tend, &ru1.ru_utime, &ru1.ru_stime );
X	tvadd( &tstart, &ru0.ru_utime, &ru0.ru_stime );
X	tvsub( &td, &tend, &tstart );
X	cput = td.tv_sec + ((double)td.tv_usec) / 1000000;
X	if( cput < 0.00001 )  cput = 0.00001;
X	return( cput );
X}
X
Xstatic void
Xprusage(r0, r1, e, b, outp)
X	register struct rusage *r0, *r1;
X	struct timeval *e, *b;
X	char *outp;
X{
X	struct timeval tdiff;
X	register time_t t;
X	register char *cp;
X#if !defined(SYSV)
X	register int i;
X#endif
X	int ms;
X
X	t = (r1->ru_utime.tv_sec-r0->ru_utime.tv_sec)*100+
X	    (r1->ru_utime.tv_usec-r0->ru_utime.tv_usec)/10000+
X	    (r1->ru_stime.tv_sec-r0->ru_stime.tv_sec)*100+
X	    (r1->ru_stime.tv_usec-r0->ru_stime.tv_usec)/10000;
X	ms =  (e->tv_sec-b->tv_sec)*100 + (e->tv_usec-b->tv_usec)/10000;
X
X#define END(x)	{while(*x) x++;}
X#if defined(SYSV)
X	cp = "%Uuser %Ssys %Ereal %P";
X#else
X#if defined(sgi)		/* IRIX 3.3 will show 0 for %M,%F,%R,%C */
X	cp = "%Uuser %Ssys %Ereal %P %Mmaxrss %F+%Rpf %Ccsw";
X#else
X	cp = "%Uuser %Ssys %Ereal %P %Xi+%Dd %Mmaxrss %F+%Rpf %Ccsw";
X#endif
X#endif
X	for (; *cp; cp++)  {
X		if (*cp != '%')
X			*outp++ = *cp;
X		else if (cp[1]) switch(*++cp) {
X
X		case 'U':
X			tvsub(&tdiff, &r1->ru_utime, &r0->ru_utime);
X			(void) sprintf(outp,"%d.%01d", (int) tdiff.tv_sec, (int) tdiff.tv_usec/100000);
X			END(outp);
X			break;
X
X		case 'S':
X			tvsub(&tdiff, &r1->ru_stime, &r0->ru_stime);
X			(void) sprintf(outp,"%d.%01d", (int) tdiff.tv_sec, (int) tdiff.tv_usec/100000);
X			END(outp);
X			break;
X
X		case 'E':
X			psecs((long) (ms / 100), outp);
X			END(outp);
X			break;
X
X		case 'P':
X			sprintf(outp,"%d%%", (int) (t*100 / ((ms ? ms : 1))));
X			END(outp);
X			break;
X
X#if !defined(SYSV)
X		case 'W':
X			i = r1->ru_nswap - r0->ru_nswap;
X			sprintf(outp,"%d", i);
X			END(outp);
X			break;
X
X		case 'X':
X			sprintf(outp,"%d", t == 0 ? 0 : (r1->ru_ixrss-r0->ru_ixrss)/t);
X			END(outp);
X			break;
X
X		case 'D':
X			sprintf(outp,"%d", t == 0 ? 0 :
X			    (r1->ru_idrss+r1->ru_isrss-(r0->ru_idrss+r0->ru_isrss))/t);
X			END(outp);
X			break;
X
X		case 'K':
X			sprintf(outp,"%d", t == 0 ? 0 :
X			    ((r1->ru_ixrss+r1->ru_isrss+r1->ru_idrss) -
X			    (r0->ru_ixrss+r0->ru_idrss+r0->ru_isrss))/t);
X			END(outp);
X			break;
X
X		case 'M':
X			sprintf(outp,"%d", r1->ru_maxrss/2);
X			END(outp);
X			break;
X
X		case 'F':
X			sprintf(outp,"%d", r1->ru_majflt-r0->ru_majflt);
X			END(outp);
X			break;
X
X		case 'R':
X			sprintf(outp,"%d", r1->ru_minflt-r0->ru_minflt);
X			END(outp);
X			break;
X
X		case 'I':
X			sprintf(outp,"%d", r1->ru_inblock-r0->ru_inblock);
X			END(outp);
X			break;
X
X		case 'O':
X			sprintf(outp,"%d", r1->ru_oublock-r0->ru_oublock);
X			END(outp);
X			break;
X		case 'C':
X			sprintf(outp,"%d+%d", r1->ru_nvcsw-r0->ru_nvcsw,
X				r1->ru_nivcsw-r0->ru_nivcsw );
X			END(outp);
X			break;
X#endif /* !SYSV */
X		}
X	}
X	*outp = '\0';
X}
X
Xstatic void
Xtvadd(tsum, t0, t1)
X	struct timeval *tsum, *t0, *t1;
X{
X
X	tsum->tv_sec = t0->tv_sec + t1->tv_sec;
X	tsum->tv_usec = t0->tv_usec + t1->tv_usec;
X	if (tsum->tv_usec > 1000000)
X		tsum->tv_sec++, tsum->tv_usec -= 1000000;
X}
X
Xstatic void
Xtvsub(tdiff, t1, t0)
X	struct timeval *tdiff, *t1, *t0;
X{
X
X	tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
X	tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
X	if (tdiff->tv_usec < 0)
X		tdiff->tv_sec--, tdiff->tv_usec += 1000000;
X}
X
Xstatic void
Xpsecs(l,cp)
Xlong l;
Xregister char *cp;
X{
X	register int i;
X
X	i = l / 3600;
X	if (i) {
X		sprintf(cp,"%d:", i);
X		END(cp);
X		i = l % 3600;
X		sprintf(cp,"%d%d", (i/60) / 10, (i/60) % 10);
X		END(cp);
X	} else {
X		i = l;
X		sprintf(cp,"%d", i / 60);
X		END(cp);
X	}
X	i %= 60;
X	*cp++ = ':';
X	sprintf(cp,"%d%d", i / 10, i % 10);
X}
X
X/*
X *			N R E A D
X */
XNread( fd, buf, count )
Xint fd;
Xvoid *buf;
Xint count;
X{
X	struct sockaddr_in from;
X	int len = sizeof(from);
X	register int cnt;
X	if( udp )  {
X		cnt = recvfrom( fd, buf, count, 0, (struct sockaddr *)&from, &len );
X		numCalls++;
X	} else {
X		if( b_flag )
X			cnt = mread( fd, buf, (unsigned) count );	/* fill buf */
X		else {
X			cnt = read( fd, buf, (unsigned) count );
X			numCalls++;
X		}
X		if (touchdata && cnt > 0) {
X			register int c = cnt, sum = 0;
X			register char *b = buf;
X			while (c--)
X				sum += *b++;
X		}
X	}
X	return(cnt);
X}
X
X/*
X *			N W R I T E
X */
XNwrite( fd, buf, count )
Xint fd;
Xvoid *buf;
Xint count;
X{
X	register int cnt;
X	if( udp )  {
Xagain:
X		cnt = sendto( fd, buf, count, 0, (struct sockaddr *)&sinhim, sizeof(sinhim) );
X		numCalls++;
X		if( cnt<0 && errno == ENOBUFS )  {
X			delay(18000);
X			errno = 0;
X			goto again;
X		}
X	} else {
X		cnt = write( fd, buf, (unsigned)count );
X		numCalls++;
X	}
X	return(cnt);
X}
X
Xvoid
Xdelay(us)
X{
X	struct timeval tv;
X
X	tv.tv_sec = 0;
X	tv.tv_usec = us;
X	(void)select( 1, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
X}
X
X/*
X *			M R E A D
X *
X * This function performs the function of a read(II) but will
X * call read(II) multiple times in order to get the requested
X * number of characters.  This can be necessary because
X * network connections don't deliver data with the same
X * grouping as it is written with.  Written by Robert S. Miles, BRL.
X */
Xint
Xmread(fd, bufp, n)
Xint fd;
Xregister char	*bufp;
Xunsigned	n;
X{
X	register unsigned	count = 0;
X	register int		nread;
X
X	do {
X		nread = read(fd, bufp, n-count);
X		numCalls++;
X		if(nread < 0)  {
X			perror("ttcp_mread");
X			return(-1);
X		}
X		if(nread == 0)
X			return((int)count);
X		count += (unsigned)nread;
X		bufp += nread;
X	 } while(count < n);
X
X	return((int)count);
X}
END_OF_ttcp.c
if test 20532 -ne `wc -c <ttcp.c`; then
    echo shar: \"ttcp.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of shell archive.
exit 0

