source: network-demos/ttcp/ttcp_orig/ttcp.c @ c87143a

4.11ERIC-NORUMnetdemos-4-5-branchnetwork-demos-4-10-branchnetwork-demos-4-6-branchnetwork-demos-4-7-branchnetwork-demos-4-8-branchnetwork-demos-4-9-branchrtems-4-5-branch Demos-30May1998
Last change on this file since c87143a was c87143a, checked in by Joel Sherrill <joel.sherrill@…>, on Jul 30, 1998 at 2:42:29 PM

base from Eric Norum -- Demos.30May1998.tar.gz

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