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