File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ttcp / ttcp.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 16:47:04 2012 UTC (12 years, 3 months ago) by misho
Branches: ttcp, MAIN
CVS tags: v0p0, v0, HEAD
ttcp

    1: /*
    2:  *	T T C P . C
    3:  *
    4:  * Test TCP connection.  Makes a connection on port 5001
    5:  * and transfers fabricated buffers or data copied from stdin.
    6:  *
    7:  * Usable on 4.2, 4.3, and 4.1a systems by defining one of
    8:  * BSD42 BSD43 (BSD41a)
    9:  * Machines using System V with BSD sockets should define SYSV.
   10:  *
   11:  * Modified for operation under 4.2BSD, 18 Dec 84
   12:  *      T.C. Slattery, USNA
   13:  * Minor improvements, Mike Muuss and Terry Slattery, 16-Oct-85.
   14:  * Modified in 1989 at Silicon Graphics, Inc.
   15:  *	catch SIGPIPE to be able to print stats when receiver has died 
   16:  *	for tcp, don't look for sentinel during reads to allow small transfers
   17:  *	increased default buffer size to 8K, nbuf to 2K to transfer 16MB
   18:  *	moved default port to 5001, beyond IPPORT_USERRESERVED
   19:  *	make sinkmode default because it is more popular, 
   20:  *		-s now means don't sink/source 
   21:  *	count number of read/write system calls to see effects of 
   22:  *		blocking from full socket buffers
   23:  *	for tcp, -D option turns off buffered writes (sets TCP_NODELAY sockopt)
   24:  *	buffer alignment options, -A and -O
   25:  *	print stats in a format that's a bit easier to use with grep & awk
   26:  *	for SYSV, mimic BSD routines to use most of the existing timing code
   27:  * Modified by Steve Miller of the University of Maryland, College Park
   28:  *	-b sets the socket buffer size (SO_SNDBUF/SO_RCVBUF)
   29:  * Modified Sept. 1989 at Silicon Graphics, Inc.
   30:  *	restored -s sense at request of tcs@brl
   31:  * Modified Oct. 1991 at Silicon Graphics, Inc.
   32:  *	use getopt(3) for option processing, add -f and -T options.
   33:  *	SGI IRIX 3.3 and 4.0 releases don't need #define SYSV.
   34:  *
   35:  * Distribution Status -
   36:  *      Public Domain.  Distribution Unlimited.
   37:  */
   38: 
   39: #define BSD43
   40: /* #define BSD42 */
   41: /* #define BSD41a */
   42: /* #define SYSV */	/* required on SGI IRIX releases before 3.3 */
   43: 
   44: #include <stdio.h>
   45: #include <signal.h>
   46: #include <ctype.h>
   47: #include <errno.h>
   48: #include <sys/types.h>
   49: #include <sys/socket.h>
   50: #include <netinet/in.h>
   51: #include <netinet/tcp.h>
   52: #include <arpa/inet.h>
   53: #include <netdb.h>
   54: #include <sys/time.h>		/* struct timeval */
   55: #include <unistd.h>
   56: #include <string.h>
   57: #include <stdlib.h>
   58: 
   59: #if defined(SYSV)
   60: #include <sys/times.h>
   61: #include <sys/param.h>
   62: struct rusage {
   63:     struct timeval ru_utime, ru_stime;
   64: };
   65: #define RUSAGE_SELF 0
   66: #else
   67: #include <sys/resource.h>
   68: #endif
   69: 
   70: struct sockaddr_in sinme;
   71: struct sockaddr_in sinhim;
   72: struct sockaddr_in frominet;
   73: 
   74: int domain, fromlen;
   75: int fd;				/* fd of network socket */
   76: 
   77: int buflen = 8 * 1024;		/* length of buffer */
   78: char *buf;			/* ptr to dynamic buffer */
   79: int nbuf = 2 * 1024;		/* number of buffers to send in sinkmode */
   80: 
   81: int bufoffset = 0;		/* align buffer to this */
   82: int bufalign = 16*1024;		/* modulo this */
   83: 
   84: int udp = 0;			/* 0 = tcp, !0 = udp */
   85: int options = 0;		/* socket options */
   86: int one = 1;                    /* for 4.3 BSD style setsockopt() */
   87: short port = 5001;		/* TCP port number */
   88: char *host;			/* ptr to name of host */
   89: int trans;			/* 0=receive, !0=transmit mode */
   90: int sinkmode = 0;		/* 0=normal I/O, !0=sink/source mode */
   91: int verbose = 0;		/* 0=print basic info, 1=print cpu rate, proc
   92: 				 * resource usage. */
   93: int nodelay = 0;		/* set TCP_NODELAY socket option */
   94: int b_flag = 0;			/* use mread() */
   95: int sockbufsize = 0;		/* socket buffer size to use */
   96: char fmt = 'K';			/* output format: k = kilobits, K = kilobytes,
   97: 				 *  m = megabits, M = megabytes, 
   98: 				 *  g = gigabits, G = gigabytes */
   99: int touchdata = 0;		/* access data after reading */
  100: 
  101: struct hostent *addr;
  102: extern int errno;
  103: extern int optind;
  104: extern char *optarg;
  105: 
  106: char Usage[] = "\
  107: Usage: ttcp -t [-options] host [ < in ]\n\
  108:        ttcp -r [-options > out]\n\
  109: Common options:\n\
  110: 	-l ##	length of bufs read from or written to network (default 8192)\n\
  111: 	-u	use UDP instead of TCP\n\
  112: 	-p ##	port number to send to or listen at (default 5001)\n\
  113: 	-s	-t: source a pattern to network\n\
  114: 		-r: sink (discard) all data from network\n\
  115: 	-A	align the start of buffers to this modulus (default 16384)\n\
  116: 	-O	start buffers at this offset from the modulus (default 0)\n\
  117: 	-v	verbose: print more statistics\n\
  118: 	-d	set SO_DEBUG socket option\n\
  119: 	-b ##	set socket buffer size (if supported)\n\
  120: 	-f X	format for rate: k,K = kilo{bit,byte}; m,M = mega; g,G = giga\n\
  121: Options specific to -t:\n\
  122: 	-n##	number of source bufs written to network (default 2048)\n\
  123: 	-D	don't buffer TCP writes (sets TCP_NODELAY socket option)\n\
  124: Options specific to -r:\n\
  125: 	-B	for -s, only output full blocks as specified by -l (for TAR)\n\
  126: 	-T	\"touch\": access each byte as it's read\n\
  127: ";	
  128: 
  129: char stats[128];
  130: double nbytes;			/* bytes on net */
  131: unsigned long numCalls;		/* # of I/O system calls */
  132: double cput, realt;		/* user, real time (seconds) */
  133: 
  134: void err();
  135: void mes();
  136: void pattern();
  137: void prep_timer();
  138: double read_timer();
  139: int Nread();
  140: int Nwrite();
  141: void delay();
  142: int mread();
  143: char *outfmt();
  144: 
  145: void
  146: sigpipe()
  147: {
  148: }
  149: 
  150: int
  151: main(argc,argv)
  152: int argc;
  153: char **argv;
  154: {
  155: 	unsigned long addr_tmp;
  156: 	int c;
  157: 
  158: 	if (argc < 2) goto usage;
  159: 
  160: 	while ((c = getopt(argc, argv, "drstuvBDTb:f:l:n:p:A:O:")) != -1) {
  161: 		switch (c) {
  162: 
  163: 		case 'B':
  164: 			b_flag = 1;
  165: 			break;
  166: 		case 't':
  167: 			trans = 1;
  168: 			break;
  169: 		case 'r':
  170: 			trans = 0;
  171: 			break;
  172: 		case 'd':
  173: 			options |= SO_DEBUG;
  174: 			break;
  175: 		case 'D':
  176: #ifdef TCP_NODELAY
  177: 			nodelay = 1;
  178: #else
  179: 			fprintf(stderr, 
  180: 	"ttcp: -D option ignored: TCP_NODELAY socket option not supported\n");
  181: #endif
  182: 			break;
  183: 		case 'n':
  184: 			nbuf = atoi(optarg);
  185: 			break;
  186: 		case 'l':
  187: 			buflen = atoi(optarg);
  188: 			break;
  189: 		case 's':
  190: 			sinkmode = !sinkmode;
  191: 			break;
  192: 		case 'p':
  193: 			port = atoi(optarg);
  194: 			break;
  195: 		case 'u':
  196: 			udp = 1;
  197: 			break;
  198: 		case 'v':
  199: 			verbose = 1;
  200: 			break;
  201: 		case 'A':
  202: 			bufalign = atoi(optarg);
  203: 			break;
  204: 		case 'O':
  205: 			bufoffset = atoi(optarg);
  206: 			break;
  207: 		case 'b':
  208: #if defined(SO_SNDBUF) || defined(SO_RCVBUF)
  209: 			sockbufsize = atoi(optarg);
  210: #else
  211: 			fprintf(stderr, 
  212: "ttcp: -b option ignored: SO_SNDBUF/SO_RCVBUF socket options not supported\n");
  213: #endif
  214: 			break;
  215: 		case 'f':
  216: 			fmt = *optarg;
  217: 			break;
  218: 		case 'T':
  219: 			touchdata = 1;
  220: 			break;
  221: 
  222: 		default:
  223: 			goto usage;
  224: 		}
  225: 	}
  226: 	if(trans)  {
  227: 		/* xmitr */
  228: 		if (optind == argc)
  229: 			goto usage;
  230: 		bzero((char *)&sinhim, sizeof(sinhim));
  231: 		host = argv[optind];
  232: 		if (atoi(host) > 0 )  {
  233: 			/* Numeric */
  234: 			sinhim.sin_family = AF_INET;
  235: #if defined(cray)
  236: 			addr_tmp = inet_addr(host);
  237: 			sinhim.sin_addr = addr_tmp;
  238: #else
  239: 			sinhim.sin_addr.s_addr = inet_addr(host);
  240: #endif
  241: 		} else {
  242: 			if ((addr=gethostbyname(host)) == NULL)
  243: 				err("bad hostname");
  244: 			sinhim.sin_family = addr->h_addrtype;
  245: 			bcopy(addr->h_addr,(char*)&addr_tmp, addr->h_length);
  246: #if defined(cray)
  247: 			sinhim.sin_addr = addr_tmp;
  248: #else
  249: 			sinhim.sin_addr.s_addr = addr_tmp;
  250: #endif /* cray */
  251: 		}
  252: 		sinhim.sin_port = htons(port);
  253: 		sinme.sin_family = AF_INET;     /* Solaris needs this */
  254: 		sinme.sin_port = 0;		/* free choice */
  255: 	} else {
  256: 		/* rcvr */
  257: 		sinme.sin_port =  htons(port);
  258: 	}
  259: 
  260: 
  261: 	if (udp && buflen < 5) {
  262: 	    buflen = 5;		/* send more than the sentinel size */
  263: 	}
  264: 
  265: 	if ( (buf = (char *)malloc(buflen+bufalign)) == (char *)NULL)
  266: 		err("malloc");
  267: 	if (bufalign != 0)
  268: 		buf += (bufalign
  269: 			-((unsigned long)buf % bufalign)
  270: 			+ bufoffset) % bufalign;
  271: 
  272: 	if (trans) {
  273: 	    fprintf(stderr,
  274: 	    "ttcp-t: buflen=%d, nbuf=%d, align=%d/%d, port=%d",
  275: 		buflen, nbuf, bufalign, bufoffset, port);
  276:  	    if (sockbufsize)
  277:  		fprintf(stderr, ", sockbufsize=%d", sockbufsize);
  278:  	    fprintf(stderr, "  %s  -> %s\n", udp?"udp":"tcp", host);
  279: 	} else {
  280: 	    fprintf(stderr,
  281:  	    "ttcp-r: buflen=%d, nbuf=%d, align=%d/%d, port=%d",
  282:  		buflen, nbuf, bufalign, bufoffset, port);
  283:  	    if (sockbufsize)
  284:  		fprintf(stderr, ", sockbufsize=%d", sockbufsize);
  285:  	    fprintf(stderr, "  %s\n", udp?"udp":"tcp");
  286: 	}
  287: 
  288: 	if ((fd = socket(AF_INET, udp?SOCK_DGRAM:SOCK_STREAM, 0)) < 0)
  289: 		err("socket");
  290: 	mes("socket");
  291: 
  292: 	if (bind(fd, (struct sockaddr *) &sinme, sizeof(sinme)) < 0)
  293: 		err("bind");
  294: 
  295: #if defined(SO_SNDBUF) || defined(SO_RCVBUF)
  296: 	if (sockbufsize) {
  297: 	    if (trans) {
  298: 		if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sockbufsize,
  299: 		    sizeof sockbufsize) < 0)
  300: 			err("setsockopt: sndbuf");
  301: 		mes("sndbuf");
  302: 	    } else {
  303: 		if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &sockbufsize,
  304: 		    sizeof sockbufsize) < 0)
  305: 			err("setsockopt: rcvbuf");
  306: 		mes("rcvbuf");
  307: 	    }
  308: 	}
  309: #endif
  310: 
  311: 	if (!udp)  {
  312: 	    signal(SIGPIPE, sigpipe);
  313: 	    if (trans) {
  314: 		/* We are the client if transmitting */
  315: 		if (options)  {
  316: #if defined(BSD42)
  317: 			if( setsockopt(fd, SOL_SOCKET, options, 0, 0) < 0)
  318: #else /* BSD43 */
  319: 			if( setsockopt(fd, SOL_SOCKET, options, &one, sizeof(one)) < 0)
  320: #endif
  321: 				err("setsockopt");
  322: 		}
  323: #ifdef TCP_NODELAY
  324: 		if (nodelay) {
  325: 			struct protoent *p;
  326: 			p = getprotobyname("tcp");
  327: 			if( p && setsockopt(fd, p->p_proto, TCP_NODELAY, 
  328: 			    &one, sizeof(one)) < 0)
  329: 				err("setsockopt: nodelay");
  330: 			mes("nodelay");
  331: 		}
  332: #endif
  333: 		if(connect(fd, (struct sockaddr*)&sinhim, sizeof(sinhim) ) < 0)
  334: 			err("connect");
  335: 		mes("connect");
  336: 	    } else {
  337: 		/* otherwise, we are the server and 
  338: 	         * should listen for the connections
  339: 	         */
  340: #if defined(ultrix) || defined(sgi)
  341: 		listen(fd,1);   /* workaround for alleged u4.2 bug */
  342: #else
  343: 		listen(fd,0);   /* allow a queue of 0 */
  344: #endif
  345: 		if(options)  {
  346: #if defined(BSD42)
  347: 			if( setsockopt(fd, SOL_SOCKET, options, 0, 0) < 0)
  348: #else /* BSD43 */
  349: 			if( setsockopt(fd, SOL_SOCKET, options, &one, sizeof(one)) < 0)
  350: #endif
  351: 				err("setsockopt");
  352: 		}
  353: 		fromlen = sizeof(frominet);
  354: 		domain = AF_INET;
  355: 		if((fd=accept(fd, (struct sockaddr*)&frominet, (socklen_t*)&fromlen) ) < 0)
  356: 			err("accept");
  357: 		{ struct sockaddr_in peer;
  358: 		  int peerlen = sizeof(peer);
  359: 		  if (getpeername(fd, (struct sockaddr*) &peer, (socklen_t*)&peerlen) < 0) {
  360: 			err("getpeername");
  361: 		  }
  362: 		  fprintf(stderr,"ttcp-r: accept from %s\n", 
  363: 			inet_ntoa(peer.sin_addr));
  364: 		}
  365: 	    }
  366: 	}
  367: 	prep_timer();
  368: 	errno = 0;
  369: 	if (sinkmode) {      
  370: 		register int cnt;
  371: 		if (trans)  {
  372: 			pattern( buf, buflen );
  373: 			if(udp)  (void)Nwrite( fd, buf, 4 ); /* rcvr start */
  374: 			while (nbuf-- && Nwrite(fd,buf,buflen) == buflen)
  375: 				nbytes += buflen;
  376: 			if(udp)  (void)Nwrite( fd, buf, 4 ); /* rcvr end */
  377: 		} else {
  378: 			if (udp) {
  379: 			    while ((cnt=Nread(fd,buf,buflen)) > 0)  {
  380: 				    static int going = 0;
  381: 				    if( cnt <= 4 )  {
  382: 					    if( going )
  383: 						    break;	/* "EOF" */
  384: 					    going = 1;
  385: 					    prep_timer();
  386: 				    } else {
  387: 					    nbytes += cnt;
  388: 				    }
  389: 			    }
  390: 			} else {
  391: 			    while ((cnt=Nread(fd,buf,buflen)) > 0)  {
  392: 				    nbytes += cnt;
  393: 			    }
  394: 			}
  395: 		}
  396: 	} else {
  397: 		register int cnt;
  398: 		if (trans)  {
  399: 			while((cnt=read(0,buf,buflen)) > 0 &&
  400: 			    Nwrite(fd,buf,cnt) == cnt)
  401: 				nbytes += cnt;
  402: 		}  else  {
  403: 			while((cnt=Nread(fd,buf,buflen)) > 0 &&
  404: 			    write(1,buf,cnt) == cnt)
  405: 				nbytes += cnt;
  406: 		}
  407: 	}
  408: 	if(errno) err("IO");
  409: 	(void)read_timer(stats,sizeof(stats));
  410: 	if(udp&&trans)  {
  411: 		(void)Nwrite( fd, buf, 4 ); /* rcvr end */
  412: 		(void)Nwrite( fd, buf, 4 ); /* rcvr end */
  413: 		(void)Nwrite( fd, buf, 4 ); /* rcvr end */
  414: 		(void)Nwrite( fd, buf, 4 ); /* rcvr end */
  415: 	}
  416: 	if( cput <= 0.0 )  cput = 0.001;
  417: 	if( realt <= 0.0 )  realt = 0.001;
  418: 	fprintf(stderr,
  419: 		"ttcp%s: %.0f bytes in %.2f real seconds = %s/sec +++\n",
  420: 		trans?"-t":"-r",
  421: 		nbytes, realt, outfmt(nbytes/realt));
  422: 	if (verbose) {
  423: 	    fprintf(stderr,
  424: 		"ttcp%s: %.0f bytes in %.2f CPU seconds = %s/cpu sec\n",
  425: 		trans?"-t":"-r",
  426: 		nbytes, cput, outfmt(nbytes/cput));
  427: 	}
  428: 	fprintf(stderr,
  429: 		"ttcp%s: %lu I/O calls, msec/call = %.2f, calls/sec = %.2f\n",
  430: 		trans?"-t":"-r",
  431: 		numCalls,
  432: 		1024.0 * realt/((double)numCalls),
  433: 		((double)numCalls)/realt);
  434: 	fprintf(stderr,"ttcp%s: %s\n", trans?"-t":"-r", stats);
  435: 	if (verbose) {
  436: 	    fprintf(stderr,
  437: 		"ttcp%s: buffer address %#x\n",
  438: 		trans?"-t":"-r",
  439: 		(unsigned int)buf);
  440: 	}
  441: 	exit(0);
  442: 
  443: usage:
  444: 	fprintf(stderr,"%s", Usage);
  445: 	exit(1);
  446: }
  447: 
  448: void
  449: err(s)
  450: char *s;
  451: {
  452: 	fprintf(stderr,"ttcp%s: ", trans?"-t":"-r");
  453: 	perror(s);
  454: 	fprintf(stderr,"errno=%d\n",errno);
  455: 	exit(1);
  456: }
  457: 
  458: void
  459: mes(s)
  460: char *s;
  461: {
  462: 	fprintf(stderr,"ttcp%s: %s\n", trans?"-t":"-r", s);
  463: }
  464: 
  465: void
  466: pattern( cp, cnt )
  467: register char *cp;
  468: register int cnt;
  469: {
  470: 	register char c;
  471: 	c = 0;
  472: 	while( cnt-- > 0 )  {
  473: 		while( !isprint((c&0x7F)) )  c++;
  474: 		*cp++ = (c++&0x7F);
  475: 	}
  476: }
  477: 
  478: char *
  479: outfmt(b)
  480: double b;
  481: {
  482:     static char obuf[50];
  483:     switch (fmt) {
  484: 	case 'G':
  485: 	    sprintf(obuf, "%.2f GB", b / 1024.0 / 1024.0 / 1024.0);
  486: 	    break;
  487: 	default:
  488: 	case 'K':
  489: 	    sprintf(obuf, "%.2f KB", b / 1024.0);
  490: 	    break;
  491: 	case 'M':
  492: 	    sprintf(obuf, "%.2f MB", b / 1024.0 / 1024.0);
  493: 	    break;
  494: 	case 'g':
  495: 	    sprintf(obuf, "%.2f Gbit", b * 8.0 / 1024.0 / 1024.0 / 1024.0);
  496: 	    break;
  497: 	case 'k':
  498: 	    sprintf(obuf, "%.2f Kbit", b * 8.0 / 1024.0);
  499: 	    break;
  500: 	case 'm':
  501: 	    sprintf(obuf, "%.2f Mbit", b * 8.0 / 1024.0 / 1024.0);
  502: 	    break;
  503:     }
  504:     return obuf;
  505: }
  506: 
  507: static struct	timeval time0;	/* Time at which timing started */
  508: static struct	rusage ru0;	/* Resource utilization at the start */
  509: 
  510: static void prusage();
  511: static void tvadd();
  512: static void tvsub();
  513: static void psecs();
  514: 
  515: #if defined(SYSV)
  516: /*ARGSUSED*/
  517: static
  518: getrusage(ignored, ru)
  519:     int ignored;
  520:     register struct rusage *ru;
  521: {
  522:     struct tms buf;
  523: 
  524:     times(&buf);
  525: 
  526:     /* Assumption: HZ <= 2147 (LONG_MAX/1000000) */
  527:     ru->ru_stime.tv_sec  = buf.tms_stime / HZ;
  528:     ru->ru_stime.tv_usec = ((buf.tms_stime % HZ) * 1000000) / HZ;
  529:     ru->ru_utime.tv_sec  = buf.tms_utime / HZ;
  530:     ru->ru_utime.tv_usec = ((buf.tms_utime % HZ) * 1000000) / HZ;
  531: }
  532: 
  533: /*ARGSUSED*/
  534: static 
  535: gettimeofday(tp, zp)
  536:     struct timeval *tp;
  537:     struct timezone *zp;
  538: {
  539:     tp->tv_sec = time(0);
  540:     tp->tv_usec = 0;
  541: }
  542: #endif /* SYSV */
  543: 
  544: /*
  545:  *			P R E P _ T I M E R
  546:  */
  547: void
  548: prep_timer()
  549: {
  550: 	gettimeofday(&time0, (struct timezone *)0);
  551: 	getrusage(RUSAGE_SELF, &ru0);
  552: }
  553: 
  554: /*
  555:  *			R E A D _ T I M E R
  556:  * 
  557:  */
  558: double
  559: read_timer(str,len)
  560: char *str;
  561: {
  562: 	struct timeval timedol;
  563: 	struct rusage ru1;
  564: 	struct timeval td;
  565: 	struct timeval tend, tstart;
  566: 	char line[132];
  567: 
  568: 	getrusage(RUSAGE_SELF, &ru1);
  569: 	gettimeofday(&timedol, (struct timezone *)0);
  570: 	prusage(&ru0, &ru1, &timedol, &time0, line);
  571: 	(void)strncpy( str, line, len );
  572: 
  573: 	/* Get real time */
  574: 	tvsub( &td, &timedol, &time0 );
  575: 	realt = td.tv_sec + ((double)td.tv_usec) / 1000000;
  576: 
  577: 	/* Get CPU time (user+sys) */
  578: 	tvadd( &tend, &ru1.ru_utime, &ru1.ru_stime );
  579: 	tvadd( &tstart, &ru0.ru_utime, &ru0.ru_stime );
  580: 	tvsub( &td, &tend, &tstart );
  581: 	cput = td.tv_sec + ((double)td.tv_usec) / 1000000;
  582: 	if( cput < 0.00001 )  cput = 0.00001;
  583: 	return( cput );
  584: }
  585: 
  586: static void
  587: prusage(r0, r1, e, b, outp)
  588: 	register struct rusage *r0, *r1;
  589: 	struct timeval *e, *b;
  590: 	char *outp;
  591: {
  592: 	struct timeval tdiff;
  593: 	register time_t t;
  594: 	register char *cp;
  595: 	register int i;
  596: 	int ms;
  597: 
  598: 	t = (r1->ru_utime.tv_sec-r0->ru_utime.tv_sec)*100+
  599: 	    (r1->ru_utime.tv_usec-r0->ru_utime.tv_usec)/10000+
  600: 	    (r1->ru_stime.tv_sec-r0->ru_stime.tv_sec)*100+
  601: 	    (r1->ru_stime.tv_usec-r0->ru_stime.tv_usec)/10000;
  602: 	ms =  (e->tv_sec-b->tv_sec)*100 + (e->tv_usec-b->tv_usec)/10000;
  603: 
  604: #define END(x)	{while(*x) x++;}
  605: #if defined(SYSV)
  606: 	cp = "%Uuser %Ssys %Ereal %P";
  607: #else
  608: #if defined(sgi)		/* IRIX 3.3 will show 0 for %M,%F,%R,%C */
  609: 	cp = "%Uuser %Ssys %Ereal %P %Mmaxrss %F+%Rpf %Ccsw";
  610: #else
  611: 	cp = "%Uuser %Ssys %Ereal %P %Xi+%Dd %Mmaxrss %F+%Rpf %Ccsw";
  612: #endif
  613: #endif
  614: 	for (; *cp; cp++)  {
  615: 		if (*cp != '%')
  616: 			*outp++ = *cp;
  617: 		else if (cp[1]) switch(*++cp) {
  618: 
  619: 		case 'U':
  620: 			tvsub(&tdiff, &r1->ru_utime, &r0->ru_utime);
  621: 			sprintf(outp,"%d.%01ld", tdiff.tv_sec, tdiff.tv_usec/100000);
  622: 			END(outp);
  623: 			break;
  624: 
  625: 		case 'S':
  626: 			tvsub(&tdiff, &r1->ru_stime, &r0->ru_stime);
  627: 			sprintf(outp,"%d.%01ld", tdiff.tv_sec, tdiff.tv_usec/100000);
  628: 			END(outp);
  629: 			break;
  630: 
  631: 		case 'E':
  632: 			psecs(ms / 100, outp);
  633: 			END(outp);
  634: 			break;
  635: 
  636: 		case 'P':
  637: 			sprintf(outp,"%d%%", (int) (t*100 / ((ms ? ms : 1))));
  638: 			END(outp);
  639: 			break;
  640: 
  641: #if !defined(SYSV)
  642: 		case 'W':
  643: 			i = r1->ru_nswap - r0->ru_nswap;
  644: 			sprintf(outp,"%d", i);
  645: 			END(outp);
  646: 			break;
  647: 
  648: 		case 'X':
  649: 			sprintf(outp,"%ld", t == 0 ? 0 : (r1->ru_ixrss-r0->ru_ixrss)/t);
  650: 			END(outp);
  651: 			break;
  652: 
  653: 		case 'D':
  654: 			sprintf(outp,"%ld", t == 0 ? 0 :
  655: 			    (r1->ru_idrss+r1->ru_isrss-(r0->ru_idrss+r0->ru_isrss))/t);
  656: 			END(outp);
  657: 			break;
  658: 
  659: 		case 'K':
  660: 			sprintf(outp,"%ld", t == 0 ? 0 :
  661: 			    ((r1->ru_ixrss+r1->ru_isrss+r1->ru_idrss) -
  662: 			    (r0->ru_ixrss+r0->ru_idrss+r0->ru_isrss))/t);
  663: 			END(outp);
  664: 			break;
  665: 
  666: 		case 'M':
  667: 			sprintf(outp,"%ld", r1->ru_maxrss/2);
  668: 			END(outp);
  669: 			break;
  670: 
  671: 		case 'F':
  672: 			sprintf(outp,"%ld", r1->ru_majflt-r0->ru_majflt);
  673: 			END(outp);
  674: 			break;
  675: 
  676: 		case 'R':
  677: 			sprintf(outp,"%ld", r1->ru_minflt-r0->ru_minflt);
  678: 			END(outp);
  679: 			break;
  680: 
  681: 		case 'I':
  682: 			sprintf(outp,"%ld", r1->ru_inblock-r0->ru_inblock);
  683: 			END(outp);
  684: 			break;
  685: 
  686: 		case 'O':
  687: 			sprintf(outp,"%ld", r1->ru_oublock-r0->ru_oublock);
  688: 			END(outp);
  689: 			break;
  690: 		case 'C':
  691: 			sprintf(outp,"%ld+%ld", r1->ru_nvcsw-r0->ru_nvcsw,
  692: 				r1->ru_nivcsw-r0->ru_nivcsw );
  693: 			END(outp);
  694: 			break;
  695: #endif /* !SYSV */
  696: 		}
  697: 	}
  698: 	*outp = '\0';
  699: }
  700: 
  701: static void
  702: tvadd(tsum, t0, t1)
  703: 	struct timeval *tsum, *t0, *t1;
  704: {
  705: 
  706: 	tsum->tv_sec = t0->tv_sec + t1->tv_sec;
  707: 	tsum->tv_usec = t0->tv_usec + t1->tv_usec;
  708: 	if (tsum->tv_usec > 1000000)
  709: 		tsum->tv_sec++, tsum->tv_usec -= 1000000;
  710: }
  711: 
  712: static void
  713: tvsub(tdiff, t1, t0)
  714: 	struct timeval *tdiff, *t1, *t0;
  715: {
  716: 
  717: 	tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
  718: 	tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
  719: 	if (tdiff->tv_usec < 0)
  720: 		tdiff->tv_sec--, tdiff->tv_usec += 1000000;
  721: }
  722: 
  723: static void
  724: psecs(l,cp)
  725: long l;
  726: register char *cp;
  727: {
  728: 	register int i;
  729: 
  730: 	i = l / 3600;
  731: 	if (i) {
  732: 		sprintf(cp,"%d:", i);
  733: 		END(cp);
  734: 		i = l % 3600;
  735: 		sprintf(cp,"%d%d", (i/60) / 10, (i/60) % 10);
  736: 		END(cp);
  737: 	} else {
  738: 		i = l;
  739: 		sprintf(cp,"%d", i / 60);
  740: 		END(cp);
  741: 	}
  742: 	i %= 60;
  743: 	*cp++ = ':';
  744: 	sprintf(cp,"%d%d", i / 10, i % 10);
  745: }
  746: 
  747: /*
  748:  *			N R E A D
  749:  */
  750: int
  751: Nread( fd, buf, count )
  752: int fd;
  753: void *buf;
  754: int count;
  755: {
  756: 	struct sockaddr_in from;
  757: 	int len = sizeof(from);
  758: 	register int cnt;
  759: 	if( udp )  {
  760: 		cnt = recvfrom( fd, buf, count, 0, (struct sockaddr *)&from, (socklen_t*)&len );
  761: 		numCalls++;
  762: 	} else {
  763: 		if( b_flag )
  764: 			cnt = mread( fd, buf, count );	/* fill buf */
  765: 		else {
  766: 			cnt = read( fd, buf, count );
  767: 			numCalls++;
  768: 		}
  769: 		if (touchdata && cnt > 0) {
  770: 			register int c = cnt, sum;
  771: 			register char *b = buf;
  772: 			while (c--)
  773: 				sum += *b++;
  774: 		}
  775: 	}
  776: 	return(cnt);
  777: }
  778: 
  779: /*
  780:  *			N W R I T E
  781:  */
  782: int
  783: Nwrite( fd, buf, count )
  784: int fd;
  785: void *buf;
  786: int count;
  787: {
  788: 	register int cnt;
  789: 	if( udp )  {
  790: again:
  791: 		cnt = sendto( fd, buf, count, 0, (struct sockaddr *)&sinhim, sizeof(sinhim) );
  792: 		numCalls++;
  793: 		if( cnt<0 && errno == ENOBUFS )  {
  794: 			delay(18000);
  795: 			errno = 0;
  796: 			goto again;
  797: 		}
  798: 	} else {
  799: 		cnt = write( fd, buf, count );
  800: 		numCalls++;
  801: 	}
  802: 	return(cnt);
  803: }
  804: 
  805: void
  806: delay(us)
  807: {
  808: 	struct timeval tv;
  809: 
  810: 	tv.tv_sec = 0;
  811: 	tv.tv_usec = us;
  812: 	(void)select( 1, NULL, NULL, NULL, &tv );
  813: }
  814: 
  815: /*
  816:  *			M R E A D
  817:  *
  818:  * This function performs the function of a read(II) but will
  819:  * call read(II) multiple times in order to get the requested
  820:  * number of characters.  This can be necessary because
  821:  * network connections don't deliver data with the same
  822:  * grouping as it is written with.  Written by Robert S. Miles, BRL.
  823:  */
  824: int
  825: mread(fd, bufp, n)
  826: int fd;
  827: register char	*bufp;
  828: unsigned	n;
  829: {
  830: 	register unsigned	count = 0;
  831: 	register int		nread;
  832: 
  833: 	do {
  834: 		nread = read(fd, bufp, n-count);
  835: 		numCalls++;
  836: 		if(nread < 0)  {
  837: 			perror("ttcp_mread");
  838: 			return(-1);
  839: 		}
  840: 		if(nread == 0)
  841: 			return((int)count);
  842: 		count += (unsigned)nread;
  843: 		bufp += nread;
  844: 	 } while(count < n);
  845: 
  846: 	return((int)count);
  847: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>