home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 8 Other / 08-Other.zip / ttcpos2.zip / ttcp.c next >
C/C++ Source or Header  |  1998-06-19  |  21KB  |  891 lines

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