static char USMID[] = "@(#)tcp/usr/etc/nettest/nettestd.c 80.5 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";
#include "nettest.h"
#include <errno.h>
#include <signal.h>
#ifdef WAIT3CODE
#include <sys/wait.h>
#endif
#include <sys/un.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifdef CRAY2
#include <sys/sysmacros.h>
#endif
#include <netinet/tcp.h>
#ifndef NO_ISO
#include <netiso/iso.h>
#include <netiso/tp_user.h>
#include <netinet/in.h>
#endif /* NO_ISO */
#include <sys/uio.h>
#include <sys/ioctl.h>
#include <syslog.h>
#include <sys/termios.h>
#ifdef WAIT3CODE
dochild()
{
int pid;
while ((pid = wait3(0, WNOHANG, 0)) > 0)
;
}
#else
#define dochild SIG_IGN
#endif
int dflag;
int ipoptions = 0;
int mesghdr = 0;
#define debug(x) if(dflag>1)fprintf x
int verbose;
int daemon = 0; /* are we running in daemon mode? */
#ifdef TCP_WINSHIFT
int winshift;
int usewinshift;
#endif
#define D_PIPE 1
#define D_UNIX 2
#define D_INET 3
#define D_FILE 4
#ifndef NO_ISO
#define D_ISO 5
#endif /* NO_ISO */
int domain = D_INET;
int type = SOCK_STREAM;
union {
struct sockaddr d_gen;
struct sockaddr_un d_unix;
struct sockaddr_in d_inet;
#ifndef NO_ISO
struct sockaddr_iso d_iso;
#endif /* NO_ISO */
} name;
int namesize;
int read();
ssize_t recv();
int (*rfunc)() = read;
main(argc, argv)
int argc;
char **argv;
{
register int s, s2, mode, dev1, dev2;
char *portname = 0;
short port = PORTNUMBER;
int on = 1;
int c;
char *f1, *f2;
#ifndef NO_ISO
/* OSI transport selector */
union {
int port;
char data[sizeof(int)];
} portnumber;
#endif /* NO_ISO */
char buf[256], buf2[256];
extern int optind;
extern char *optarg;
while ((c = getopt(argc, argv, "bdimp:s:vV")) != EOF) {
switch(c) {
case 'b': /* run as a background daemon */
if (verbose) {
fprintf(stderr,
"-v flag ignored when -b flag is used\n");
verbose = 0;
}
daemon++;
break;
case 'd': /* turn on socket level debugging */
++dflag;
break;
case 'i':
ipoptions++;
break;
case 'm': /* use recvmsg() instead of recvfrom() */
#ifdef CMSG_DATA
++mesghdr;
#else
printf("'m' flag not supported\n");
#endif
break;
case 'p': /* specify the protocol to use */
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, "iso")) {
#ifndef NO_ISO
domain = D_ISO;
type = SOCK_SEQPACKET;
#else
printf("Unsupported protocol: %s\n", optarg);
usage();
#endif /* NO_ISO */
} else if (!strcmp(optarg, "tcp")) {
domain = D_INET;
type = SOCK_STREAM;
} else if (!strcmp(optarg, "udp")) {
domain = D_INET;
type = SOCK_DGRAM;
} else if (!strcmp(optarg, "file")) {
domain = D_FILE;
} else if (!strcmp(optarg, "pipe")) {
#ifdef NAMEDPIPES
domain = D_PIPE;
#else
printf("Unsupported protocol: %s\n", optarg);
usage();
#endif /* NAMEDPIPES */
} else {
printf("Unknown protocol: %s\n", optarg);
usage();
}
break;
case 's': /* set the default window shift value */
#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
case 'v': /* print out errors in sequenced data */
if (daemon) {
fprintf(stderr,
"-v flag ignored when -b flag is used\n");
verbose = 0;
} else {
++verbose;
}
break;
case 'V': /* print out version & copyright info */
printf("%s\n%s", &USMID[4], ©right[4]);
exit(0);
case '?':
default:
usage();
break;
}
}
argc -= optind;
argv += optind;
#ifdef TCP_WINSHIFT
if (usewinshift && ((domain != D_INET) || (type != SOCK_STREAM))) {
fprintf(stderr,
"nettestd: -s option ignored (only valid for tcp)\n");
usewinshift = 0;
}
#endif
if (mesghdr && (type != SOCK_DGRAM)) {
fprintf(stderr,
"nettestd: -m option ignored (only valid for udp and unixd)\n");
mesghdr = 0;
}
if (ipoptions && ((domain != D_INET) && (type != SOCK_DGRAM))) {
fprintf(stderr,
"nettestd: -i option ignored (only valid for udp)\n");
ipoptions = 0;
}
if (domain == D_FILE) {
if (argc != 2)
usage();
f1 = *argv++;
f2 = *argv++;
argc -= 2;
} else if (argc > 1)
usage();
else if (argc == 1) {
portname = *argv++;
argc--;
port = atoi(portname);
}
#ifndef _PATH_TTY
# define _PATH_TTY "/dev/tty"
#endif
#ifndef TIOCNOTTY
# ifdef TIOCSCTTY
# define TIOCNOTTY TIOCSCTTY
# else
# ifdef TCSETCTTY
# define TIOCNOTTY TCSETCTTY
# endif
# endif
#endif
if (daemon) {
if (setpgrp(0, getpid()) < 0)
perror("setpgrp");
if ((c = open(_PATH_TTY, O_RDWR)) >= 0) {
(void)ioctl(c, TIOCNOTTY, (char *)0);
(void)close(c);
}
switch (fork()) {
default: /* in the parent */
exit(0);
case -1: /* fork failed */
perror("nettestd: fork");
exit(1);
case 0: /* in the child */
break;
}
for (c = getdtablesize(); c >= 0; --c)
(void)close(c);
}
switch (domain) {
#ifdef NAMEDPIPES
case D_PIPE:
if (portname == 0)
portname = PIPENAME;
mode = S_IFIFO|0666;
dev1 = dev2 = 0;
sprintf(buf, "%sR", portname);
sprintf(buf2, "%sW", portname);
umask(0);
for(;;) {
unlink(buf);
if (mknod(buf, mode, dev1) < 0) {
error("mknod");
exit(1);
}
unlink(buf2);
if (mknod(buf2, mode, dev2) < 0) {
error("mknod");
goto err1;
}
if ((s2 = open(buf2, O_RDONLY)) < 0) {
error(buf2);
goto err2;
}
if ((s = open(buf, O_WRONLY)) < 0) {
error(buf);
close(s2);
err2: unlink(buf2);
err1: unlink(buf);
exit(1);
}
data_stream(s2, s);
close(s2);
close(s);
}
break;
#endif /* NAMEDPIPES */
case D_FILE:
for(;;) {
s = open(f1, 0);
if (s < 0) {
error(f1);
exit(1);
}
s2 = open(f2, 1);
if (s2 < 0) {
error(f2);
exit(1);
}
data_stream(s, s2);
close(s2);
close(s);
sleep(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);
(void) unlink(portname);
goto dosock;
break;
case D_INET:
name.d_inet.sin_family = AF_INET;
if (port <= 0) {
fprintf(stderr, "bad port number\n");
exit(1);
}
name.d_inet.sin_port = htons(port);
#if !defined(CRAY) || defined(s_addr)
name.d_inet.sin_addr.s_addr = 0;
#else
name.d_inet.sin_addr = 0;
#endif
namesize = sizeof(name.d_inet);
goto dosock;
break;
#ifndef NO_ISO
case D_ISO:
name.d_iso.siso_len = sizeof(struct sockaddr_iso);
name.d_iso.siso_family = AF_ISO;
name.d_iso.siso_tlen = 2;
if ((port <= 0) || (port > 65535)) {
fprintf(stderr, "bad ISO port number\n");
exit(1);
}
portnumber.port = htons(port);
bcopy(&(portnumber.data[(sizeof(int)-2)]),
TSEL(&(name.d_iso)), 2);
namesize = sizeof(name.d_iso);
#endif /* NO_ISO */
dosock:
if ((s = socket(name.d_gen.sa_family, type, 0)) < 0) {
error("socket");
exit(1);
}
if (dflag && setsockopt(s, SOL_SOCKET, SO_DEBUG, &on, sizeof(on)) < 0)
error("setsockopt - SO_DEBUG");
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
#if defined(IP_RECVOPTS) || defined(IP_RECVRETOPTS) || defined(IP_RECVDSTADDR)
if (ipoptions)
if(
# if defined(IP_RECVOPTS)
setsockopt(s, IPPROTO_IP,
IP_RECVOPTS, &on, sizeof(on)) < 0
# endif
# if defined(IP_RECVRETOPTS)
|| setsockopt(s, IPPROTO_IP,
IP_RECVRETOPTS, &on, sizeof(on)) < 0
# endif
# if defined(IP_RECVDSTADDR)
|| setsockopt(s, IPPROTO_IP,
IP_RECVDSTADDR, &on, sizeof(on)) < 0
# endif
)
error("setsockopt (IP_OPTIONS)");
#endif
if (bind(s, (struct sockaddr *)&name, namesize) < 0) {
error("bind");
exit(1);
}
if (type == SOCK_DGRAM)
do_dgram(s);
else
do_stream(s);
/*NOTREACHED*/
break;
}
}
do_stream(s)
register int s;
{
register int i, s2;
#ifndef NO_ISO
struct sockaddr_iso isoname;/*ZAP*/
#endif /* NO_ISO */
int kbufsize;
#ifdef TCP_WINSHIFT
if (usewinshift) {
if (setsockopt(s, IPPROTO_TCP, TCP_WINSHIFT, &winshift,
sizeof(winshift)) < 0)
error("setsockopt - TCP_WINSHIFT");
}
#endif
listen(s, 5);
signal(SIGCHLD, (void *)dochild);
for (;;) {
namesize = sizeof(name);
s2 = accept(s, (struct sockaddr *)&name, &namesize);
if (s2 < 0) {
extern int errno;
if (errno == EINTR)
continue;
error("accept");
} else {
if ((i = fork()) == 0) {
close(s);
i = data_stream(s2, s2);
shutdown(s2, 2);
exit(i);
} else if (i < 0)
error("fork");
close(s2);
}
}
}
#ifndef CRAY
#define VRFY() { \
register int j, k; \
register long *ldp = (long *)(data + (offset&~0x7)); \
register int len = t + (offset&0x7); \
for (j = 0; j < len/8; j++) { \
k = (ntohl(*ldp++) != hival); \
if ((ntohl(*ldp++) != loval) || k) { \
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; \
} \
if ((len&0x7) && (offset+t) >= chunksize) { \
*(ldp-(chunksize/8)) = *ldp; \
*(ldp-(chunksize/8)+1) = *(ldp+1); \
} \
}
#else
#define VRFY() { \
register int j; \
register long *ldp = (long *)(data + (offset&~0x7)); \
register int len = t + (offset&0x7); \
for (j = 0; j < len/8; j++) { \
if (*ldp++ != loval) { \
printf("expected %16x, got %16x\n", \
loval, *(ldp-1)); \
loval = *(ldp-1); \
} \
++loval; \
} \
if ((len&0x7) && ((offset+t) >= chunksize)) { \
*(ldp-(chunksize/8)) = *ldp; \
} \
}
#endif
data_stream(in, out)
register in, out;
{
register int i, t, offset = 0;
register char *cp, *data;
char buf[128], *malloc();
int chunks = 0, chunksize = 0, fullbuf = 0, kbufsize = 0;
int tos = 0, nodelay = 0, seqdata = 0, waitall = 0;
register unsigned long hival, loval;
#ifndef NO_ISO
/* read ISO CR - 0 bytes of data */
if (domain == D_ISO) {
if ((i = read(in, buf, sizeof(buf))) != 0) {
fprintf(stderr, "read(ISO CR) failed\n");
exit(1);
}
}
#endif /* NO_ISO */
for (cp = buf; ; ) {
i = read(in, cp, 1);
if (i != 1) {
if (i < 0)
error("nettestd: read");
else
fprintf(stderr, "nettestd: Read returned %d, expected 1\n", i);
exit(1);
}
if (*cp == '\n')
break;
cp++;
}
*cp = '\0';
sscanf(buf, "%d %d %d %d %d %d %d %d", &chunks, &chunksize, &fullbuf,
&kbufsize, &tos, &nodelay, &seqdata, &waitall);
/*
* If fullbuf is set, allocate a buffer twice as big. This
* is so that we can always read a full size buffer, from
* the offset of the last read. This keeps the data in
* the first chunksize consistent in case the remote side
* is trying to verify the contents.
*/
data = malloc(fullbuf ? 2*chunksize : chunksize);
if (data == NULL) {
sprintf(buf, "0 malloc() failed\n");
write(out, buf, strlen(buf));
return(1);
}
strcpy(buf, "1");
if (kbufsize) {
#ifdef SO_SNDBUF
if ((setsockopt(out, SOL_SOCKET, SO_SNDBUF, &kbufsize,
sizeof(kbufsize)) < 0) ||
(setsockopt(in, SOL_SOCKET, SO_RCVBUF, &kbufsize,
sizeof(kbufsize)) < 0))
#endif
strcat(buf, " Cannot set buffers sizes.");
}
if (tos) {
#ifdef IP_TOS
if (setsockopt(out, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0)
#endif
strcat(buf, " Cannot set TOS bits.");
}
if (nodelay) {
#ifdef TCP_NODELAY
if (setsockopt(out, IPPROTO_TCP, TCP_NODELAY, &nodelay,
sizeof(nodelay)) < 0)
#endif
strcat(buf, " Cannot set TCP_NODELAY.");
}
if (waitall) {
#ifdef MSG_WAITALL
waitall = MSG_WAITALL;
rfunc = recv;
#else
strcat(buf, " MSG_WAITALL not supported.");
waitall = 0;
#endif
}
strcat(buf, " \n");
write(out, buf, strlen(buf));
hival = loval = 0;
for (i = 0; i < chunks || offset; i++) {
if ((t = (*rfunc)(in, data + offset, chunksize, waitall)) < 0) {
sprintf(buf, "server: read #%d.%d", i+1, chunksize);
goto bad;
}
if (t == 0) {
fprintf(stderr, "server: EOF on read, block # %d\n", i);
break;
}
if (verbose && seqdata)
VRFY();
/*@*/ debug((stderr, "server: %d: read %d\n", i, t));
if (fullbuf) {
offset += t;
if (offset >= chunksize)
offset -= chunksize;
else
--i;
} else while (t != chunksize) {
register int t2;
t2 = (*rfunc)(in, data+t, chunksize-t, waitall);
if (verbose && seqdata)
VRFY();
if (t2 < 0) {
sprintf(buf, "server: read #%d.%d",
i+1, chunksize-t);
goto bad;
}
if (t2 == 0) {
fprintf(stderr, "server: EOF on read, block # %d\n", i);
break;
}
t += t2;
/*@*/ debug((stderr, "server: %d: partial read %d (%d)\n", i, t2, t));
}
}
hival = loval = 0;
for (i = 0; i < chunks; i++) {
if (seqdata) {
register int j;
register long *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, "server: write #%d", i+1);
goto bad;
}
if (t != chunksize)
fprintf(stderr, "server: write: %d vs %d\n", t, chunksize);
/*@*/ else
/*@*/ debug((stderr, "server: %d: write %d\n", i, t));
}
#ifndef NO_ISO
/* read ISO sync-up data */
if (domain == D_ISO) {
if ((i = read(in, buf, sizeof(buf))) == 4) {
if (strncmp(buf, "DONE", 4))
fprintf(stderr,
"OSI server got wrong sync-up data\n");
} else
fprintf(stderr,
"OSI server got wrong size sync-up (%d)\n", i);
}
#endif /* NO_ISO */
free(data);
return(0);
bad:
error(buf);
free(data);
return(1);
}
#define MAXSIZE (64*1024)
do_dgram(s)
int s;
{
register int t, t2;
register char *cp, *data;
register struct hostent *hp;
char *inet_ntoa(), *malloc();
register char *errmsg;
#ifdef CMSG_DATA
struct msghdr inmsg;
struct iovec iov;
char control[3*(sizeof(struct cmsghdr)+40)];
register struct cmsghdr *cm;
#endif /* CMSG_DATA */
data = malloc(MAXSIZE);
if (data == NULL) {
fprintf(stderr, "no malloc\n");
shutdown(s, 2);
exit(1);
}
#ifdef CMSG_DATA
if(mesghdr) {
iov.iov_base = data;
iov.iov_len = MAXSIZE;
inmsg.msg_iov = &iov;
inmsg.msg_iovlen = 1;
inmsg.msg_name = (caddr_t)&name.d_inet;
inmsg.msg_control = (caddr_t)control;
inmsg.msg_flags = 0;
errmsg = "recvmsg";
} else
#endif /* CMSG_DATA */
errmsg = "recvfrom";
for (;;) {
#ifdef CMSG_DATA
if (mesghdr) {
inmsg.msg_namelen = sizeof(name.d_inet);
inmsg.msg_controllen = sizeof(control);
t = recvmsg(s, &inmsg, 0);
} else
#endif
{
namesize = sizeof(name.d_inet);
t = recvfrom(s, data, MAXSIZE, 0, (struct sockaddr *)&name.d_inet,
&namesize);
}
if (t < 0) {
error(errmsg);
continue;
}
if (domain == D_INET) {
cp = inet_ntoa(name.d_inet.sin_addr);
printf("got %d bytes from %s\n", t, cp);
} else
printf("got %d bytes\n", t);
}
}
usage()
{
fprintf(stderr, "%s%s%s%s%s",
"Usage: nettestd [-b] [-d] [-v] [-s val] [-p tcp] [port]\n",
" nettestd [-b] [-d] [-i] [-m] -p udp [port]\n",
#ifndef NO_ISO
" nettestd [-b] [-d] [-v] -p iso [port]\n",
#else
"",
#endif
" nettestd [-b] [-d] [-v] -p unix|pipe [filename]\n",
" nettestd [-b] [-d] [-m] -p unixd [filename]\n",
" nettestd [-b] [-d] [-v] -p file readfile writefile\n",
" nettestd -V\n");
exit(1);
}
error(string)
char *string;
{
if (daemon)
syslog(LOG_ERR, "nettestd: %s %m", string);
else
perror(string);
}
syntax highlighted by Code2HTML, v. 0.9.1