static char USMID[] = "@(#)tcp/usr/etc/nettest/nettest.c 80.6 11/03/92 17:12:29";
/*
* Copyright 1992 Cray Research, Inc.
* All Rights Reserved.
*/
/*
* Permission to use, copy, modify and distribute this software, in
* source and binary forms, and its documentation, without fee is
* hereby granted, provided that: 1) the above copyright notice and
* this permission notice appear in all source copies of this
* software and its supporting documentation; 2) distributions
* including binaries display the following acknowledgement: ``This
* product includes software developed by Cray Research, Inc.'' in
* the documentation or other materials provided with the distribution
* and in all advertising materials mentioning features or use of
* this software; 3) the name Cray Research, Inc. may not be used to
* endorse or promote products derived from this software without
* specific prior written permission; 4) the USMID revision line and
* binary copyright notice are retained without modification in all
* source and binary copies of this software; 5) the software is
* redistributed only as part of a bundled package and not as a
* separate product (except that it may be redistibuted separately if
* if no fee is charged); and 6) this software is not renamed in any
* way and is referred to as Nettest.
*
* THIS SOFTWARE IS PROVIDED AS IS AND CRAY RESEARCH, INC.
* DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. IN NO EVENT SHALL CRAY RESEARCH, INC. BE
* LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
* WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
char copyright[] =
"@(#) Copyright 1992 Cray Research, Inc.\n\
All rights reserved.\n";
#define SRCRT
#include "nettest.h"
#ifdef BSD44
#include <machine/endian.h>
#endif
#if defined(BSD44) || defined(sun) || defined(ultrix) || defined(sgi)
#include <netinet/in_systm.h>
#endif
#include <sys/wait.h>
#include <sys/un.h>
#include <netinet/tcp.h>
#include <netinet/ip.h>
#include <sys/uio.h>
#include <sys/signal.h>
#ifndef NO_ISO
#include <netiso/iso.h>
#include <netiso/tp_user.h>
#endif /* NO_ISO */
#ifdef CRAY
# include <time.h>
# ifndef HZ
# define HZ CLK_TCK
# endif
#endif
#define D_PIPE 1
#define D_UNIX 2
#define D_INET 3
#define D_FILE 4
#define D_ISO 5
union {
struct sockaddr d_gen;
struct sockaddr_in d_inet;
struct sockaddr_un d_unix;
#ifndef NO_ISO
struct sockaddr_iso d_iso;
#endif /* NO_ISO */
} name;
int namesize;
int domain = D_INET;
int nchunks = NCHUNKS; /* 100 */
int chunksize = CHUNK; /* 4096 */
int dflag = 0;
int checkdata = 0;
int seqdata = 0;
int hash = 0;
int fullbuf = 0;
int kbufsize = 0;
int nodelay = 0;
int mesghdr = 0;
#ifdef BSD44
clock_t times();
#else
long times();
#endif
#if !defined(CRAY) && !defined(SYSV)
#define GETTIMES(a, b) ftime(&a); times(&b);
#define TIMETYPE struct timeb
#else
#define GETTIMES(a, b) a = times(&b);
#define TIMETYPE long
#endif
#ifdef TCP_WINSHIFT
int winshift;
int usewinshift;
#endif
int tos;
int maxchildren;
int waitall;
int sync_children = 0;
char UT_MAGIC[8] = { 'U', 't', 'i', 'm', 'e', 's', '.', '.' };
struct magic_tms {
char mt_magic[8];
struct tms mt_tms;
TIMETYPE mt_start;
TIMETYPE mt_end;
};
struct in_addr hisaddr;
char *hisname, _myname[256], *myname = _myname;
#ifndef NO_ISO
struct sockaddr_iso to_s = {sizeof(to_s), AF_ISO};
#endif
void do_children(), do_stream(), usage(), do_dgram(), prtimes();
int read();
ssize_t recv();
int (*rfunc)() = read;
main(argc, argv)
int argc;
char **argv;
{
register int s, s2, port = PORTNUMBER;
struct hostent *gethostbyname(), *hp;
char *destname;
register char *portname = 0;
int type = SOCK_STREAM;
int i;
int on = 1;
int nconnections = 1;
#if defined(SRCRT) && defined(IPPROTO_IP)
char *srp = 0, *strrchr();
unsigned long sourceroute(), srlen;
#endif
#ifndef NO_ISO
struct sockaddr_iso *to = &to_s;
union {
int port;
char data[sizeof(int)];
} portnumber;
struct hostinfo *hi;
#endif
extern char *optarg;
extern int optind;
/*
* Set max children to allow for all the pipes to be
* created. We assume that we will have one pipe open
* per child, plus stdin/stdout/stderr, plus one extra
* file descriptor for when we create the pipe. So, we
* subract 4 from the maximum number of file descriptors
* to get the maximum number of children.
*/
maxchildren = getdtablesize() - 4;
while ((i = getopt(argc, argv, "b:cCdfFhmn:p:s:S:t:Vw?")) != EOF) {
switch(i) {
case 'b': /* kernel socket buffer size */
kbufsize = atoval(optarg);
break;
case 'c': /* check the data for correctness */
++checkdata;
break;
case 'C': /* use a sequential data pattern */
++checkdata; /* implies -c option */
++seqdata;
break;
case 'd': /* turn on socket debugging */
dflag++;
break;
case 'f': /* always post full buffers for reads */
fullbuf++;
break;
case 'F': /* turn off the NODELAY bit for TCP */
#ifdef TCP_NODELAY
nodelay++;
#else
fprintf(stderr, "TCP nodelay option not supported\n");
usage();
#endif
break;
case 'h': /* show progress of data transfer */
++hash;
break;
case 'm': /* use sendmsg() instead of sendto() */
++mesghdr;
break;
case 'n': /* # connections to the destination */
nconnections = atoi(optarg);
if (nconnections < 1 || nconnections > maxchildren) {
fprintf(stderr,
"-n: value must be between 1 and %d\n",
maxchildren);
usage();
}
break;
case 'p': /* protocol to use */
if (!strcmp(optarg, "tcp")) {
domain = D_INET;
type = SOCK_STREAM;
} else if (!strcmp(optarg, "iso")) {
#ifndef NO_ISO
domain = D_ISO;
type = SOCK_SEQPACKET;
#else /* NO_ISO */
fprintf(stderr, "iso protocol not supported\n");
usage();
#endif /* NO_ISO */
} else if (!strcmp(optarg, "udp")) {
domain = D_INET;
type = SOCK_DGRAM;
nchunks = 1;
} else if (!strcmp(optarg, "unix")) {
domain = D_UNIX;
type = SOCK_STREAM;
} else if (!strcmp(optarg, "unixd")) {
domain = D_UNIX;
type = SOCK_DGRAM;
} else if (!strcmp(optarg, "pipe")) {
domain = D_PIPE;
type = SOCK_STREAM;
} else if (!strcmp(optarg, "file")) {
domain = D_FILE;
type = SOCK_STREAM;
} else {
fprintf(stderr, "Unknown protocol: %s\n", optarg);
usage();
}
break;
case 's': /* Use the TCP window shift option */
#ifdef TCP_WINSHIFT
usewinshift++;
winshift = atoi(optarg);
if (winshift < -1 || winshift > 14) {
fprintf(stderr, "window shift (-s) must be beteen -1 and 14\n");
usage();
}
#else
fprintf(stderr, "window shift option not supported\n");
usage();
#endif
break;
case 'S': /* Set the IP Type-of-Service bits */
case 't': /* old flag for setting TOS... */
#ifdef IP_TOS
if ((tos = parsetos(optarg, "*")) < 0) {
fprintf(stderr, "Bad tos argument: '%s'\n", optarg);
usage();
}
break;
#else
fprintf(stderr, "TOS (-%c) option not supported\n", (char)i);
usage();
#endif
case 'V': /* Print the version of this program */
printf("%s\n%s", &USMID[4], ©right[4]);
exit(0);
case 'w': /* use the MSG_WAITALL flag on recv() */
#ifdef MSG_WAITALL
waitall = MSG_WAITALL;
rfunc = recv;
#else
fprintf(stderr, "%s%s\n",
"MSG_WAITALL (-w) not supported locally, ",
"but will be passed on to server.");
waitall = 1; /* will be re-set to 0 below */
#endif
break;
case '?':
default:
usage();
}
}
argc -= optind;
argv += optind;
/*
* Verify consitency of the specified options
*/
if (nodelay && ((domain != D_INET) || type != SOCK_STREAM)) {
fprintf(stderr, "-F flag ignored (only valid for tcp\n");
nodelay = 0;
}
if (mesghdr && (type != SOCK_DGRAM)) {
fprintf(stderr,
"-m flag ignored (only valid for udp and unixd\n");
}
if (tos && (domain != D_INET)) {
fprintf(stderr,
"tos value ignored (only valid for tcp and udp)\n");
tos = 0;
}
if (waitall && ((domain == D_PIPE) ||
(domain == D_FILE) ||
(type == SOCK_DGRAM))) {
fprintf(stderr,
#ifndef NO_ISO
"-w flag ignored (only valid for tcp, iso and unix)\n"
#else
"-w flag ignored (only valid for tcp and unix)\n"
#endif
);
}
if (checkdata &&
#ifndef NO_ISO
(type != SOCK_SEQPACKET) &&
#endif
(type != SOCK_STREAM)) {
fprintf(stderr, "-%c flag ignored (only valid for %s)\n",
seqdata ? 'C' : 'c',
#ifndef NO_ISO
"tcp, iso, unix, pipe, and file"
#else
"tcp, unix, pipe, and file"
#endif
);
}
/*
* Pick up the port/file name(s)
*/
if ((domain == D_INET) || (domain == D_ISO)) {
hisname = myname;
if (argc) {
if (strcmp(*argv, "-"))
hisname = *argv;
--argc; ++argv;
}
} else if (domain == D_FILE) {
if (argc < 2)
usage();
myname = *argv++;
hisname = *argv++;
argc -= 2;
}
if (argc) {
if (strcmp(*argv, "-"))
nchunks = atoval(*argv);
--argc; ++argv;
if (argc) {
if (strcmp(*argv, "-"))
chunksize = atoval(*argv);
--argc; ++argv;
if (argc) {
if (strcmp(*argv, "-")) {
port = atoi(*argv);
portname = *argv;
}
if (argc > 1)
usage();
}
}
}
switch(domain) {
case D_PIPE:
if (portname == 0)
portname = PIPENAME;
if (nconnections > 1) {
fprintf(stderr, "-n flag not supported for pipe\n");
usage();
}
sprintf(myname, "%sW", portname);
if ((s2 = open(myname, 1)) < 0) {
perror(myname);
exit(1);
}
sprintf(myname, "%sR", portname);
if ((s = open(myname, 0)) < 0) {
perror(myname);
close(s2);
exit(1);
}
break;
case D_FILE:
if (nconnections > 1) {
fprintf(stderr, "-n flag not supported for file\n");
usage();
}
s2 = open(myname, 1);
if (s2 < 0) {
perror(myname);
exit(1);
}
s = open(hisname, 0);
if (s < 0) {
perror(hisname);
exit(1);
}
break;
case D_UNIX:
if (portname == 0)
portname = (type == SOCK_DGRAM) ? UNIXDPORT : UNIXPORT;
name.d_unix.sun_family = AF_UNIX;
strcpy(name.d_unix.sun_path, portname);
namesize = sizeof(name.d_unix) - sizeof(name.d_unix.sun_path)
+ strlen(name.d_unix.sun_path);
goto dosock;
break;
case D_INET:
if (nconnections > 1 && type != SOCK_STREAM) {
fprintf(stderr, "-n flag not supported for udp\n");
usage();
}
namesize = sizeof(name.d_inet);
name.d_inet.sin_family = AF_INET;
gethostname(_myname, sizeof(_myname));
#if defined(SRCRT) && defined(IPPROTO_IP)
if (*hisname == '@' || *hisname == '!') {
int temp;
if ((destname = strrchr(hisname, ':')) == NULL)
destname = strrchr(hisname, '@');
destname++;
srp = 0;
temp = sourceroute(hisname, &srp, &srlen);
if (temp == 0) {
#ifndef sun
herror(srp);
#else
printf("Can't get source route: %s\n", srp);
#endif
return 0;
} else if (temp == -1) {
printf("Bad source route option: %s\n",
hisname);
return 0;
} else {
#if !defined(CRAY) || defined(s_addr)
name.d_inet.sin_addr.s_addr = temp;
#else
name.d_inet.sin_addr = temp;
#endif
}
} else {
#endif
if ((hp = gethostbyname(hisname)) == NULL) {
long tmp;
tmp = inet_addr(hisname);
if (tmp == -1) {
fprintf(stderr, "no host entry fo %s\n", hisname);
exit(1);
}
#if !defined(CRAY) || defined(s_addr)
name.d_inet.sin_addr.s_addr = tmp;
#else
name.d_inet.sin_addr = tmp;
#endif
} else {
#if !defined(CRAY) || defined(s_addr)
bcopy(hp->h_addr, (char *)&name.d_inet.sin_addr,
hp->h_length);
#else
long tmp;
bcopy(hp->h_addr, (char *)&tmp, hp->h_length);
name.d_inet.sin_addr = tmp;
#endif
}
}
name.d_inet.sin_port = htons(port);
goto dosock;
break;
#ifndef NO_ISO
case D_ISO:
gethostname(_myname, sizeof(_myname));
if (hisname != myname) {
if ((hi = gethostinfo(hisname, 0, AF_ISO, 0, 0)) == 0) {
perror("gethostinfo(AF_ISO)");
exit(1);
}
to = (struct sockaddr_iso *)(*hi->h_addr_serv)->hs_addr;
}
name.d_iso = *to;
namesize = sizeof(name.d_iso);
name.d_iso.siso_tlen = 2;
portnumber.port = htons(port);
bcopy(&(portnumber.data[(sizeof(int)-2)]),
TSEL(&(name.d_iso)), 2);
#endif /* NO_ISO */
dosock:
if (nconnections > 1)
do_children(nconnections);
s = socket(name.d_gen.sa_family, type, 0);
if (s < 0) {
perror("socket");
exit(1);
}
if (dflag)
if (setsockopt(s, SOL_SOCKET, SO_DEBUG, &on, sizeof(on)) < 0)
perror("setsockopt - SO_DEBUG");
#ifdef IP_TOS
if (tos)
if (setsockopt(s, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0)
perror("setsockopt - IP_TOS");
#endif
if (kbufsize) {
#ifdef SO_SNDBUF
if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &kbufsize,
sizeof(kbufsize)) < 0)
perror("setsockopt - SO_SNDBUF");
if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &kbufsize,
sizeof(kbufsize)) < 0)
perror("setsockopt - SO_RCVBUF");
#else /* !SO_SNDBUF */
printf("-b: cannot set local buffer sizes\n");
#endif /* SO_SNDBUF */
}
#ifdef TCP_WINSHIFT
if (usewinshift) {
if (setsockopt(s, IPPROTO_TCP, TCP_WINSHIFT, &winshift,
sizeof(winshift)) < 0)
perror("setsockopt - TCP_WINSHIFT");
}
#endif
#ifdef TCP_NODELAY
if (nodelay) {
if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &nodelay,
sizeof(nodelay)) < 0)
perror("setsockopt - TCP_NODELAY");
}
#endif
#if defined(SRCRT) && defined(IPPROTO_IP)
if (srp && setsockopt(s, IPPROTO_IP, IP_OPTIONS,
(char *)srp, srlen) < 0)
perror("setsockopt (IP_OPTIONS)");
#endif
if (type == SOCK_DGRAM) {
do_dgram(s);
shutdown(s, 2);
exit(0);
}
#ifdef BSD44
if (connect(s, (struct sockaddr *)&name, namesize) < 0) {
#else
if (connect(s, (char *)&name, namesize) < 0) {
#endif
perror("connect");
exit(1);
}
s2 = s;
break;
}
printf("Transfer: %d*%d bytes", nchunks, chunksize);
if ((domain == D_INET) || (domain == D_ISO))
printf(" from %9s to %9s\n", myname, hisname);
else
printf("\n");
do_stream(s, s2);
if (s == s2)
shutdown(s, 2);
else {
close(s);
close(s2);
}
}
struct children {
int c_read;
int c_write;
int c_pid;
int c_ready;
TIMETYPE c_start, c_end;
};
#define CHILD_READ(n) (childrenp[n].c_read)
#define CHILD_WRITE(n) (childrenp[n].c_write)
#define CHILD_PID(n) (childrenp[n].c_pid)
#define CHILD_READY(n) (childrenp[n].c_ready)
#define CHILD_START(n) (childrenp[n].c_start)
#define CHILD_END(n) (childrenp[n].c_end)
#define ARRAY_SIZE(n) ((n)*sizeof(struct children))
/*
* When called, this routine will fork off "nconnections" children, and
* return in each of the children. The parent program will hang around
* for the children to die, printing out their statistics (read off of
* a pipe set up beforehand).
*/
void
do_children(nconnections)
int nconnections;
{
register int i;
int n;
struct children *childrenp;
char *malloc();
int status, child_error = 0;
int notready = 0, nchildren;
struct tms tms1, tms2;
TIMETYPE start, end;
char buf[1024];
int gottimes;
bzero((char *)&start, sizeof(start));
bzero((char *)&end, sizeof(end));
bzero((char *)&tms1, sizeof(tms1));
bzero((char *)&tms2, sizeof(tms2));
sync_children = getpid();
if (sync_children != getpgrp()) {
(void) setpgid(sync_children, sync_children);
sync_children = getpgrp();
}
childrenp = (struct children *)malloc(ARRAY_SIZE(nconnections));
if (childrenp == NULL) {
fprintf(stderr,
"malloc() for data to keep track of children failed\n");
exit(1);
}
bzero(childrenp, ARRAY_SIZE(nconnections));
for (i = 0; i < nconnections; i++) {
if (pipe(&CHILD_READ(i)) < 0) {
fprintf(stderr, "Cannot create pipe for child %d\n", i);
CHILD_READ(i) = -1;
continue;
}
switch(n = fork()) {
case 0:
/*
* In the child. Close down all the pipes, dup
* our pipe to stdout and stderr, and return.
*/
for (n = 0; n <= i; n++) {
if (CHILD_READ(n) >= 0)
close(CHILD_READ(n));
}
dup2(CHILD_WRITE(i), 1);
dup2(CHILD_WRITE(i), 2);
close(CHILD_WRITE(i));
return;
case -1:
close(CHILD_READ(i));
CHILD_READ(i) = -1;
close(CHILD_WRITE(i));
CHILD_WRITE(i) = -1;
fprintf(stderr, "Child %d not started\n", i);
break;
default:
close(CHILD_WRITE(i));
CHILD_PID(i) = n;
notready++;
break;
}
}
nchildren = notready;
while ((n = waitpid(-1, &status, WUNTRACED)) >= 0) {
for (i = 0; i < nconnections; i++) {
if (CHILD_PID(i) == n)
break;
}
if (i == nconnections) {
fprintf(stderr, "Unknown child [pid %d] died.\n", n);
continue;
}
/*
* Check for stopped children. When they are all
* stopped, send the SIGCONT to all of them to
* fire them up.
*/
if (WIFSTOPPED(status)) {
if (CHILD_READY(i) == 0) {
CHILD_READY(i) = 1;
if (--notready == 0)
killpg(sync_children, SIGCONT);
}
continue;
}
/*
* Check for children that have died before
* suspending themselves.
*/
if (CHILD_READY(i) == 0) {
CHILD_READY(i) = 1;
if (--notready == 0)
killpg(sync_children, SIGCONT);
}
/*
* Print out the childs statistics.
*/
printf("Child %d statistics:\n", i);
fflush(stdout);
gottimes = 0;
while ((n = read(CHILD_READ(i), buf, sizeof(buf))) > 0) {
gottimes += extract_times(buf, &n, &tms2, &start, &end,
&CHILD_START(i), &CHILD_END(i));
if (n > 0)
(void) write(1, buf, n);
}
close(CHILD_READ(i));
if (!gottimes || !WIFEXITED(status) || WEXITSTATUS(status))
child_error++;
CHILD_PID(i) = -1;
}
/*
* Print the aggregate statistics.
*/
printf("--------------------\n");
printf("Aggregate statistics for %d of %d children:\n",
nchildren, nconnections);
if (child_error)
printf(" (May not be accurate due to errors in children)\n");
printf("Transfer: %d*%d bytes over %d streams",
nchunks, chunksize, nchildren);
if ((domain == D_INET) || (domain == D_ISO))
printf(" from %9s to %9s\n", myname, hisname);
else
printf("\n");
nchunks *= nchildren; /* for total amount of data transfered */
prtimes(&start, &end, 0, &tms1, &tms2, 0);
printf("\nSyncronization information:\n");
printf("Child: Start Duration End\n");
for (i = 0; i < nconnections; i++) {
float offset, duration;
if (CHILD_READY(i) == 0)
continue;
#if !defined(CRAY) && !defined(SYSV)
offset = (CHILD_START(i).time - start.time)*1000L
+ CHILD_START(i).millitm - start.millitm;
duration = (CHILD_END(i).time - CHILD_START(i).time)*1000L
+ CHILD_END(i).millitm - CHILD_START(i).millitm;
#else
offset = (float)(CHILD_START(i) - start)*1000.0/HZ;
duration = (float)(CHILD_END(i) - CHILD_START(i))*1000.0/HZ;
#endif
printf("%5d: %8.4f %8.4f %8.4f\n", i, offset/1000.0,
duration/1000.0, (offset + duration)/1000.0);
}
exit(0);
}
/*
* Extract client timing information from the
* data stream. It returns non-zero or zero to
* inicate whether or not timing information was
* extracted from the buffer.
*
* This routine assumes that if we get all the timing
* information, or we get none of it. If the data is
* split across read()s it will not be extracted.
*/
int
extract_times(buf, np, tmsp, startp, endp, cstartp, cendp)
char *buf;
int *np;
struct tms *tmsp;
TIMETYPE *startp, *endp, *cstartp, *cendp;
{
static struct magic_tms tms;
register char *c1;
/*
* Scan the buffer for the magic string that
* designates the beginning of the timing information.
*/
for (c1 = buf; c1 <= buf + *np - sizeof(tms); c1++) {
/*
* Quick check to aviod overhead of strncmp()
*/
if (*c1 != UT_MAGIC[0])
continue;
if (strncmp(c1, UT_MAGIC, 8) == 0) {
goto gotit;
}
}
/* indicate that we did not get timing information */
return(0);
gotit:
/*
* Pull the timing data out of the buffer, and
* adjust the length value that was passed in.
*/
bcopy(c1, (char *)&tms, sizeof(tms));
bcopy(c1 + sizeof(tms), c1, *np - (c1 + sizeof(tms) - buf));
*np -= sizeof(tms);
/*
* Add in the timing information, and update the ending
* time if it is later than what we've gotten so far.
*/
tmsp->tms_utime += tms.mt_tms.tms_utime;
tmsp->tms_stime += tms.mt_tms.tms_stime;
#if !defined(CRAY) && !defined(SYSV)
if ((tms.mt_start.time < startp->time) ||
((tms.mt_start.time == startp->time) &&
(tms.mt_start.millitm < startp->millitm)) ||
((startp->time == 0) && (startp->millitm == 0)))
*startp = tms.mt_start;
if ((tms.mt_end.time > endp->time) ||
((tms.mt_end.time == endp->time) &&
(tms.mt_end.millitm > endp->millitm)))
*endp = tms.mt_end;
#else
if ((tms.mt_start < *startp) || (*startp == 0))
*startp = tms.mt_start;
if (tms.mt_end > *endp)
*endp = tms.mt_end;
#endif
*cstartp = tms.mt_start;
*cendp = tms.mt_end;
/* indicate that we extracted the timing information */
return(1);
}
int
atoval(s)
register char *s;
{
register int retval;
retval = atoi(s);
while (*s >= '0' && *s <= '9')
++s;
if (*s == 'k' || *s == 'K')
retval *= 1024;
return(retval);
}
void
do_stream(in, out)
register int in, out;
{
register int i, t, j, offset = 0, t2;
register char *cp;
char buf[128], *data, *malloc(), *orgdata;
long *cnts;
register long *ldp;
struct tms tms1, tms2, tms3;
TIMETYPE start, turnaround, end;
register unsigned long loval;
#ifndef CRAY
register unsigned long hival;
#endif
#ifndef NO_ISO
/* read ISO CC - 0 bytes */
if (domain == D_ISO) {
if ((i = read(in, buf, sizeof(buf))) != 0) {
fprintf(stderr, "read(ISO CC) failed\n");
exit(1);
}
}
#endif /* NO_ISO */
if (seqdata && chunksize&0x7) {
printf("data size must be multiple of 8. %d rounded to %d\n",
chunksize, chunksize & ~0x7);
chunksize &= ~0x7;
}
sprintf(buf, "%d %d %d %d %d %d %d %d\n", nchunks, chunksize, fullbuf,
kbufsize, tos, nodelay, seqdata, waitall);
#ifndef MSG_WAITALL
waitall = 0; /* so we don't screw up the recv() */
#endif
if (write(out, buf, strlen(buf)) != strlen(buf)) {
perror("write1");
exit(1);
}
for (cp = buf; ; ) {
i = read(in, cp, 1);
if (i != 1) {
if (i < 0)
perror("read (waiting to verify setup)");
else
fprintf(stderr, "nettest: Read returned %d, expected 1\n", i);
exit(1);
}
if (*cp == '\n')
break;
cp++;
}
*cp = '\0';
if (cp - buf > 2)
printf("remote server: %s\n", &buf[1]);
if (cp - buf > 1 && buf[0] == '0')
exit(1);
orgdata = data = malloc(chunksize+8);
if (data == NULL) {
fprintf(stderr, "cannot malloc enough data space\n");
exit(1);
}
cnts = (long *)malloc((chunksize+1)*sizeof(long));
if (cnts == NULL) {
fprintf(stderr, "cannot malloc enough stats space\n");
exit(1);
}
bzero(cnts, (chunksize+1)*sizeof(long));
if (checkdata && !seqdata)
for (cp = data, i = 0; i < chunksize; )
*cp++ = *("abcdefghijklmnopqrstuvwxyzABCDEF" + (i++/8)%32);
if (hash)
write(0, "\r\nWrite: ", 9);
loval = 0;
#ifndef CRAY
hival = 0;
#endif
if (sync_children) {
/*
* Don't start until all the children
* are ready to go. The master client
* will restart us.
*/
kill(getpid(), SIGSTOP); /* suspend ourself */
}
GETTIMES(start, tms1);
for (i = 0; i < nchunks; i++) {
if (seqdata) {
ldp = (long *)data;
for (j = 0; j < chunksize/8; j++) {
#ifndef CRAY
*ldp++ = htonl(hival);
*ldp++ = htonl(loval);
if (++loval == 0)
++hival;
#else
*ldp++ = loval++;
#endif
}
}
if ((t = write(out, data, chunksize)) < 0) {
sprintf(buf, "write #%d:", i+1);
goto bad;
}
if (t != chunksize)
fprintf(stderr, "write: %d got back %d\n", chunksize, t);
if (hash)
write(1, "#", 1);
}
GETTIMES(turnaround, tms2);
if (hash)
write(0, "\r\nRead: ", 9);
loval = 0;
#ifndef CRAY
hival = 0;
#endif
for (i = 0; i < nchunks || offset; i++) {
if ((t = (*rfunc)(in, data, chunksize, waitall)) < 0) {
sprintf(buf, "read #%d.%d", i+1, chunksize);
goto bad;
}
if (t == 0) {
fprintf(stderr, "EOF on file, block # %d\n", i);
break;
}
cnts[t]++;
if (fullbuf) {
t2 = offset;
offset += t;
if (offset >= chunksize) {
offset -= chunksize;
if (hash)
write(1, "#", 1);
} else {
--i;
if (hash)
write(1, ".", 1);
}
} else {
while (t != chunksize) {
if (hash)
write(1, ".", 1);
if ((t2 = (*rfunc)(in, data+t, chunksize-t,
waitall)) < 0) {
sprintf(buf, "read #%d.%d", i,
chunksize-t);
goto bad;
}
if (t2 == 0) {
fprintf(stderr,
"EOF on file, block # %d\n", i);
break;
}
cnts[t2]++;
t += t2;
}
if (hash)
write(1, "#", 1);
t2 = 0;
}
if (!checkdata)
continue;
if (!seqdata) {
for (cp = data, j = 0; j < t; cp++, j++) {
if (*cp != *("abcdefghijklmnopqrstuvwxyzABCDEF" +
((j+t2)/8)%32)) {
fprintf(stderr, "%d/%d(%d): got %d, expected %d\n",
i, (j+t2), i*chunksize + (j+t2), *cp,
*("abcdefghijklmnopqrstuvwxyzABCDEF" +
((j+t2)/8)%32));
}
}
continue;
}
t += data - orgdata;
data = orgdata;
ldp = (long *)data;
for (j = 0; j < t/8; j++) {
#ifndef CRAY
t2 = ntohl(*ldp++) != hival;
if ((ntohl(*ldp++) != loval) || t2) {
printf("expected %8x%8x, got %8x%8x\n",
hival, loval, ntohl(*(ldp-2)),
ntohl(*(ldp-1)));
hival = ntohl(*(ldp-2));
loval = ntohl(*(ldp-1));
}
if (++loval == 0)
++hival;
#else
if (*ldp++ != loval) {
printf("expected %16x, got %16x\n",
loval, *(ldp-1));
loval = *(ldp-1);
}
++loval;
#endif
}
t -= j*8;
if (t) {
*(long *)orgdata = *ldp;
#ifndef CRAY
*(((long *)orgdata) + 1) = *(ldp+1);
#endif
data = orgdata + t;
}
}
GETTIMES(end, tms3);
if (sync_children) {
/*
* We are a slave of the master client. Write out
* a magic cookie and then the time it took to do
* the data transfer.
*
* Note that we do this before printing out the
* statistics, so that it it will be at the beginning
* of the data read by the master client, and it
* won't have to worry about this data getting
* split across read()s.
*/
struct magic_tms td;
strncpy(td.mt_magic, UT_MAGIC, 8);
td.mt_tms.tms_utime = tms3.tms_utime - tms1.tms_utime;
td.mt_tms.tms_stime = tms3.tms_stime - tms1.tms_stime;
td.mt_tms.tms_cutime = 0;
td.mt_tms.tms_cstime = 0;
td.mt_start = start;
td.mt_end = end;
write(1, &td, sizeof(td));
}
prtimes(&start, &turnaround, &end, &tms1, &tms2, &tms3);
j = 0;
for (i = 0; i <= chunksize; i++)
if (cnts[i]) {
printf("%6d: %5d ", i, cnts[i]);
if (++j == 4) {
printf("\n");
j = 0;
}
}
if (j)
printf("\n");
#ifndef NO_ISO
/* send out ISO sync data to server */
if (domain == D_ISO) {
strncpy(data, "DONE", 4);
write(out, data, 4);
sleep(1); /* wait for packet to reach server */
}
#endif /* NO_ISO */
return;
bad:
perror(buf);
exit(1);
}
void
usage()
{
fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
"Usage: nettest [-cdfFh] [-b bufsize] [-s winshift] [-S tos] [-n #streams]",
" [-p tcp|udp|iso] [host [count [size [port]]]]",
" nettest [-cdfh] [-b bufsize] -p unix|pipes [-n #streams]",
" [count [size [filename]]]",
" nettest [-cdfh] [-b bufsize] -p file file1 file2 [count [size]]",
" nettest -V\n");
exit(1);
}
void
do_dgram(s)
register int s;
{
register int ret, i;
register char *data;
char *malloc();
struct tms tms1, tms2;
TIMETYPE start, end;
struct msghdr outmsg;
struct iovec iov;
data = malloc(chunksize);
if (data == NULL) {
fprintf(stderr, "cannot malloc enough space\n");
exit(1);
}
iov.iov_base = data;
iov.iov_len = chunksize;
bzero((char *)&outmsg, sizeof(outmsg));
outmsg.msg_iov = &iov;
outmsg.msg_iovlen = 1;
outmsg.msg_name = (caddr_t)&name;
outmsg.msg_namelen = namesize;
GETTIMES(start, tms1);
*data = 0;
for (i = 0; i < nchunks; i++) {
ret = mesghdr ? sendmsg(s, &outmsg, 0)
: sendto(s, data, chunksize, 0,
(struct sockaddr *)&name, namesize);
if (ret < 0) {
perror(mesghdr ? "sendmsg" : "sendto");
printf("%d out of %d sent\n", i, nchunks);
exit(1);
}
if (ret != chunksize)
printf("%s returned %d, expected %d\n",
mesghdr ? "sendmsg" : "sendto", ret, chunksize);
(*data)++;
}
GETTIMES(end, tms2);
/*
* Pass in same middle and end times because we only do writes for udp.
*/
prtimes(&start, &end, &end, &tms1, &tms2, &tms2);
}
void
prtimes(p0, p1, p2, tms1, tms2, tms3)
TIMETYPE *p0, *p1, *p2;
struct tms *tms1, *tms2, *tms3;
{
float t1, t2;
#if !defined(CRAY) && !defined(SYSV)
t1 = (p1->time - p0->time)*1000L
+ p1->millitm - p0->millitm;
t2 = (p2 ? ((p2->time - p1->time)*1000L
+ p2->millitm - p1->millitm) : 0.0);
#else
t1 = (float)(*p1 - *p0)*1000.0/HZ;
t2 = (p2 ? ((float)(*p2 - *p1)*1000.0/HZ) : 0.0);
#endif
tms1->tms_utime = tms2->tms_utime - tms1->tms_utime;
tms1->tms_stime = tms2->tms_stime - tms1->tms_stime;
tms2->tms_utime = tms3 ? (tms3->tms_utime - tms2->tms_utime) : 0;
tms2->tms_stime = tms3 ? (tms3->tms_stime - tms2->tms_stime) : 0;
printf(" Real System User Kbyte Mbit(K^2) mbit(1+E6)\n");
#define FORMAT "%7s %7.4f %7.4f (%4.1f%%) %7.4f (%4.1f%%) %7.2f %7.3f %7.3f\n"
if (t1 && p2)
printf(FORMAT, "write", t1/1000.0,
(float)tms1->tms_stime/HZ,
(float)tms1->tms_stime/t1*100000.0/HZ,
(float)tms1->tms_utime/HZ,
(float)tms1->tms_utime/t1*100000.0/HZ,
(chunksize*nchunks)/(1024.0*(t1/1000.0)),
(chunksize*nchunks)/(128.0*1024.0*(t1/1000.0)),
(chunksize*nchunks)/(125.0*t1));
if (t2 && p2)
printf(FORMAT, "read", t2/1000.0,
(float)tms2->tms_stime/HZ,
(float)tms2->tms_stime/t2*100000.0/HZ,
(float)tms2->tms_utime/HZ,
(float)tms2->tms_utime/t2*100000.0/HZ,
(chunksize*nchunks)/(1024.0*(t2/1000.0)),
(chunksize*nchunks)/(128.0*1024.0*(t2/1000.0)),
(chunksize*nchunks)/(125.0*t2));
if ((t1 && t2) || (!p2 && (t1 + t2)))
printf(FORMAT, "r/w", (t2+t1)/1000.0,
(float)(tms1->tms_stime + tms2->tms_stime)/HZ,
(float)(tms1->tms_stime + tms2->tms_stime)/(t1+t2)*100000.0/HZ,
(float)(tms1->tms_utime + tms2->tms_utime)/HZ,
(float)(tms1->tms_utime + tms2->tms_utime)/(t1+t2)*100000.0/HZ,
(chunksize*nchunks)/(512.0*((t1 + t2)/1000.0)),
(chunksize*nchunks)/(64.0*1024.0*((t1 + t2)/1000.0)),
(chunksize*nchunks)/(62.5*(t1 + t2)));
}
#if defined(SRCRT) && defined(IPPROTO_IP)
/*
* Source route is handed in as
* [!]@hop1@hop2...[@|:]dst
* If the leading ! is present, it is a
* strict source route, otherwise it is
* assmed to be a loose source route.
*
* We fill in the source route option as
* hop1,hop2,hop3...dest
* and return a pointer to hop1, which will
* be the address to connect() to.
*
* Arguments:
* arg: pointer to route list to decipher
*
* cpp: If *cpp is not equal to NULL, this is a
* pointer to a pointer to a character array
* that should be filled in with the option.
*
* lenp: pointer to an integer that contains the
* length of *cpp if *cpp != NULL.
*
* Return values:
*
* Returns the address of the host to connect to. If the
* return value is -1, there was a syntax error in the
* option, either unknown characters, or too many hosts.
* If the return value is 0, one of the hostnames in the
* path is unknown, and *cpp is set to point to the bad
* hostname.
*
* *cpp: If *cpp was equal to NULL, it will be filled
* in with a pointer to our static area that has
* the option filled in. This will be 32bit aligned.
*
* *lenp: This will be filled in with how long the option
* pointed to by *cpp is.
*
*/
unsigned long
sourceroute(arg, cpp, lenp)
char *arg;
char **cpp;
int *lenp;
{
static char lsr[44];
char *cp, *cp2, *lsrp, *lsrep, *index();
register int tmp;
struct in_addr sin_addr;
register struct hostent *host = 0;
register char c;
/*
* Verify the arguments, and make sure we have
* at least 7 bytes for the option.
*/
if (cpp == NULL || lenp == NULL)
return((unsigned long)-1);
if (*cpp != NULL && *lenp < 7)
return((unsigned long)-1);
/*
* Decide whether we have a buffer passed to us,
* or if we need to use our own static buffer.
*/
if (*cpp) {
lsrp = *cpp;
lsrep = lsrp + *lenp;
} else {
*cpp = lsrp = lsr;
lsrep = lsrp + 44;
}
cp = arg;
/*
* Next, decide whether we have a loose source
* route or a strict source route, and fill in
* the begining of the option.
*/
if (*cp == '!') {
cp++;
*lsrp++ = IPOPT_SSRR;
} else
*lsrp++ = IPOPT_LSRR;
if (*cp != '@')
return((unsigned long)-1);
lsrp++; /* skip over length, we'll fill it in later */
*lsrp++ = 4;
cp++;
sin_addr.s_addr = 0;
for (c = 0;;) {
if (c == ':')
cp2 = 0;
else for (cp2 = cp; c = *cp2; cp2++) {
if (c == ',') {
*cp2++ = '\0';
if (*cp2 == '@')
cp2++;
} else if (c == '@') {
*cp2++ = '\0';
} else if (c == ':') {
*cp2++ = '\0';
} else
continue;
break;
}
if (!c)
cp2 = 0;
if ((tmp = inet_addr(cp)) != -1) {
sin_addr.s_addr = tmp;
} else if (host = gethostbyname(cp)) {
#if defined(h_addr)
memcpy((caddr_t)&sin_addr,
host->h_addr_list[0], host->h_length);
#else
memcpy((caddr_t)&sin_addr, host->h_addr, host->h_length);
#endif
} else {
*cpp = cp;
return(0);
}
memcpy(lsrp, (char *)&sin_addr, 4);
lsrp += 4;
if (cp2)
cp = cp2;
else
break;
/*
* Check to make sure there is space for next address
*/
if (lsrp + 4 > lsrep)
return((unsigned long)-1);
}
if ((*(*cpp+IPOPT_OLEN) = lsrp - *cpp) <= 7) {
*cpp = 0;
*lenp = 0;
return((unsigned long)-1);
}
*lsrp++ = IPOPT_NOP; /* 32 bit word align it */
*lenp = lsrp - *cpp;
return(sin_addr.s_addr);
}
#endif
#ifndef HAS_PARSETOS
#define MIN_TOS 0
#define MAX_TOS 255
int
parsetos(name, proto)
char *name;
char *proto;
{
register char *c;
int tos;
#undef IP_TOS
#ifdef IP_TOS
struct tosent *tosp;
tosp = (struct tosent *)gettosbyname(name, proto);
if (tosp) {
tos = (int)tosp->t_tos;
} else {
#endif
for (c = name; *c; c++) {
if (*c < '0' || *c > '9') {
return (-1);
}
}
tos = (int)strtol(name, (char **)NULL, 0);
#ifdef IP_TOS
}
#endif
if (tos < MIN_TOS || tos > MAX_TOS) {
return (-1);
}
return (tos);
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1