rossc@extro.ucc.su.oz.au (Ross Cartlidge) (12/09/89)
Original-posting-by: rossc@extro.ucc.su.oz.au (Ross Cartlidge) Reposted-by: emv@math.lsa.umich.edu (Edward Vielmetti) Posting-id: 891208.1915 Posting-number: Volume TEST, Number TEST Archive-name: tcpcon -- connect an arbitrary process to a device [This is an experimental alt.sources re-posting from the newsgroup(s) comp.protocols.tcp-ip. No attempt has been made to edit, clean, modify, or otherwise change the contents of the original posting, or to contact the author. Please consider cross-posting all sources postings to alt.sources as a matter of course.] [Comments on this service to emv@math.lsa.umich.edu (Edward Vielmetti)] For all those people which replied to my posting here is the source:- ________________________________________________________________________ Ross Rodney Cartlidge | rossc@extro.ucc.su.oz.au University Computing Service, H08 | Phone: +61 2 6923497 University of Sydney, NSW 2006, Australia | FAX: +61 2 6606557 ------------------------------- Cut Here ------------------------------------- #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # Makefile # README # nd.1 # nd.c # tcpcon.1 # tcpcon.c # tcpserv.1 # tcpserv.c # This archive created: Fri Dec 8 16:58:58 1989 export PATH; PATH=/bin:/usr/bin:$PATH if test -f 'Makefile' then echo shar: "will not over-write existing file 'Makefile'" else cat << \SHAR_EOF > 'Makefile' # Set the follwing for your site # # INSTALLDIR Place to install binaries # XCFLAGS Extra libraries needed for bsd stuff # XLIBS Extra libraries needed for bsd stuff # # Values for MIPS RISC/OS 3/4 INSTALLDIR=/usr/local XCFLAGS=-I/usr/include/bsd XLIBS=-lbsd # # Values for BSD 4.3 #INSTALLDIR=/usr/local #XCFLAGS= #XLIBS= # PROGS=nd tcpserv tcpcon all: $(PROGS) tcpcon: tcpcon.c $(CC) $(XCFLAGS) $(CFLAGS) -o $@ tcpcon.c $(LIBS) $(XLIBS) nd: nd.c $(CC) $(XCFLAGS) $(CFLAGS) -o $@ nd.c $(LIBS) $(XLIBS) tcpserv: tcpserv.c $(CC) $(XCFLAGS) $(CFLAGS) -o $@ tcpserv.c $(LIBS) $(XLIBS) install: all /etc/install -o -f $(INSTALLDIR) nd /etc/install -o -f $(INSTALLDIR) tcpcon /etc/install -o -f $(INSTALLDIR) tcpserv clean: clobber: clean rm -f $(PROGS) SHAR_EOF fi if test -f 'README' then echo shar: "will not over-write existing file 'README'" else cat << \SHAR_EOF > 'README' This distribution is a set of programs to connect an arbitrary process to a device. It works by attaching the process to the master side of a pty device. This makes the slave side appear to be a connection to this process. The process can do anything, however, most commonly it is a process to establish a network connection such as telnet or tcpcon , a command supplied which connects to an arbitrary tcp address and port. It is usually used to assign a device to a port on a terminal server so that the port can be used just like a real port on a machine. This enables the port to connect a printer, run a getty, slip, uucp, ACSnet, etc. FILES:- Makefile README nd.1 nd.c tcpcon.1 tcpcon.c tcpserv.1 tcpserv.c INSTALLATION: . Edit Makefile to reflect your machine . type "make install" . Install the manual entries. . Set up an "nd" device (See manual entries and also notes below) A TEST: Try these commands to test it nd -l /dev/ptypf tcpcon localhost smtp & cat < /dev/ttypf & stty -echo < /dev/ttypf # < should be > for BSD systems cat > /dev/ttypf You should now be talking to the SMTP server of your machine. try the command help<CR> Use <CNTL>D to kill cat and then kill the async cat. Notes for Bridge/3COM terminal servers. . Enable the generic port 2000 service for your terminal servers. . Assign an IP address to the server port to which you wish to connect. . Make the port a host device. . Set the Physical parameters of the port ( Use CTS/RTS flow control and 8bit no parity if possible) To set up a connection to a port with address "ipaddr" set up the following line in /etc/inittab after creating the directory "/etc/tcpcon.d" vn:respawn:/usr/local/nd -r -d /etc/tcpcon.d -t ptypf /usr/local/tcpcon -l /dev/ptypf ipaddr 2000 If you don't have inittab then the nd command should be in a startup rc file. The pty's should be allocated from your last pty downward to stop nd clashing with automatically allocated ptys. Notes for Bridge/3COM terminal servers. . Create a server process for each port you wish to put a virtual device on, calling each process port<n> and assigning it to TCP port 2000+n. . Attach the appropriate server to the port. . Set the Physical parameters of the port ( Use CTS/RTS flow control and 8bit no parity if possible) . Enable the server. To set up device on port 6 of a cmc server with IP name cmcip, say set up the following line in /etc/inittab after creating the directory "/etc/tcpcon.d" vn:respawn:/usr/local/nd -r -d /etc/tcpcon.d -t ptypf /usr/local/tcpcon -l /dev/ptypf cmcip 2006 If you don't have inittab then the nd command should be in a startup rc file. The pty's should be allocated from your last pty downward to stop nd clashing with automatically allocated ptys. Caveats I only just added the UDP support so it might be buggy Some systems (RISC/OS 4.0.1 eg) don't make a read return on a pty when the corresponding tty is closed. This makes the process (eg the tcp connection) continue, when the tty is closed, this is annoying if you wish to cause a modem drop at the other end. To get round this you have to send a SIGINT to the nd process. See nd(1) for more details. SHAR_EOF fi if test -f 'nd.1' then echo shar: "will not over-write existing file 'nd.1'" else cat << \SHAR_EOF > 'nd.1' .TH ND 1 "April 1989" .SH NAME nd \- connect a process to a pty .SH SYNOPSIS .B nd [ .B \-r ] [ .B \-l pty ] [ .B \-f failtime ] [ .B \-c cleartime ] [ .B \-d piddir ] [ .B \-t pidtag ] .I command .SH DESCRIPTION .B Nd runs the process specified in .I command with standard input, output, error and controlling terminal assigned to the device specified by the .IR pty specified in the .B \-l option. If no .B \-l option is supplied then .I command must open the appropriate pty. The command is passed to a forked .I sh as .BI "sh \-c 'exec " "command" "'" "'" so any legal .I sh syntax can appear in the .I command field. .PP Unless .B \-r is specified, .B nd dies .I cleartime seconds after the successful completion of .IR command , allowing the other side of the connection to clear the connection. By default .I cleartime is set to 2 seconds. In the event of .I command exiting with a non-zero exit status .B nd will sleep for .I failtime before exiting. If .B \-r is specified .B nd will re-exec .I command after waiting for .I cleartime or .I failtime as appropriate. The .I failtime is to stop .B nd from exec-ing the command too often. By default .I failtime is set to 15 seconds, preventing .B nd from respawning more than 10 times in 2 minutes and being disabled by .BR init (1M), if it is being spawned from an entry in .B inittab (4) .PP .BR Init (1M) will respawn .B nd automatically if a line similar to:- .IP .BI p1:234:respawn: " nd command" .LP is added to .B /etc/inittab. .PP If you don't wish to run it from inittab or don't have inittab, .B nd should be started with the .B \-r option if you wish the connection to be permanent. .SH OPTIONS .TP 1i .BI \-l " pty" Attach .I command to .IR pty . .TP 1i .BI \-d " piddir" Log the .B pid of .I command in .IR piddir/tag . Where .I tag is the tag specified by .BR \-t or if not specified the basename of .I dev or if no .B \-l specified then tag defaults to .IR pid. "<pid of command>." Therefore if you wish to drop the connection, then kill the process with the .B pid stored in this file. .TP 1i .BI \-t " tag" set the name of the file which stores the pid of command to .IR tag . .I failtime seconds. .TP 1i .BI \-f " failtime" set the fail sleep time to .I failtime seconds. .TP 1i .BI \-c " cleartime" set the clear sleep time to .I cleartime seconds. .SH EXAMPLES .IP .B nd -r /dev/ptyqf telnet nos .LP will make the device .I /dev/ttyqf a direct connection to the .B telnet session to the host .IR nos . The connection will be respawned everytime the .I telnet dies. .IP .B kill `cat /etc/tcpcon.d/ptyqf` .LP will drop the connection established in the previous example. .IP .B nd tcpcon \-l /dev/ptyqe terminal_server 2000 .LP will make the device .I /dev/ttyqe a direct connection to the the .B TCP port 2000 on the host .IR terminal_server . .IP .B nd \-l /dev/ptyqd tcpserv 2000 .LP will make the device .I /dev/ttyqd a direct connection to any client which connects to .B TCP port 2000. .SH SIGNALS .TP 1i SIGHUP Sends a SIGTERM at the process group associated with .IR command and restarts .IR command . .TP 1i SIGTERM Sends a SIGTERM at the process group associated with .I command and exits. .SH "SEE ALSO" .BR tcpserv (1), .BR tcpcon (1), .BR telnet (1), .BR pty (7), .BR inittab (4). .SH FILES .PD 0 .TP 2i /etc/services List of ports and services .TP 2i /etc/hosts List of hosts .TP 2i /etc/inittab Script for init processes .PD SHAR_EOF fi if test -f 'nd.c' then echo shar: "will not over-write existing file 'nd.c'" else cat << \SHAR_EOF > 'nd.c' /* Written by Ross Cartlidge (rossc@extro.ucc.su.oz) University Computer Service March 1989 tcpcon - Program to connect a tty to a tcp socket Developed on a MIPS M/2000 running SysVr3 Ported to BSD/SUN-OS */ #include <fcntl.h> #include <sys/ioctl.h> #include <sys/signal.h> #include <sys/types.h> #include <syslog.h> #include <errno.h> #include <stdio.h> #include <string.h> #if defined(SYSTYPE_BSD43) #define sigset signal #define sighold(s) sigblock(sigmask(s)) #define sigrelse(s) sigsetmask(sigsetmask(-1) & ~sigmask(s)) #endif int pid; int to; int term; char *piddir; main(argc, argv) int argc; char *argv[]; { int i; char sh_c[2048]; int ret; char *dev = (char *)0; int failtime = 15; /* > 2m/10 for init */ int cleantime = 2; /* tcp connection to cleanup*/ int respawn = 0; /* respawn process*/ char *tag = (char *)0; int c; int errflg = 0; int retval; void terminate(); void timeout(); extern int errno; extern char *sys_errlist[]; extern char *optarg; extern int optind; openlog(argv[0], 0, LOG_LOCAL0); while ((c = getopt(argc, argv, "rl:f:c:d:t:")) != -1) switch (c) { case 'f': failtime = atoi(optarg); break; case 'c': cleantime = atoi(optarg); break; case 'l': dev = optarg; break; case 'd': piddir = optarg; break; case 't': tag = optarg; break; case 'r': respawn++; break; case '?': errflg++; } if (errflg || optind >= argc) { syslog(LOG_ERR, "Usage: %s [ -d <pty> ] <command>", argv[0]); exit(2); } strcpy(sh_c, "exec"); for (i = optind; i < argc; i++) { strcat(sh_c, " "); strcat(sh_c, argv[i]); } do { sighold(SIGTERM); sighold(SIGHUP); sigset(SIGTERM, terminate); sigset(SIGHUP, terminate); if (pid = fork()) { char pidf[64]; FILE *pidfs; if (piddir) { if (!tag) { if (dev) { if (tag = strrchr(dev , '/')) tag++; else tag = dev; sprintf(pidf, "%s/%s", piddir, tag); } else sprintf(pidf, "%s/pid.%d", piddir, pid); } else sprintf(pidf, "%s/%s", piddir, tag); if ((pidfs = fopen(pidf, "w")) == NULL) syslog(LOG_ERR, "open(%s) - %s", pidf, sys_errlist[errno]); else { fprintf(pidfs, "%d\n", pid); fclose(pidfs); } } if (failtime > 0) { sigset(SIGALRM, timeout); alarm(failtime); } else to = 1; sigrelse(SIGTERM); sigrelse(SIGHUP); while (wait(&ret) != -1 || errno == EINTR) ; if ((ret & 0xff) == 0) { if ((ret >> 8 & 0xff) != 0) { unlink(pidf); syslog(LOG_ERR, "Failed(%d) %s", ret >> 8, sh_c); sighold(SIGALRM); while (!to) sigpause(SIGALRM); sigrelse(SIGALRM); retval = 1; continue; } else syslog(LOG_DEBUG, "Completed %s", sh_c); } else syslog(LOG_DEBUG, "Killed(%d) %s", ret, sh_c); unlink(pidf); sleep(cleantime); retval = 0; continue; } #if defined(SYSTYPE_BSD43) ioctl(0, TIOCNOTTY, 0); setpgrp(0, getpid()); #endif #if defined(SYSTYPE_SYSV) setpgrp(); #endif close(0); close(1); close(2); sigset(SIGTERM, SIG_DFL); sigset(SIGHUP, SIG_DFL); sigrelse(SIGTERM); sigrelse(SIGHUP); if (dev) { if (open(dev, O_RDWR) == -1) { syslog(LOG_ERR, "open(%s) - %s", dev, sys_errlist[errno]); exit(2); } dup(0); dup(0); } else { open("/dev/null", O_RDONLY); open("/dev/null", O_WRONLY); dup(1); } syslog(LOG_DEBUG, "Started %s", sh_c); execl("/bin/sh", "sh", "-c", sh_c, (char *)0); syslog(LOG_ERR, "Exec failed %s", sh_c); } while (!term); } void terminate(s) int s; { if (s == SIGTERM) term = 1; kill(-pid, SIGTERM); } void timeout(s) int s; { to = 1; } SHAR_EOF fi if test -f 'tcpcon.1' then echo shar: "will not over-write existing file 'tcpcon.1'" else cat << \SHAR_EOF > 'tcpcon.1' .TH TCPCON 1 "April 1989" .SH NAME tcpcon \- Connect to a TCP socket .SH SYNOPSIS .B tcpcon [ .B \-a ] [ .B \-l pty ] [ .B \-k tty ] [ .B \-t mintime ] [ .B \-r minreads ] [ .B \-u ] .I host .I port .SH DESCRIPTION .B Tcpcon sets up a .B TCP connection to .I host on port number .IR port , forwarding standard input down the connection and writing data from the connection to standard output. No data is sent down the connection until either .I minreads have been received or .I mintime has expired. This is because many terminal servers accept connections to send information such as .B "Host Busy" and then close the connection. Data sent down these transient connections would be lost. .PP It is is usually used with .BR nd (1) to attach a .B TCP connection to a device. .SH OPTIONS .TP 1i .BI \-a Set socket connection in .B KEEPALIVE mode so that the connection will die if the other side goes down. .TP 1i .BI \-l " pty" Attach the TCP connection to .I pty rather than standard input and output. Only open .I pty after .I mintime or .I minreads has occurred. This will ensure that the slave will block until a reliable connection is created. .TP 1i .BI \-k " tty" Open .I tty after setting up the TCP connection so that the connection will be kept open when other processes close the .IR tty . If this option is specified .I tty should be the slave partner to the device specified in the .B -l option. .TP 1i .BI \-t " mintime" Set the minimum time a connection must be up before sending characters down the connection to .I mintime seconds. .TP 1i .BI \-r " minreads" Set the minimum number of reads received before sending characters down the connection to .I mintime seconds. .TP 1i .BI \-u connect to a UDP socket instead of a TCP socket. .SH EXAMPLES .IP .B tcpcon -l /dev/ptyqe localhost smtp .LP connect to the .B smtp server on the local machine and attach this connection to .IR /dev/ttyqe . .IP .B kill `cat /etc/tcpcon.d/ptyqe` .LP will drop the connection established in the previous example. .SH "SEE ALSO" .BR nd (1), .BR setsockopt (2), .BR tcpserv (1), .SH FILES .PD 0 .TP 2i /etc/hosts List of hosts .TP 2i /etc/services List of ports and services .PD SHAR_EOF fi if test -f 'tcpcon.c' then echo shar: "will not over-write existing file 'tcpcon.c'" else cat << \SHAR_EOF > 'tcpcon.c' /* Written by Ross Cartlidge (rossc@extro.ucc.su.oz) University Computer Service March 1989 tcpcon - Program to connect a tty to a tcp socket Developed on a MIPS M/2000 running SysVr3 Ported to BSD/SUN-OS */ #include <fcntl.h> #include <sys/ioctl.h> #include <sys/signal.h> #include <sys/types.h> #include <syslog.h> #include <errno.h> #include <stdio.h> #include <string.h> #include <sys/time.h> #include <sys/stat.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <setjmp.h> #define max(a,b) (a<b ? b : a) #define min(a,b) (a>b ? b : a) #if defined(SYSTYPE_BSD43) #define sigset signal #define sighold(s) sigblock(sigmask(s)) #define sigrelse(s) sigsetmask(sigsetmask(-1) & ~sigmask(s)) extern int errno; #endif #if !defined(FD_SET) #define fd_set int #define FD_SET(n,p) (*(p) |= 1 << (n)) #define FD_CLR(n,p) (*(p) &= ~(1 << (n))) #define FD_ISSET(n,p) (*(p) & 1 << (n)) #define FD_ZERO(p) (*(p) = 0) #endif #define BUFSIZE 1024 struct buf { char buf[BUFSIZE]; int cnt; }; jmp_buf env; int keepalive = 0; int pid; main(argc, argv) int argc; char *argv[]; { struct hostent *host; struct servent *serv; struct sockaddr_in sin; int s; int i; int r; char perror_fmt[128]; char usage[128]; int p; fd_set rfds; fd_set efds; fd_set wfds; int mintime = 2; int minreads = 2; char *dev = (char *)0; char *kdev = (char *)0; int errflg = 0; void terminate(); int c; int status; struct buf *bufs; int timeout(); int con_type = SOCK_STREAM; extern char *optarg; extern int optind; sprintf(perror_fmt, "PERROR_FMT=%s: %%t %%s%%m - (%%e)", argv[0]); sprintf ( usage, "USAGE: %s [-a] [-t mintime ] [-r minreads] [-l pty] [-k tty] <IP Address> <TCP Port>\n", argv[0] ); #if defined(SYSTYPE_SYSV) putenv(perror_fmt); #endif while ((c = getopt(argc, argv, "at:l:r:k:u")) != -1) switch (c) { case 'u': con_type = SOCK_DGRAM; break; case 'a': keepalive = 1; break; case 'k': kdev = optarg; break; case 't': mintime = atoi(optarg); break; case 'r': minreads = atoi(optarg); break; case 'l': dev = optarg; break; case '?': errflg++; } if (errflg || optind + 1 >= argc) { fputs(usage, stderr); exit(2); } if ((sin.sin_addr.s_addr = inet_addr(argv[optind])) != -1) sin.sin_family = AF_INET; else { if (host = gethostbyname(argv[optind])) { sin.sin_family = host->h_addrtype; memcpy(&sin.sin_addr.s_addr, host->h_addr, host->h_length); } else { fprintf ( stderr, "%s: %s: unknown host\n", argv[0], argv[optind] ); exit(2); } } if (serv = getservbyname(argv[optind + 1], "tcp")) sin.sin_port = serv->s_port; else if ( ( sin.sin_port = htons ( (short)strtol(argv[optind + 1], (char **)0, 0) ) ) <= 0 ) { fprintf ( stderr, "%s: %s: unknown service\n", argv[0], argv[optind + 1] ); exit(2); } if ((s = connectsocket(&sin, con_type)) < 0) exit(1); if ((bufs = (struct buf *)calloc(max(minreads, 1) ,sizeof (struct buf))) < 0) { perror("calloc bufs"); exit(1); } sigset(SIGALRM, timeout); sighold(SIGALRM); alarm(mintime); if (setjmp(env) == 0) for (i = 0; i < minreads; i++) { sigrelse(SIGALRM); r = read(s, bufs[i].buf, BUFSIZE); sighold(SIGALRM); if (r <= 0) exit(1); else bufs[i].cnt = r; } alarm(0); sigset(SIGALRM, SIG_IGN); sigrelse(SIGALRM); if (dev) { close(0); close(1); sighold(SIGTERM); if (pid = fork()) { sigset(SIGTERM, terminate); sigrelse(SIGTERM); if (kdev != (char *)0 && open(kdev, O_RDWR) == -1) kill(pid, SIGTERM); #if defined(SYSTYPE_BSD43) ioctl(0, TIOCNOTTY, 0); setpgrp(0, getpid()); #endif #if defined(SYSTYPE_SYSV) setpgrp(); #endif while (wait(&status) != -1 || errno == EINTR) ; if ((status & 0xff) == 0 && (status >> 8 & 0xff)) exit(status >> 8 & 0xff); else exit(0); } #if defined(SYSTYPE_BSD43) ioctl(0, TIOCNOTTY, 0); setpgrp(0, getpid()); #endif #if defined(SYSTYPE_SYSV) setpgrp(); #endif sigrelse(SIGTERM); if (open(dev, O_RDWR) == -1) { perror(dev); exit(1); } dup(0); } for (i = 0; i < minreads && bufs[i].cnt > 0; i++) if (write(1, bufs[i].buf, bufs[i].cnt) != bufs[i].cnt) exit(0); for (;;) { char *buf = bufs[0].buf; FD_ZERO(&rfds); FD_ZERO(&efds); FD_SET(0, &rfds); FD_SET(s, &rfds); FD_SET(0, &efds); FD_SET(s, &efds); select(s + 1, &rfds, (fd_set *)0, &efds, (struct timeval *)0); if (FD_ISSET(s, &rfds) || FD_ISSET(s, &efds)) { if ((r = read(s, buf, BUFSIZE)) <= 0) { perror("read"); exit(0); } if (write(1, buf, r) != r) { perror("write"); exit(0); } } if ((FD_ISSET(0, &rfds) || FD_ISSET(0, &efds))) { if ((r = read(0, buf, BUFSIZE)) <= 0) { perror("read"); exit(0); } if (write(s, buf, r) != r) { perror("write"); exit(0); } } } } connectsocket(sinp, t) struct sockaddr_in *sinp; int t; { int s; int l; int sockopt; if ((s = socket(AF_INET, t, 0)) < 0) { perror("socket"); return -1; } l = sizeof *sinp; if (connect(s, sinp, l) < 0) { perror("connect"); return -1; } if ( t == SOCK_STREAM && keepalive == 1 && setsockopt ( s, SOL_SOCKET, SO_KEEPALIVE, (sockopt = 1, (char *)&sockopt), sizeof sockopt ) < 0 ) { perror("setsockopt"); return -1; } return s; } timeout(s) int s; { longjmp(env, 1); } void terminate(s) int s; { kill(pid, s); } SHAR_EOF fi if test -f 'tcpserv.1' then echo shar: "will not over-write existing file 'tcpserv.1'" else cat << \SHAR_EOF > 'tcpserv.1' .TH TCPSERV 1 "April 1989" .SH NAME tcpserv \- accept a TCP connection .SH SYNOPSIS .B tcpserv [ .B \-u ] .I port .SH DESCRIPTION .B Tcpserv accepts a .B TCP connection on on port number .IR port , forwarding standard input down the connection and writing data from the connection to standard output. .PP It is usually used with .BR nd (1) to attach a .B TCP connection to a device. .SH OPTIONS .BI \-u service a UDP socket instead of a TCP socket. .SH EXAMPLES .IP .B tcpserv smtp .LP accepts connections to the .B smtp port on the local machine. .SH "SEE ALSO" .BR nd (1), .BR tcpcon (1). .SH FILES .PD 0 .TP 2i /etc/services List of ports and services .PD .SH BUGS SHAR_EOF fi if test -f 'tcpserv.c' then echo shar: "will not over-write existing file 'tcpserv.c'" else cat << \SHAR_EOF > 'tcpserv.c' /* Written by Ross Cartlidge (rossc@extro.ucc.su.oz) University Computer Service March 1989 */ #include <sys/types.h> #include <sys/time.h> #include <sys/stat.h> #include <signal.h> #include <sys/fcntl.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <stdio.h> #if !defined(FD_SET) #define fd_set int #define FD_SET(n,p) (*(p) |= 1 << (n)) #define FD_CLR(n,p) (*(p) &= ~(1 << (n))) #define FD_ISSET(n,p) (*(p) & 1 << (n)) #define FD_ZERO(p) (*(p) = 0) #endif #define BUFSIZE 1024 char buf[BUFSIZE]; main(argc, argv) int argc; char *argv[]; { struct sockaddr_in sin; struct sockaddr_in from; int fromlen; int s; int c; int errflg = 0; int r; char perror_fmt[128]; char usage[128]; int nfds; fd_set rfds; fd_set efds; int sockopt; int con_type = SOCK_STREAM; extern char *optarg; extern int optind; sprintf(perror_fmt, "PERROR_FMT=%s: %%t %%s%%m - (%%e)", argv[0]); sprintf(usage, "USAGE: %s <TCP Port>\n", argv[0]); #if defined(SYSTYPE_SYSV) putenv(perror_fmt); #endif while ((c = getopt(argc, argv, "u")) != -1) switch (c) { case 'u': con_type = SOCK_DGRAM; break; case '?': errflg++; break; } if (errflg || optind >= argc) { fputs(usage, stderr); exit(2); } if ((s = socket(AF_INET, con_type, 0)) < 0) { perror("socket"); exit(1); } sin.sin_family = AF_INET; sin.sin_addr.s_addr = INADDR_ANY; if ((sin.sin_port = htons((short)strtol(argv[optind], (char **)0, 0))) <= 0) { fputs(usage, stderr); exit(2); } if (bind(s, (struct sockaddr *)&sin, sizeof sin) < 0) { perror("bind"); exit(1); } if (con_type == SOCK_STREAM) { listen(s, 5); if ((s = accept(s, (struct sockaddr *)0, (int *)0)) < 0) { perror("accept"); exit(1); } if ( setsockopt ( s, SOL_SOCKET, SO_KEEPALIVE, (sockopt = 1, (char *)&sockopt), sizeof sockopt ) < 0 ) { perror("setsockopt"); exit(1); } } else { fromlen = sizeof from; if ((r = recvfrom(s, buf, sizeof buf, 0, &from , &fromlen)) == -1) { perror("recvfom"); exit(1); } if (connect(s, &from, sizeof from) == -1) { perror("connect"); exit(1); } if (write(1, buf, r) != r) { perror("write"); exit(0); } } for (;;) { FD_ZERO(&rfds); FD_ZERO(&efds); FD_SET(0, &rfds); FD_SET(s, &rfds); FD_SET(0, &efds); FD_SET(s, &efds); select(s + 1, &rfds, (fd_set *)0, &efds, (struct timeval *)0); if (FD_ISSET(0, &rfds) || FD_ISSET(0, &efds)) { if ((r = read(0, buf, BUFSIZE)) <= 0) { perror("read"); exit(0); } if (write(s, buf, r) != r) { perror("write"); exit(0); } } if (FD_ISSET(s, &rfds) || FD_ISSET(s, &efds)) { if ((r = read(s, buf, BUFSIZE)) <= 0) { perror("read"); exit(0); } if (write(1, buf, r) != r) { perror("write"); exit(0); } } } } SHAR_EOF fi exit 0 # End of shell archive -- ________________________________________________________________________ Ross Rodney Cartlidge | rossc@extro.ucc.su.oz.au University Computing Service, H08 | Phone: +61 2 6923497 University of Sydney, NSW 2006, Australia | FAX: +61 2 6606557