Annotation of embedaddon/ttcp/ttcp.c, revision 1.1.1.1
1.1 misho 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>