mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 10:11:27 +01:00
bitkeeper revision 1.1041.6.1 (40e5221awCqaZfcsO_ny2z3p_6BiEg)
nsplitd.c, Makefile: mvdir Makefile: Rename: BitKeeper/deleted/.del-Makefile~9f548ce6ff509eac -> tools/nsplitd/Makefile nsplitd.c: Rename: BitKeeper/deleted/.del-nsplitd.c~8b67653f8e377176 -> tools/nsplitd/nsplitd.c
This commit is contained in:
1 parent
e32a5a3265
commit
dc44ed4764
3 files changed
+710
No files matched your search
@@ -201,6 +201,8 @@
|
||||
3f6dc140C8tAeBfroAF24VrmCS4v_w tools/misc/miniterm/README
|
||||
3f6dc142IHaf6XIcAYGmhV9nNSIHFQ tools/misc/miniterm/miniterm.c
|
||||
40c9c469kT0H9COWzA4XzPBjWK0WsA tools/misc/netfix
|
||||
4022a73cEKvrYe_DVZW2JlAxobg9wg tools/misc/nsplitd/Makefile
|
||||
4022a73cKms4Oq030x2JBzUB426lAQ tools/misc/nsplitd/nsplitd.c
|
||||
3f870808_8aFBAcZbWiWGdgrGQyIEw tools/misc/p4perf.h
|
||||
3f5ef5a2ir1kVAthS14Dc5QIRCEFWg tools/misc/xen-clone
|
||||
3f5ef5a2dTZP0nnsFoeq2jRf3mWDDg tools/misc/xen-clone.README
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
|
||||
CC = gcc
|
||||
CFLAGS = -Wall -O3
|
||||
CFILES = $(wildcard *.c)
|
||||
|
||||
HDRS = $(wildcard *.h)
|
||||
OBJS = $(patsubst %.c,%.o,$(wildcard *.c))
|
||||
|
||||
TARGET = nsplitd
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
install: all
|
||||
|
||||
clean:
|
||||
$(RM) *.o $(TARGET) *~
|
||||
|
||||
$(TARGET): $(OBJS)
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
|
||||
%.o: %.c $(HDRS) Makefile
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
@@ -0,0 +1,686 @@
|
||||
/*
|
||||
* nsplitd.c
|
||||
* ---------
|
||||
*
|
||||
* $Id: nsplitd.c,v 2.6 1998/09/17 14:28:37 sde1000 Exp $
|
||||
*
|
||||
* Copyright (c) 1995, University of Cambridge Computer Laboratory,
|
||||
* Copyright (c) 1995, Richard Black, All Rights Reserved.
|
||||
*
|
||||
*
|
||||
* A complete re-implementation of DME's nsplitd for use from inetd
|
||||
*
|
||||
*/
|
||||
|
||||
/* The basic stream comes in (via inetd) and we then conenct to
|
||||
* somewhere else providing a loop-through service, except we offer
|
||||
* two other ports for connection - one of which gets a second channel
|
||||
* using the top bit to distinguish, and the other is a master control
|
||||
* port (normally used for gdb) which gets complete exclusive access
|
||||
* for its duration.
|
||||
*
|
||||
* Originally designed for multiplexing a xwcons/telnet with a gdb
|
||||
* post-mortem debugging session.
|
||||
*
|
||||
* Here is a picture:
|
||||
*
|
||||
* port0 (from inetd)
|
||||
* 8-bit connection /
|
||||
* made by us <----> nsplitd <-----gdbport (default port0+2)
|
||||
* to host:port/tcp |\
|
||||
* | port1 (default port0+1)
|
||||
* \
|
||||
* control (default port0+3)
|
||||
*
|
||||
* If port1 is explicitly disabled (through a command-line option) then
|
||||
* port0 becomes 8-bit clean.
|
||||
*/
|
||||
|
||||
/*
|
||||
* N.B.: We do NOT support 8 bit stdin/stdout usage on a
|
||||
* /dev/... because to do that right involves much messing with ioctl
|
||||
* and TIOC... etc. If you want to do that sort of thing then the
|
||||
* right way to do it is to chain this onto wconsd (which does know
|
||||
* about and understand all the ioctl and TIOC grief).
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include <netdb.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sys/signal.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#ifndef LOG_DAEMON
|
||||
#define LOG_DAEMON 0
|
||||
#endif
|
||||
|
||||
#define DB(x) /* ((x), fflush(stderr)) */
|
||||
|
||||
extern char *optarg;
|
||||
|
||||
extern int optind, opterr, optopt;
|
||||
|
||||
static char *prog_name;
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr, "This program (%s) should be run via inetd (tcp)\n\n",
|
||||
prog_name);
|
||||
fprintf(stderr, "usage: %s [-h<highport>][-g<gdbport>]"
|
||||
"[-c<ctlport>][-8] host:service\n",
|
||||
prog_name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void fault(char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char logbuf[1024];
|
||||
|
||||
va_start(ap, format);
|
||||
fprintf(stderr, "%s: ", prog_name);
|
||||
vfprintf(stderr, format, ap);
|
||||
fflush(stderr);
|
||||
va_end(ap);
|
||||
|
||||
/* XXX This is a bit dubious, but there is no vsyslog */
|
||||
va_start(ap, format);
|
||||
vsprintf(logbuf, format, ap);
|
||||
syslog(LOG_ERR, logbuf);
|
||||
va_end(ap);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static int getservice(char *name, unsigned short *port)
|
||||
{
|
||||
struct servent *se;
|
||||
|
||||
if (!name) return -1;
|
||||
|
||||
if (isdigit(name[0]))
|
||||
*port = atoi(name);
|
||||
else
|
||||
{
|
||||
if (!(se = getservbyname(name, "tcp")))
|
||||
return -1;
|
||||
*port = ntohs(se->s_port);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* connect_host: connect to ("name", "port")
|
||||
*/
|
||||
static int connect_host (char *name, unsigned int port)
|
||||
{
|
||||
int fd;
|
||||
struct hostent *hostent;
|
||||
struct sockaddr_in sin;
|
||||
int on;
|
||||
|
||||
if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0)
|
||||
fault("socket");
|
||||
|
||||
if (!(hostent = gethostbyname(name)))
|
||||
fault("gethostbyname: %s: %s\n", name, strerror(errno));
|
||||
|
||||
memset(&sin, 0, sizeof(sin));
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons (port);
|
||||
memcpy(&sin.sin_addr.s_addr, hostent->h_addr, sizeof(struct in_addr));
|
||||
|
||||
if (connect(fd, (struct sockaddr *) &sin, sizeof (sin)) < 0)
|
||||
fault("connect: %s:%u: %s\n", name, port, strerror(errno));
|
||||
|
||||
on = 1;
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof (on)) < 0)
|
||||
syslog(LOG_WARNING, "setsockopt (TCP_NODELAY): %m");
|
||||
|
||||
on = 1;
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0)
|
||||
syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
/*
|
||||
* open a tcp socket and start listening for connections on it
|
||||
*/
|
||||
static int startlistening(unsigned short port)
|
||||
{
|
||||
int fd, on;
|
||||
struct sockaddr_in sin;
|
||||
|
||||
if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0)
|
||||
fault("socket");
|
||||
|
||||
on = 1;
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0)
|
||||
syslog(LOG_WARNING, "setsockopt (SO_REUSEADDR): %m");
|
||||
|
||||
memset(&sin, 0, sizeof(sin));
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons (port);
|
||||
sin.sin_addr.s_addr = INADDR_ANY;
|
||||
if (bind(fd, &sin, sizeof(sin)) < 0)
|
||||
fault("bind: %u: %s\n", port, strerror(errno));
|
||||
|
||||
if (listen(fd, 1) < 0)
|
||||
fault("listen: %s\n", strerror(errno));
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static void noblock(int fd)
|
||||
{
|
||||
int on=1;
|
||||
|
||||
if (ioctl(fd, FIONBIO, &on) < 0)
|
||||
fault("ioctl: FIONBIO: %s\n", strerror(errno));
|
||||
}
|
||||
|
||||
|
||||
/* You might not believe this, but fd_sets don't have to be a 32-bit
|
||||
* integer. In particular, in glibc2 it is an array of unsigned
|
||||
* longs. Hence, this hacked up FD_SET_rjb() that works out if it
|
||||
* would have been a nop. */
|
||||
#define FD_SET_rjb(fd, setp) \
|
||||
do { \
|
||||
if ((fd) != 32) \
|
||||
FD_SET((fd), (setp)); \
|
||||
} while(0)
|
||||
|
||||
#define FD_ISSET_rjb(fd, setp) (((fd) != 32)? FD_ISSET((fd), (setp)) : 0)
|
||||
|
||||
#define MAXSIZE 256
|
||||
|
||||
/* -----------------------------------------------------------------
|
||||
* The main bit of the algorithm. Note we use 32 to mean not connected
|
||||
* because this gives us 1<<32 == 0. We could have done this one
|
||||
* character at a time, but that would have been very inefficient and
|
||||
* not the unix way. */
|
||||
static int debug;
|
||||
|
||||
static void doit(int actl, int acto, int lish, int lisg, int lisc)
|
||||
{
|
||||
int acth, actg, actc;
|
||||
int gdbmode = FALSE;
|
||||
char gibuf[MAXSIZE], oibuf[MAXSIZE];
|
||||
char libuf[MAXSIZE], lobuf[MAXSIZE];
|
||||
char hibuf[MAXSIZE], hobuf[MAXSIZE];
|
||||
char ctlbuf[MAXSIZE];
|
||||
fd_set rdfs, wrfs, exfs;
|
||||
int gicc, oicc, licc, locc, hicc, hocc, ctlcc;
|
||||
char *giptr, *oiptr, *liptr, *loptr, *hiptr, *hoptr;
|
||||
int rc, fromlen;
|
||||
struct sockaddr_in from;
|
||||
|
||||
gicc = oicc = licc = locc = hicc = hocc = ctlcc = 0;
|
||||
acth = actg = actc = 32; /* XXX yummy */
|
||||
|
||||
noblock(actl);
|
||||
noblock(acto);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
FD_ZERO(&rdfs);
|
||||
FD_ZERO(&wrfs);
|
||||
FD_ZERO(&exfs);
|
||||
|
||||
/* always take input from the control port (if it's connected) */
|
||||
FD_SET_rjb(actc, &rdfs);
|
||||
|
||||
if (gdbmode)
|
||||
{
|
||||
if (oicc)
|
||||
FD_SET_rjb(actg, &wrfs);
|
||||
else
|
||||
FD_SET_rjb(acto, &rdfs);
|
||||
|
||||
if (gicc)
|
||||
FD_SET_rjb(acto, &wrfs);
|
||||
else
|
||||
FD_SET_rjb(actg, &rdfs);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* There is no such thing as oibuf because its been split into
|
||||
* lobuf and hobuf
|
||||
*/
|
||||
if (locc || hocc)
|
||||
{
|
||||
if (locc)
|
||||
FD_SET_rjb(actl, &wrfs);
|
||||
if (hocc)
|
||||
FD_SET_rjb(acth, &wrfs);
|
||||
}
|
||||
else
|
||||
FD_SET_rjb(acto, &rdfs);
|
||||
|
||||
if (licc)
|
||||
FD_SET_rjb(acto, &wrfs);
|
||||
else
|
||||
FD_SET_rjb(actl, &rdfs);
|
||||
|
||||
if (hicc)
|
||||
FD_SET_rjb(acto, &wrfs);
|
||||
else
|
||||
FD_SET_rjb(acth, &rdfs);
|
||||
}
|
||||
|
||||
if (acth == 32 && lish>=0) FD_SET_rjb(lish, &rdfs);
|
||||
if (actg == 32) FD_SET_rjb(lisg, &rdfs);
|
||||
if (actc == 32) FD_SET_rjb(lisc, &rdfs);
|
||||
|
||||
/* now make exfs the union of the read and write fd sets, plus
|
||||
* "actl" */
|
||||
{
|
||||
int i;
|
||||
exfs = rdfs;
|
||||
for(i=0; i<32; i++) /* XXX we only copy fd numbers up to 31 */
|
||||
if (FD_ISSET(i, &wrfs))
|
||||
FD_SET_rjb(i, &exfs);
|
||||
FD_SET_rjb(actl, &exfs);
|
||||
}
|
||||
|
||||
/* XXX AND: can't print something of type fd_set as %x - it
|
||||
* might be an array */
|
||||
DB(fprintf(stderr, "%s: before select: %08x %08x %08x\n",
|
||||
prog_name, rdfs, wrfs, exfs));
|
||||
|
||||
if (select(32, &rdfs, &wrfs, &exfs, NULL) < 0)
|
||||
fault("select: %s\n", strerror(errno));
|
||||
|
||||
DB(fprintf(stderr, "%s: after select: %08x %08x %08x\n",
|
||||
prog_name, rdfs, wrfs, exfs));
|
||||
|
||||
/* XXX it appears that a non-blocking socket may not show up
|
||||
* correctly in exfs but instead goes readable with no data in
|
||||
* it. Thus we check for zero and goto the appropriate close
|
||||
* method. */
|
||||
|
||||
/* Deal with exceptions */
|
||||
if (FD_ISSET_rjb(actg, &exfs))
|
||||
{
|
||||
exfs_actg:
|
||||
close(actg);
|
||||
gdbmode = FALSE;
|
||||
oicc = 0;
|
||||
oiptr = oibuf;
|
||||
actg = 32;
|
||||
continue; /* because assumptions changed */
|
||||
}
|
||||
if (FD_ISSET_rjb(acth, &exfs))
|
||||
{
|
||||
exfs_acth:
|
||||
close(acth);
|
||||
hicc = hocc = 0;
|
||||
hiptr = hibuf;
|
||||
hoptr = hibuf;
|
||||
acth = 32;
|
||||
continue; /* because assumptions changed */
|
||||
}
|
||||
if (FD_ISSET_rjb(actl, &exfs) ||
|
||||
FD_ISSET_rjb(acto, &exfs))
|
||||
{
|
||||
exfs_actl:
|
||||
exfs_acto:
|
||||
/* Thats all folks ... */
|
||||
break;
|
||||
}
|
||||
if (FD_ISSET_rjb(actc, &exfs))
|
||||
{
|
||||
exfs_ctl:
|
||||
close(actc);
|
||||
actc = 32;
|
||||
ctlcc = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Deal with reading */
|
||||
if (FD_ISSET_rjb(acto, &rdfs))
|
||||
{
|
||||
if ((oicc = read(acto, oiptr = oibuf, MAXSIZE)) < 0)
|
||||
fault("read acto: %d: %s\n", oicc, strerror(errno));
|
||||
if (!oicc) goto exfs_acto;
|
||||
|
||||
if (!gdbmode)
|
||||
{
|
||||
int t;
|
||||
|
||||
assert((locc == 0) && (hocc == 0));
|
||||
loptr = lobuf;
|
||||
hoptr = hobuf;
|
||||
|
||||
if (lish>=0) {
|
||||
for(t=0; t<oicc; t++)
|
||||
if (oibuf[t] & 0x80)
|
||||
hobuf[hocc++] = oibuf[t] & 0x7f;
|
||||
else
|
||||
lobuf[locc++] = oibuf[t];
|
||||
} else {
|
||||
for (t=0; t<oicc; t++)
|
||||
lobuf[locc++] = oibuf[t];
|
||||
}
|
||||
/* If no high connection scratch that */
|
||||
if (acth == 32)
|
||||
hocc=0;
|
||||
}
|
||||
}
|
||||
if (FD_ISSET_rjb(actl, &rdfs))
|
||||
{
|
||||
if ((licc = read(actl, liptr = libuf, MAXSIZE)) < 0)
|
||||
fault("read actl: %d: %s\n", licc, strerror(errno));
|
||||
if (!licc) goto exfs_actl;
|
||||
}
|
||||
if (FD_ISSET_rjb(acth, &rdfs))
|
||||
{
|
||||
int t;
|
||||
|
||||
if ((hicc = read(acth, hiptr = hibuf, MAXSIZE)) < 0)
|
||||
fault("read acth: %d: %s\n", hicc, strerror(errno));
|
||||
if (!hicc) goto exfs_acth;
|
||||
for(t=0; t<hicc; t++)
|
||||
hibuf[t] |= 0x80;
|
||||
}
|
||||
if (FD_ISSET_rjb(actg, &rdfs))
|
||||
{
|
||||
if ((gicc = read(actg, giptr = gibuf, MAXSIZE)) < 0)
|
||||
fault("read actg: %d: %s\n", gicc, strerror(errno));
|
||||
if (debug) write(1, giptr, gicc); /* XXX */
|
||||
if (!gicc) goto exfs_actg;
|
||||
}
|
||||
if (FD_ISSET_rjb(actc, &rdfs))
|
||||
{
|
||||
if ((ctlcc = read(actc, ctlbuf, MAXSIZE)) < 0)
|
||||
fault("read actc: %d: %s\n", ctlcc, strerror(errno));
|
||||
if (debug) write(1, ctlbuf, gicc);
|
||||
if (!ctlcc) goto exfs_ctl;
|
||||
if (ctlbuf[0] == 'r') /* reset command */
|
||||
{
|
||||
syslog(LOG_INFO, "reset command read, exiting");
|
||||
if (debug) write(1, "reseting\n", sizeof("reseting\n"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Deal with writing */
|
||||
if (FD_ISSET_rjb(actg, &wrfs))
|
||||
{
|
||||
/* We must be in gdb mode so send oi buffer data */
|
||||
assert(gdbmode);
|
||||
if (debug) write(2, oiptr, oicc); /* XXX */
|
||||
if ((rc = write(actg, oiptr, oicc)) <= 0)
|
||||
fault("write actg: %d: %s\n", rc, strerror(errno));
|
||||
oiptr += rc;
|
||||
oicc -= rc;
|
||||
}
|
||||
if (FD_ISSET_rjb(actl, &wrfs))
|
||||
{
|
||||
if ((rc = write(actl, loptr, locc)) <= 0)
|
||||
fault("write actl: %d: %s\n", rc, strerror(errno));
|
||||
loptr += rc;
|
||||
locc -= rc;
|
||||
}
|
||||
if (FD_ISSET_rjb(acth, &wrfs))
|
||||
{
|
||||
if ((rc = write(acth, hoptr, hocc)) <= 0)
|
||||
fault("write acth: %d: %s\n", rc, strerror(errno));
|
||||
hoptr += rc;
|
||||
hocc -= rc;
|
||||
}
|
||||
if (FD_ISSET_rjb(acto, &wrfs))
|
||||
{
|
||||
/* If in gdb mode send gdb input, otherwise send low data
|
||||
preferentially */
|
||||
if (gdbmode)
|
||||
{
|
||||
assert(gicc);
|
||||
if ((rc = write(acto, giptr, gicc)) <= 0)
|
||||
fault("write acto: %d: %s\n", rc, strerror(errno));
|
||||
giptr += rc;
|
||||
gicc -= rc;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (licc)
|
||||
{
|
||||
if ((rc = write(acto, liptr, licc)) <= 0)
|
||||
fault("write acto: %d: %s\n", rc, strerror(errno));
|
||||
liptr += rc;
|
||||
licc -= rc;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(hicc);
|
||||
if ((rc = write(acto, hiptr, hicc)) <= 0)
|
||||
fault("write acto: %d: %s\n", rc, strerror(errno));
|
||||
hiptr += rc;
|
||||
hicc -= rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Deals with new connections */
|
||||
if ((acth == 32) && lish>=0 && (FD_ISSET_rjb(lish, &rdfs)))
|
||||
{
|
||||
fromlen = sizeof(from);
|
||||
if ((acth = accept(lish, &from, &fromlen)) < 0)
|
||||
{
|
||||
syslog(LOG_WARNING, "accept: %m");
|
||||
acth = 32;
|
||||
}
|
||||
else
|
||||
{
|
||||
noblock(acth);
|
||||
hicc = hocc = 0;
|
||||
syslog(LOG_INFO, "highbit client peer is %s:%u\n",
|
||||
inet_ntoa(from.sin_addr), ntohs(from.sin_port));
|
||||
}
|
||||
}
|
||||
|
||||
if ((actg == 32) && (FD_ISSET_rjb(lisg, &rdfs)))
|
||||
{
|
||||
fromlen = sizeof(from);
|
||||
if ((actg = accept(lisg, &from, &fromlen)) < 0)
|
||||
{
|
||||
syslog(LOG_WARNING, "accept: %m");
|
||||
actg = 32;
|
||||
}
|
||||
else
|
||||
{
|
||||
noblock(actg);
|
||||
gicc = 0;
|
||||
gdbmode = TRUE;
|
||||
syslog(LOG_INFO, "gdb client peer is %s:%u\n",
|
||||
inet_ntoa(from.sin_addr), ntohs(from.sin_port));
|
||||
}
|
||||
}
|
||||
|
||||
if ((actc == 32) && (FD_ISSET_rjb(lisc, &rdfs)))
|
||||
{
|
||||
fromlen = sizeof(from);
|
||||
if ((actc = accept(lisc, &from, &fromlen)) < 0)
|
||||
{
|
||||
syslog(LOG_WARNING, "accept (ctl): %m");
|
||||
actc = 32;
|
||||
}
|
||||
else
|
||||
{
|
||||
noblock(actc);
|
||||
syslog(LOG_INFO, "ctl client peer is %s:%u\n",
|
||||
inet_ntoa(from.sin_addr), ntohs(from.sin_port));
|
||||
}
|
||||
}
|
||||
|
||||
/* Back to top of loop */
|
||||
}
|
||||
|
||||
/* We are bailing because one of the primary connections has gone
|
||||
* away. We close these all explicitly here because that way the
|
||||
* timeout on reusing the port numbers is smnaller. */
|
||||
|
||||
close(acth);
|
||||
close(actg);
|
||||
/* XXX AND: why are we closing all these "character counts" ?? */
|
||||
close(gicc);
|
||||
close(oicc);
|
||||
close(licc);
|
||||
close(locc);
|
||||
close(hicc);
|
||||
close(hocc);
|
||||
}
|
||||
|
||||
/*
|
||||
* ------------------------------------------------------------
|
||||
*/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
/* In general, suffix "l" is low channel, "h" is high channel, "g"
|
||||
* is gdb channel, "c" is control channel and "o" is output channel.
|
||||
*/
|
||||
struct sockaddr_in from;
|
||||
int infd = 0, outfd;
|
||||
unsigned short portl, porth, portg, portc, porto;
|
||||
int on = 1, c;
|
||||
char *outname, *outservice;
|
||||
int fromlen;
|
||||
int lish, lisg, lisc;
|
||||
#if 0
|
||||
FILE *newerr;
|
||||
#endif /* 0 */
|
||||
|
||||
prog_name = argv[0];
|
||||
|
||||
if (isatty(infd))
|
||||
usage();
|
||||
|
||||
/* Here, then not just a simple idiot. */
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
openlog(prog_name, LOG_PID, LOG_DAEMON);
|
||||
|
||||
fromlen = sizeof(from);
|
||||
if (getsockname(infd, &from, &fromlen) < 0)
|
||||
fault("getsockname: %s", strerror(errno));
|
||||
if ((fromlen != sizeof(from)) || (from.sin_family != AF_INET))
|
||||
fault("not an inet socket (family=%d)\n", from.sin_family);
|
||||
|
||||
portl = ntohs(from.sin_port);
|
||||
porth = portl+1;
|
||||
portg = porth+1;
|
||||
portc = portg+1;
|
||||
|
||||
fromlen = sizeof(from);
|
||||
if (getpeername(infd, &from, &fromlen) < 0)
|
||||
fault("getpeername: %s", strerror(errno));
|
||||
if ((fromlen != sizeof(from)) || (from.sin_family != AF_INET))
|
||||
fault("not an inet socket (family=%d)\n", from.sin_family);
|
||||
|
||||
syslog(LOG_INFO, "on port %u peer is %s:%u\n", portl,
|
||||
inet_ntoa(from.sin_addr), ntohs(from.sin_port));
|
||||
|
||||
if (setsockopt(infd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0)
|
||||
syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
|
||||
|
||||
/* from here on, we map stderr to output on the connection so we can
|
||||
* report errors to the remote user.
|
||||
*/
|
||||
#if 0
|
||||
if (!(newerr = fdopen(infd, "w")))
|
||||
syslog(LOG_WARNING, "fdopen: %m");
|
||||
else
|
||||
*stderr = *newerr;
|
||||
#endif
|
||||
|
||||
while((c = getopt(argc, argv, "d8h:g:c:")) != EOF)
|
||||
{
|
||||
switch(c)
|
||||
{
|
||||
case 'd':
|
||||
debug++;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
/* high bit port */
|
||||
if (getservice(optarg, &porth) < 0)
|
||||
fault("getservice failed (high port '%s')\n", optarg);
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
/* gdb port */
|
||||
if (getservice(optarg, &portg) < 0)
|
||||
fault("getservice failed (gdb port '%s')\n", optarg);
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
/* control port */
|
||||
if (getservice(optarg, &portc) < 0)
|
||||
fault("getservice failed (control port '%s')\n", optarg);
|
||||
break;
|
||||
|
||||
case '8':
|
||||
/* 8-bit clean; no high port */
|
||||
porth=0;
|
||||
break;
|
||||
|
||||
default:
|
||||
fault("bad argument list!\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (argc != optind + 1)
|
||||
fault("unparsed arguments (%d!=%d)\n", argc, optind+1);
|
||||
|
||||
outname = argv[optind];
|
||||
if (!(outservice = strchr(outname, ':')))
|
||||
fault("output arg '%s' doesn't contain ':'\n", outname);
|
||||
*outservice++ = 0;
|
||||
if (getservice(outservice, &porto) < 0)
|
||||
fault("getservice failed (output port '%s')\n", outservice);
|
||||
|
||||
/* Time to start the sockets */
|
||||
|
||||
if (porth) {
|
||||
lish = startlistening(porth);
|
||||
} else {
|
||||
lish = -1;
|
||||
}
|
||||
lisg = startlistening(portg);
|
||||
lisc = startlistening(portc);
|
||||
|
||||
outfd = connect_host(outname, porto);
|
||||
|
||||
doit(infd, outfd, lish, lisg, lisc);
|
||||
|
||||
syslog(LOG_INFO, "terminating normally\n");
|
||||
|
||||
fclose(stderr);
|
||||
|
||||
closelog();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* End $Id: nsplitd.c,v 2.6 1998/09/17 14:28:37 sde1000 Exp $ */
|
||||