4 * Test TCP connection. Makes a connection on port 5001
5 * and transfers fabricated buffers or data copied from stdin.
7 * Usable on 4.2, 4.3, and 4.1a systems by defining one of
9 * Machines using System V with BSD sockets should define SYSV.
11 * Modified for operation under 4.2BSD, 18 Dec 84
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 * Modified Aug.1993 at University Paderborn, Germany
35 * some SVR4 changes and time functions changed to itimer() calls
36 * Modified by Douglas C. Schmidt September 28, 1994
37 * added support for testing UNIX domain socket performance
38 * Modified by Tim Harrison May, 1995
39 * added support for ACE wrappers
40 * Distribution Status -
41 * Public Domain. Distribution Unlimited.
47 // #define SYSV /* required on SGI IRIX releases before 3.3 */
49 #include "ace/Log_Msg.h"
50 #include "ace/SOCK_Connector.h"
51 #include "ace/SOCK_Acceptor.h"
57 #include <sys/types.h>
58 #include <sys/socket.h>
59 #include <netinet/in.h>
64 #include <netinet/tcp.h>
65 #include <arpa/inet.h>
67 #include <sys/time.h> /* struct itimerval */
72 ACE_SOCK_Connector connector_factory
;
73 ACE_SOCK_Acceptor acceptor_factory
;
74 ACE_INET_Addr address
;
77 #define bcopy(b1,b2,n) memcpy(b2,b1,n)
78 #define bzero(b1,n) memset(b1,0,n)
79 #include <sys/times.h>
80 #include <sys/param.h>
84 struct timeval ru_utime
, ru_stime
;
89 #include <sys/resource.h>
92 struct sockaddr_in sinme
;
93 struct sockaddr_un sunme
;
94 struct sockaddr_in sinhim
;
95 struct sockaddr_un sunhim
;
96 struct sockaddr_in frominet
;
97 struct sockaddr_un fromunix
;
99 struct Session_Control_Message
102 // number of buffers that will be sent this round.
104 // size of the buffers that will be sent
105 } session_control_buf
;
107 struct Data_Control_Message
114 int domain
= PF_INET
; /* Default is to use Internet domain sockets. */
115 char *domainname
; /* Rendezvous address for UNIX domain sockets. */
116 int fd
; /* fd of network socket */
118 int data_buf_len
= 1024 * 1024 * 2; // length of data portion
119 long total_msg_len
; // length of entire message
120 char *data_buf
; // pointer to data portion
121 int nbuf
= 2 * 1024; /* number of buffers to send in sinkmode */
123 int bufoffset
= 0; /* align buffer to this */
124 int bufalign
= 16 * 1024; /* modulo this */
126 int udp
= 0; /* 0 = tcp, !0 = udp */
127 int options
= 0; /* socket options */
128 int one
= 1; /* for 4.3 BSD style setsockopt() */
129 short port
= 5001; /* TCP port number */
130 char *host
; /* ptr to name of host */
131 int trans
; /* 0=receive, !0=transmit mode */
132 int sinkmode
= 0; /* 0=normal I/O, !0=sink/source mode */
133 int verbose
= 0; /* 0=print basic info, 1=print cpu rate, proc
135 int nodelay
= 0; /* set TCP_NODELAY socket option */
136 int b_flag
= 0; /* use mread() */
137 int sockbufsize
= 0; /* socket buffer size to use */
138 char fmt
= 'K'; /* output format: k = kilobits, K = kilobytes,
139 * m = megabits, M = megabytes,
140 * g = gigabits, G = gigabytes */
141 int touchdata
= 0; /* access data after reading */
143 struct hostent
*addr
;
149 Usage: ttcp -t [-options] host [ < in ]\n\
150 ttcp -r [-options > out]\n\
152 -l ## length of bufs read from or written to network (default 8192)\n\
153 -u use UDP instead of TCP\n\
154 -U use UNIX domain sockets instead of Internet domain sockets\n\
155 -p ## port number to send to or listen at (default 5001)\n\
156 -s -t: source a pattern to network\n\
157 -r: sink (discard) all data from network\n\
158 -A align the start of buffers to this modulus (default 16384)\n\
159 -O start buffers at this offset from the modulus (default 0)\n\
160 -v verbose: print more statistics\n\
161 -d set SO_DEBUG socket option\n\
162 -b ## set socket buffer size (if supported)\n\
163 -f X format for rate: k,K = kilo{bit,byte}; m,M = mega; g,G = giga\n\
164 Options specific to -t:\n\
165 -n## number of source bufs written to network (default 2048)\n\
166 -D don't buffer TCP writes (sets TCP_NODELAY socket option)\n\
167 Options specific to -r:\n\
168 -B for -s, only output full blocks as specified by -l (for TAR)\n\
169 -T \"touch\": access each byte as it's read\n\
173 unsigned long nbytes
; /* bytes on net */
174 unsigned long numCalls
= 0; /* # of I/O system calls */
175 double cput
, realt
; /* user, real time (seconds) */
179 void pattern (register char *cp
, register int cnt
);
180 char *outfmt (double b
);
182 double read_timer (char *str
, int len
);
183 static void prusage (register struct rusage
*r0
, struct rusage
*r1
, struct timeval
*e
, struct timeval
*b
, char *outp
);
184 static void tvadd (struct timeval
*tsum
, struct timeval
*t0
, struct timeval
*t1
);
185 static void tvsub (struct timeval
*tdiff
, struct timeval
*t1
, struct timeval
*t0
);
186 static void psecs (long l
, register char *cp
);
188 int mread (int fd
, register char *bufp
, unsigned n
);
189 int Nread (ACE_SOCK_Stream
&s
, void *buf
, int count
);
190 int Nwrite (ACE_SOCK_Stream
&s
, void *buf
, int count
);
192 #if !defined (__cplusplus)
193 typedef void (*SIG_TYP
)();
195 typedef void (*SIG_TYP
)(int);
208 void sigpipe(int foo
)
210 printf("Caught signal %d\n", foo
);
217 ACE_TMAIN(int argc
, ACE_TCHAR
*argv
[])
219 ACE_SOCK_Stream connection_stream
;
222 printf("HZ = %d\n", HZ
);
226 while ((c
= getopt (argc
, argv
, "drstU:uvBDTb:f:l:n:p:A:O:L:xh:")) != -1)
256 "ttcp: -D option ignored: TCP_NODELAY socket option not supported\n");
260 nbuf
= atoi (optarg
);
263 data_buf_len
= atoi (optarg
);
266 sinkmode
= !sinkmode
;
269 port
= atoi (optarg
);
282 bufalign
= atoi (optarg
);
285 bufoffset
= atoi (optarg
);
288 #if defined(SO_SNDBUF) || defined(SO_RCVBUF)
289 sockbufsize
= atoi (optarg
);
292 "ttcp: -b option ignored: SO_SNDBUF/SO_RCVBUF socket options not supported\n");
307 /* if transmitter, create remote address to transmit to. */
311 if (address
.set (port
, host
) == -1)
312 perror ("address.set"), exit (1);
315 /* else, receiver create address to listen on */
321 total_msg_len
= sizeof (long) + data_buf_len
;
323 // allocate the buffer
324 message_buf
= (Data_Control_Message
*) malloc (total_msg_len
);
325 if (message_buf
== 0)
328 // if (bufalign != 0)
329 // message_buf += (bufalign - ((int) message_buf % bufalign) + bufoffset) % bufalign;
331 // let's go ahead and set the control message for every send right now
332 message_buf
->size_
= data_buf_len
;
334 session_control_buf
.nbuf_
= nbuf
;
335 session_control_buf
.size_
= data_buf_len
;
338 // print out option values for trans and receiver
344 "ttcp-t: data_buf_len=%d, nbuf=%d, align=%d/%d, port=%d",
345 data_buf_len
, nbuf
, bufalign
, bufoffset
, port
);
347 fprintf (stdout
, ", sockbufsize=%d", sockbufsize
);
348 fprintf (stdout
, " %s -> %s\n",
349 domain
== PF_INET
? (udp
? "udp" : "tcp") : "unix",
350 host
== 0 ? domainname
: host
);
355 "ttcp-r: data_buf_len=%d, nbuf=%d, align=%d/%d, port=%d",
356 data_buf_len
, nbuf
, bufalign
, bufoffset
, port
);
358 fprintf (stdout
, ", sockbufsize=%d", sockbufsize
);
359 fprintf (stdout
, " %s\n", domain
== PF_INET
? (udp
? "udp" : "tcp") : "unix");
365 // connect and accept
370 signal (SIGPIPE
, (SIG_TYP
) sigpipe
);
372 /* the transmitter will set options and connect to receiver */
375 // turn off weird ack things
378 struct protoent
*p
= getprotobyname ("tcp");
380 if (p
&& connection_stream
.set_option (p
->p_proto
,
384 err ("setsockopt: nodelay");
387 if (connector_factory
.connect (connection_stream
, address
) == -1)
388 perror ("connection failed"), exit (1);
390 "ttcp-t: data_buf_len=%d, nbuf=%d, align=%d/%d, port=%d",
391 data_buf_len
, nbuf
, bufalign
, bufoffset
, port
);
395 if (connection_stream
.set_option (SOL_SOCKET
,
397 (char *) &sockbufsize
,
398 sizeof sockbufsize
) == -1)
399 err ("acceptor_factory.set_option");
404 /* receiver will listen for connections from the transmitter */
407 if (acceptor_factory
.open (address
, 1) == -1)
408 perror ("acceptor open"), exit (1);
412 if (connection_stream
.set_option (SOL_SOCKET
,
414 (char *) &sockbufsize
,
415 sizeof sockbufsize
) == -1)
416 err ("acceptor_factory.set_option");
420 ACE_INET_Addr remote_address
;
422 if (acceptor_factory
.accept (connection_stream
,
423 (ACE_Addr
*) &remote_address
) == -1)
424 perror ("acceptor accept"), exit (1);
426 // set the window size
429 "ttcp-r: accept from %s\n",
430 remote_address
.get_host_name());
441 pattern (& (message_buf
->data_
), data_buf_len
);
444 ACE_DEBUG ((LM_DEBUG
, "Sending session control message"
445 " nbuf %d, size %d\n", session_control_buf
.nbuf_
,
446 session_control_buf
.size_
));
447 if (connection_stream
.send_n ((char *) &session_control_buf
,
448 sizeof (Session_Control_Message
))
449 != sizeof (Session_Control_Message
))
450 ACE_ERROR_RETURN ((LM_ERROR
,
451 "%p send session control failed\n",
459 send_result
= connection_stream
.send_n ((char *) message_buf
,
461 if (send_result
!= total_msg_len
)
462 ACE_ERROR_RETURN ((LM_ERROR
,
463 "%p only sent %d of %d bytes on call %d\n",
464 "ttcp", send_result
, total_msg_len
, numCalls
+ 1),
467 nbytes
+= data_buf_len
;
469 if (connection_stream
.recv_n ((char *) &ack
, sizeof ack
) != sizeof ack
)
470 ACE_ERROR_RETURN ((LM_ERROR
, "%p recv of ack failed\n", "ttcp"), -1);
472 if (ack
!= data_buf_len
)
473 ACE_DEBUG ((LM_DEBUG
, "received ack for only %d bytes\n", ack
));
475 printf("Client finished.\n");
481 if (connection_stream
.recv_n ((char *) &session_control_buf
,
482 sizeof (Session_Control_Message
))
483 != sizeof (Session_Control_Message
))
484 ACE_ERROR_RETURN ((LM_ERROR
,
485 "%p recv session control failed\n",
489 ACE_DEBUG ((LM_DEBUG
, "received session control message"
490 " nbuf %d, size %d\n", session_control_buf
.nbuf_
,
491 session_control_buf
.size_
));
493 nbuf
= session_control_buf
.nbuf_
;
494 // ignore session_control_buf.size_ for now
500 if (connection_stream
.recv_n ((char *) message_buf
, sizeof (long))
502 ACE_ERROR_RETURN ((LM_ERROR
,
503 "%p recv data control failed\n",
507 cnt
= connection_stream
.recv_n (& (message_buf
->data_
), message_buf
->size_
);
508 if (cnt
!= message_buf
->size_
)
509 ACE_ERROR_RETURN ((LM_ERROR
, "recv data failed\n"), -1);
514 if (connection_stream
.send_n ((char *) &cnt
, sizeof cnt
)
516 ACE_ERROR_RETURN ((LM_ERROR
,
517 "%p send ack failed\n",
521 printf("Server finished.\n");
531 (void) read_timer (stats
, sizeof (stats
));
534 (void) Nwrite (connection_stream
, message_buf
, 4); /* rcvr end */
535 (void) Nwrite (connection_stream
, message_buf
, 4); /* rcvr end */
536 (void) Nwrite (connection_stream
, message_buf
, 4); /* rcvr end */
537 (void) Nwrite (connection_stream
, message_buf
, 4); /* rcvr end */
544 #if defined (LM_RESULTS)
545 if (trans
&& (title
!= 0))
549 char filename
[BUFSIZ
];
550 ACE_OS::sprintf (filename
, "%s.results", title
);
551 fd
= fopen(filename
,"a+");
553 fprintf(fd
,"\n -l %ldk \t", data_buf_len
/1024);
554 tmp
= ((double) nbytes
) / realt
;
555 fprintf(fd
,"%.2f ", tmp
* 8.0 / 1024.0 / 1024.0);
561 "ttcp%s: %ld bytes in %.2f real seconds = %s/sec +++\n",
563 nbytes
, realt
, outfmt (((double) nbytes
) / realt
));
567 "ttcp%s: %ld bytes in %.2f CPU seconds = %s/cpu sec\n",
569 nbytes
, cput
, outfmt (((double) nbytes
) / cput
));
572 "ttcp%s: %d I/O calls, msec/call = %.2f, calls/sec = %.2f\n",
575 1024.0 * realt
/ ((double) numCalls
),
576 ((double) numCalls
) / realt
);
577 fprintf (stdout
, "ttcp%s: %s\n", trans
? "-t" : "-r", stats
);
581 "ttcp%s: buffer address %#x\n",
588 fprintf (stderr
, Usage
);
595 fprintf (stderr
, "ttcp%s: ", trans
? "-t" : "-r");
597 fprintf (stderr
, "errno=%d\n", errno
);
604 fprintf (stderr
, "ttcp%s: %s\n", trans
? "-t" : "-r", s
);
608 pattern (register char *cp
, register int cnt
)
614 while (!isprint ((c
& 0x7F)))
616 *cp
++ = (c
++ & 0x7F);
623 static char obuf
[50];
627 sprintf (obuf
, "%.2f GB", b
/ 1024.0 / 1024.0 / 1024.0);
631 sprintf (obuf
, "%.2f KB", b
/ 1024.0);
634 sprintf (obuf
, "%.2f MB", b
/ 1024.0 / 1024.0);
637 sprintf (obuf
, "%.2f Gbit", b
* 8.0 / 1024.0 / 1024.0 / 1024.0);
640 sprintf (obuf
, "%.2f Kbit", b
* 8.0 / 1024.0);
643 sprintf (obuf
, "%.2f Mbit", b
* 8.0 / 1024.0 / 1024.0);
649 static struct itimerval itime0
; /* Time at which timing started */
650 static struct rusage ru0
; /* Resource utilization at the start */
655 getrusage (int ignored
, register struct rusage
*ru
)
661 /* Assumption: HZ <= 2147 (LONG_MAX/1000000) */
662 ru
->ru_stime
.tv_sec
= buf
.tms_stime
/ HZ
;
663 ru
->ru_stime
.tv_usec
= ((buf
.tms_stime
% HZ
) * 1000000) / HZ
;
664 ru
->ru_utime
.tv_sec
= buf
.tms_utime
/ HZ
;
665 ru
->ru_utime
.tv_usec
= ((buf
.tms_utime
% HZ
) * 1000000) / HZ
;
670 * P R E P _ T I M E R
675 itime0
.it_interval
.tv_sec
= 0;
676 itime0
.it_interval
.tv_usec
= 0;
677 // itime0.it_value.tv_sec = LONG_MAX / 22; /* greatest possible value , itimer() count backwards */
678 itime0
.it_value
.tv_sec
= 3600;
679 itime0
.it_value
.tv_usec
= 0;
682 getrusage (RUSAGE_SELF
, &ru0
);
683 fprintf(stdout
, "\n");
684 fprintf(stdout
, "beginning user time = %d sec and %d usec\n", ru0
.ru_utime
.tv_sec
, ru0
.ru_utime
.tv_usec
);
685 fprintf(stdout
, "beginning sys time = %d sec and %d usec\n", ru0
.ru_stime
.tv_sec
, ru0
.ru_stime
.tv_usec
);
687 /* Init REAL Timer */
688 if (setitimer (ITIMER_REAL
, &itime0
, 0))
690 perror ("Setting 'itimer' REAL failed");
693 fprintf(stdout
, "Beginning transaction time = %d sec and %d usec\n", itime0
.it_value
.tv_sec
, itime0
.it_value
.tv_usec
);
697 * R E A D _ T I M E R
700 read_timer (char *str
, int len
)
702 struct itimerval itimedol
;
705 struct timeval tend
, tstart
;
708 getrusage (RUSAGE_SELF
, &ru1
);
709 fprintf(stdout
, "final user time = %d sec and %d usec\n", ru1
.ru_utime
.tv_sec
, ru1
.ru_utime
.tv_usec
);
710 fprintf(stdout
, "final sys time = %d sec and %d usec\n", ru1
.ru_stime
.tv_sec
, ru1
.ru_stime
.tv_usec
);
712 if (getitimer (ITIMER_REAL
, &itimedol
))
714 perror ("Getting 'itimer' REAL failed");
717 fprintf(stdout
, "End transaction time = %d sec and %d usec\n", itimedol
.it_value
.tv_sec
, itimedol
.it_value
.tv_usec
);
718 prusage (&ru0
, &ru1
, &itime0
.it_value
, &itimedol
.it_value
, line
);
719 (void) strncpy (str
, line
, len
);
722 tvsub (&td
, &itime0
.it_value
, &itimedol
.it_value
);
723 realt
= td
.tv_sec
+ ((double) td
.tv_usec
) / 1000000;
725 /* Get CPU time (user+sys) */
726 tvadd (&tend
, &ru1
.ru_utime
, &ru1
.ru_stime
);
727 tvadd (&tstart
, &ru0
.ru_utime
, &ru0
.ru_stime
);
728 tvsub (&td
, &tend
, &tstart
);
729 cput
= td
.tv_sec
+ ((double) td
.tv_usec
) / 1000000;
736 prusage (register struct rusage
*r0
, struct rusage
*r1
,
737 struct timeval
*b
, struct timeval
*e
, char *outp
)
739 struct timeval tdiff
;
745 t
= (r1
->ru_utime
.tv_sec
- r0
->ru_utime
.tv_sec
) * 1000 +
746 (r1
->ru_utime
.tv_usec
- r0
->ru_utime
.tv_usec
) / 100000 +
747 (r1
->ru_stime
.tv_sec
- r0
->ru_stime
.tv_sec
) * 1000 +
748 (r1
->ru_stime
.tv_usec
- r0
->ru_stime
.tv_usec
) / 100000;
749 ms
= -((e
->tv_sec
- b
->tv_sec
) * 1000 + (e
->tv_usec
- b
->tv_usec
) / 1000);/* in milliseconds */
751 #define END(x) {while(*x) x++;}
753 cp
= "%Uuser %Ssys %Ereal %P";
755 cp
= "%Uutime %Sstime %Edtime %P cpu occupancy";
756 /* cp = "%Uuser %Ssys %Ereal %P %Xi+%Dd %Mmaxrss %F+%Rpf %Ccsw";*/
766 tvsub (&tdiff
, &r1
->ru_utime
, &r0
->ru_utime
);
767 /* sprintf (outp, "%d.%01d", tdiff.tv_sec, tdiff.tv_usec);*/
768 sprintf (outp
, "%f", (tdiff
.tv_sec
+ tdiff
.tv_usec
/1000000.0));
773 tvsub (&tdiff
, &r1
->ru_stime
, &r0
->ru_stime
);
774 /* sprintf (outp, "%d.%01d", tdiff.tv_sec, tdiff.tv_usec);*/
775 sprintf (outp
, "%f", (tdiff
.tv_sec
+ tdiff
.tv_usec
/1000000.0));
780 psecs (ms
/ 1000, outp
);
785 sprintf (outp
, "%f%%", (t
* 100.0 / ((ms
? ms
: 1))));
791 i
= r1
->ru_nswap
- r0
->ru_nswap
;
792 sprintf (outp
, "%d", i
);
797 sprintf (outp
, "%d", t
== 0 ? 0 : (r1
->ru_ixrss
- r0
->ru_ixrss
) / t
);
802 sprintf (outp
, "%d", t
== 0 ? 0 :
803 (r1
->ru_idrss
+ r1
->ru_isrss
- (r0
->ru_idrss
+ r0
->ru_isrss
)) / t
);
808 sprintf (outp
, "%d", t
== 0 ? 0 :
809 ((r1
->ru_ixrss
+ r1
->ru_isrss
+ r1
->ru_idrss
) -
810 (r0
->ru_ixrss
+ r0
->ru_idrss
+ r0
->ru_isrss
)) / t
);
815 sprintf (outp
, "%d", r1
->ru_maxrss
/ 2);
820 sprintf (outp
, "%d", r1
->ru_majflt
- r0
->ru_majflt
);
825 sprintf (outp
, "%d", r1
->ru_minflt
- r0
->ru_minflt
);
830 sprintf (outp
, "%d", r1
->ru_inblock
- r0
->ru_inblock
);
835 sprintf (outp
, "%d", r1
->ru_oublock
- r0
->ru_oublock
);
840 sprintf (outp
, "%d+%d", r1
->ru_nvcsw
- r0
->ru_nvcsw
,
841 r1
->ru_nivcsw
- r0
->ru_nivcsw
);
851 tvadd (struct timeval
*tsum
, struct timeval
*t0
, struct timeval
*t1
)
853 tsum
->tv_sec
= t0
->tv_sec
+ t1
->tv_sec
;
854 tsum
->tv_usec
= t0
->tv_usec
+ t1
->tv_usec
;
855 if (tsum
->tv_usec
> 1000000)
856 tsum
->tv_sec
++, tsum
->tv_usec
-= 1000000;
860 tvsub (struct timeval
*tdiff
, struct timeval
*t1
, struct timeval
*t0
)
862 tdiff
->tv_sec
= t1
->tv_sec
- t0
->tv_sec
;
863 tdiff
->tv_usec
= t1
->tv_usec
- t0
->tv_usec
;
864 if (tdiff
->tv_usec
< 0)
865 tdiff
->tv_sec
--, tdiff
->tv_usec
+= 1000000;
869 psecs (long l
, register char *cp
)
876 sprintf (cp
, "%d hours", i
);
879 sprintf (cp
, "%d minutes ", (i
/ 60));
880 sprintf (cp
, "%d seconds ", (i
% 60));
886 sprintf (cp
, "%d minutes ", i
/ 60);
891 sprintf (cp
, "%d seconds ", i
);
898 Nread (ACE_SOCK_Stream
&s
, void *buf
, int count
)
901 return (s
.recv (buf
, count
));
908 Nwrite (ACE_SOCK_Stream
&s
, void *buf
, int count
)
911 return s
.send (buf
, count
);
921 (void) select (1, (fd_set
*) 0, (fd_set
*) 0, (fd_set
*) 0, &tv
);
927 * This function performs the function of a read(II) but will
928 * call read(II) multiple times in order to get the requested
929 * number of characters. This can be necessary because
930 * network connections don't deliver data with the same
931 * grouping as it is written with. Written by Robert S. Miles, BRL.
934 mread (int fd
, register char *bufp
, unsigned n
)
936 register unsigned count
= 0;
941 nread
= read (fd
, bufp
, n
- count
);
945 perror ("ttcp_mread");
949 return ((int) count
);
950 count
+= (unsigned) nread
;
955 return ((int) count
);