|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T t
Length: 16872 (0x41e8) Types: TextFile Names: »tp0bridge.c«
└─⟦3d0c2be1b⟧ Bits:30001254 ISODE-5.0 Tape └─⟦eba4602b1⟧ »./isode-5.0.tar.Z« └─⟦d3ac74d73⟧ └─⟦this⟧ »isode-5.0/others/tp0bridge/tp0bridge.c«
/* tp0bridge.c - TCP/X.25 TP0 bridge */ #ifndef lint static char *rcsid = "$Header: /f/osi/others/tp0bridge/RCS/tp0bridge.c,v 6.0 89/03/18 23:36:31 mrose Rel $"; #endif /* * $Header: /f/osi/others/tp0bridge/RCS/tp0bridge.c,v 6.0 89/03/18 23:36:31 mrose Rel $ * * Contributed by Julian Onions, Nottingham University in the UK * * * $Log: tp0bridge.c,v $ * Revision 6.0 89/03/18 23:36:31 mrose * Release 5.0 * */ /* * NOTICE * * Acquisition, use, and distribution of this module and related * materials are subject to the restrictions of a license agreement. * Consult the Preface in the User's Manual for the full terms of * this agreement. * */ #include <signal.h> #include <stdio.h> #include <varargs.h> #include <isode/tpkt.h> #include <sys/ioctl.h> #ifdef BSD42 #include <sys/file.h> #endif #ifdef SYS5 #include <fcntl.h> #endif #include <isode/internet.h> #include <isode/x25.h> #include <isode/logger.h> #include <isode/tailor.h> /* \f */ static int debug = 0; static int options = 0; static int nbits = FD_SETSIZE; static LLog _pgm_log = { "tp0bridge.log", NULLCP, NULLCP, LLOG_FATAL | LLOG_EXCEPTIONS | LLOG_NOTICE, LLOG_FATAL, -1, LLOGCLS | LLOGCRT | LLOGZER, NOTOK }; LLog *pgm_log = &_pgm_log; static char *myname = "tp0bridge"; static char myhost[64]; static char *myprotocol = "tcp"; static char *myservice = "x25bridge"; static int tcp_fd; static int nfds; static fd_set ifds; static struct sockaddr_in main_in_socket; static struct sockaddr_in *mainisock = &main_in_socket; static struct sockaddr_in emptyaddr; static fd_set sentinel; static int sent2list[FD_SETSIZE]; static int list2sent[FD_SETSIZE]; static struct sockaddr_in callbacks[FD_SETSIZE]; #ifdef CAMTEC static struct NSAPaddr listens[FD_SETSIZE]; #define FORK_LISTENER /* new process per listener */ #endif void abortfd (), shuffle (); void adios (), advise (); #ifdef BSD42 int chldser (); #else int alrmser (); #endif extern int errno; /* \f */ /* ARGSUSED */ main (argc, argv, envp) int argc; char **argv, **envp; { int fd; fd_set mask; arginit (argv); envinit (); nfds = 0; FD_ZERO (&ifds); FD_ZERO (&sentinel); if ((tcp_fd = start_tcp_server (mainisock, SOMAXCONN, options & SO_DEBUG ? SO_DEBUG : 0, SO_KEEPALIVE)) == NOTOK) adios ("failed", "start_tcp_server"); FD_SET (tcp_fd, &ifds); if (tcp_fd >= nfds) nfds = tcp_fd + 1; #ifdef BSD42 (void) signal (SIGCHLD, chldser); #endif for (;;) { mask = ifds; #ifdef CAMTEC /* due to problems in select when camtec is enabled, a small timeout is given. This should not affect anything I hope. */ (void) xselect (nfds, &mask, NULLFD, NULLFD, 1); #else (void) xselect (nfds, &mask, NULLFD, NULLFD, NOTOK); #endif for (fd = 0; fd < nbits; fd++) if (FD_ISSET (fd, &mask)) { if (fd == tcp_fd) do_new_fd (); else if (FD_ISSET (fd, &sentinel)) abortfd (fd); else do_old_fd (fd); } #ifndef BSD42 while (mywait3 (NULLIP) != NOTOK) continue; #endif } } /* \f */ static do_new_fd () { int fd; char c; struct sockaddr_in zosock; struct sockaddr_in *osock = & zosock; if ((fd = join_tcp_client (tcp_fd, osock)) == NOTOK) { if (errno != EINTR) advise (LLOG_EXCEPTIONS, "failed", "join_tcp_client"); return; } if (read_tcp_socket (fd, &c, 1) != 1) { advise (LLOG_EXCEPTIONS, "failed", "initial read_tcp_socket"); goto out; } switch (c) { case 1: #ifdef DEBUG advise (LLOG_DEBUG, NULLCP, "outgoing connection"); #endif switch (fork ()) { case OK: do_outgoing (fd); _exit (1); /* NOTREACHED */ case NOTOK: advise (LLOG_EXCEPTIONS, "TCP socket", "no forks, so rejecting connection on"); default: (void) close_tcp_socket (fd); #ifdef EXOS FD_CLR (tcp_fd, &ifds); if ((tcp_fd = start_tcp_server (isock, SOMAXCONN, options & SO_DEBUG ? SO_DEBUG : 0, SO_KEEPALIVE)) == NOTOK) adios ("failed", "start_tcp_server"); FD_SET (tcp_fd, &ifds); if (tcp_fd >= nfds) nfds = tcp_fd + 1; #endif break; } break; case 2: #ifdef DEBUG advise (LLOG_DEBUG, NULLCP, "setup listen address"); #endif do_listen (fd); break; default: advise (LLOG_NOTICE, NULLCP, "unknown dialogue mode 0x%x", c); out: ; (void) close_tcp_socket (fd); break; } } /* \f */ static do_outgoing (fd) int fd; { int sd; struct NSAPaddr znsap; register struct NSAPaddr *nsap = &znsap; #ifdef SOCKETS (void) close_tcp_socket (tcp_fd); #endif for (sd = 0; sd < nbits; sd++) if (sd != fd && FD_ISSET (sd, &ifds)) (void) close (sd); #ifdef BSD42 (void) signal (SIGCHLD, SIG_DFL); #endif (void) ll_close (pgm_log); if (bridge_read_nsap_addr (fd, nsap, read_tcp_socket) == NOTOK) adios ("failed", "read of NSAP"); switch (nsap -> na_type) { case NA_BRG: nsap -> na_type = NA_X25; /* we use real X.25 here */ break; case NA_X25: break; case NA_NSAP: case NA_TCP: default: adios (NULLCP, "Addressing style not supported (type %d)", nsap -> na_type); break; } #ifdef DEBUG advise(LLOG_DEBUG, NULLCP, "x25 call on to %*s\n", nsap->na_dtelen, nsap->na_dte); #endif if ((sd = start_x25_client (nsap)) == NOTOK) adios ("failed", "start_x25_client"); if (join_x25_server (sd, nsap) == NOTOK) adios ("failed", "join_x25_server"); transfer (sd, fd); } /* \f */ static do_listen (fd) int fd; { struct sockaddr_in in_socket; register struct sockaddr_in *isock = &in_socket; struct NSAPaddr znsap; register struct NSAPaddr *nsap = &znsap; int newfd; if (bridge_read_nsap_addr (fd, nsap, read_tcp_socket) == NOTOK) { advise (LLOG_EXCEPTIONS, "failed", "read of NSAP"); goto out; } switch (nsap -> na_type) { case NA_BRG: nsap -> na_type = NA_X25; /* we use real X.25 here */ break; case NA_X25: break; case NA_NSAP: case NA_TCP: default: adios (NULLCP, "Addressing style not supported (type %d)", nsap -> na_type); break; } #ifdef DEBUG advise (LLOG_DEBUG, NULLCP, "type=%d Listening on '%s' len=%d", nsap -> na_type, nsap -> na_dte, nsap -> na_dtelen); advise (LLOG_DEBUG, NULLCP, "pid='%s'(%d) fac='%s'(%d) cudf='%s'(%d)", nsap -> na_pid, nsap -> na_pidlen, nsap -> na_fac, nsap -> na_faclen, nsap -> na_pid, nsap -> na_pidlen, nsap -> na_cudf, nsap -> na_cudflen); #endif if (readx (fd, (char *) isock, sizeof *isock, read_tcp_socket) != sizeof *isock) { advise (LLOG_EXCEPTIONS, "failed", "read_tcp_socket of sockaddr_in"); goto out; } isock -> sin_family = ntohs (isock -> sin_family); #ifdef FORK_LISTENER switch (fork ()) { case OK: { int i; for (i = 0; i < nbits; i++) if (i != fd && FD_ISSET (i, &ifds)) (void) close (i); break; } case NOTOK: advise (LLOG_EXCEPTIONS, "X25 socket", "no forks, so rejecting listen on"); default: (void) close_tcp_socket (fd); return; } /* more from the 'stamp out boring names' committee */ #define iso_defining_new_protocols 1 while (iso_defining_new_protocols) { #endif if ((newfd = start_x25_server (nsap, SOMAXCONN, options & SO_DEBUG ? SO_DEBUG : 0, SO_KEEPALIVE)) == NOTOK) { advise (LLOG_EXCEPTIONS, "failed", "start_x25_server"); #ifdef FORK_LISTENER _exit (0); #endif return; } #ifdef CAMTEC listens[newfd] = *nsap; /* struct copy */ #endif callbacks[newfd] = *isock; /* struct copy */ /* set up the admin stuff */ FD_SET (newfd, &ifds); /* listen for new connections */ FD_SET (fd, &ifds); /* listen for problems */ FD_SET (fd, &sentinel); sent2list[fd] = newfd; list2sent[newfd] = fd; if (newfd >= nfds) nfds = newfd + 1; #ifdef FORK_LISTENER do_old_fd (newfd); (void) close (newfd); } /* loop again */ #endif return; out: ; (void) close_tcp_socket (fd); } /* \f */ static do_old_fd (fd) int fd; { int sd; register struct sockaddr_in *isock = &callbacks[fd]; struct NSAPaddr znsap; register struct NSAPaddr *nsap = &znsap; #ifdef DEBUG advise (LLOG_DEBUG, NULLCP, "callback"); #endif if (isock == NULL || isock -> sin_family != AF_INET) { advise (LLOG_EXCEPTIONS, NULLCP, "Callback has bogus address"); return; } if ((sd = join_x25_client (fd, nsap)) == NOTOK) { if (errno != EINTR) { advise (LLOG_EXCEPTIONS, "failed", "join_x25_client"); abortfd (list2sent[fd]); } return; } #ifdef DEBUG advise (LLOG_DEBUG, NULLCP, "type=%d Accepted '%s' len=%d", nsap -> na_type, nsap -> na_dte, nsap -> na_dtelen); advise (LLOG_DEBUG, NULLCP, "pid='%s'(%d) fac='%s'(%d) cudf='%s'(%d)", nsap -> na_pid, nsap -> na_pidlen, nsap -> na_fac, nsap -> na_faclen, nsap -> na_pid, nsap -> na_pidlen, nsap -> na_cudf, nsap -> na_cudflen); #endif nsap -> na_type = NA_BRG; #ifdef CAMTEC /* get back addressing info for this fd into nsap */ nsap = &listens[fd]; #endif switch (fork ()) { case OK: break; case NOTOK: advise (LLOG_EXCEPTIONS, "X.25 socket", "no forks, so rejecting connection on"); default: (void) close (sd); return; } #ifndef CAMTEC (void) close (fd); #endif for (fd = 0; fd < nbits; fd++) if (fd != sd && FD_ISSET (fd, &ifds)) (void) close (fd); #ifdef BSD42 (void) signal (SIGCHLD, SIG_DFL); #endif (void) ll_close (pgm_log); #ifdef DEBUG advise (LLOG_DEBUG, NULLCP, "connecting to %s", inet_ntoa (isock -> sin_addr)); advise (LLOG_DEBUG, NULLCP, "port=%d", (int) ntohs (isock -> sin_port)); #endif if ((fd = start_tcp_client ((struct sockaddr_in *) NULL, 0)) == NOTOK) adios ("failed", "start_tcp_client"); if (join_tcp_server (fd, isock) == NOTOK) adios ("failed", "join_tcp_server"); if (bridge_write_nsap_addr (fd, nsap, write_tcp_socket) == NOTOK) adios ("failed", "write of NSAP"); transfer (sd, fd); _exit (1); /* NOTREACHED */ } /* \f */ static transfer (sd, fd) int sd, fd; { int mfds; fd_set rfds, mask; struct tsapblk *tcpb, *x25b; FD_ZERO (&rfds); mfds = (sd > fd ? sd : fd) + 1; FD_SET (sd, &rfds); FD_SET (fd, &rfds); if ((tcpb = newtblk ()) == NULL) adios (NULLCP, "out of memory"); tcpb -> tb_fd = fd; (void) TTService (tcpb); if ((x25b = newtblk ()) == NULL) adios (NULLCP, "out of memory"); x25b -> tb_fd = sd; (void) XTService (x25b); #ifndef CAMTEC for (;;) { mask = rfds; if (xselect (mfds, &mask, NULLFD, NULLFD, NOTOK) == NOTOK) adios ("failed", "xselect"); if (FD_ISSET (sd, &mask)) shuffle (x25b, tcpb); if (FD_ISSET (fd, &mask)) shuffle (tcpb, x25b); } #else for (;;) { FD_ZERO (&mask); mfds = fd + 1; FD_SET (fd, &mask); if (xselect (mfds, &mask, NULLFD, NULLFD, 1) == NOTOK) adios ("failed", "xselect tcp"); if (FD_ISSET (fd, &mask)) { advise (LLOG_DEBUG, NULLCP, "tcp -> x25"); shuffle (tcpb, x25b); } FD_ZERO (&mask); mfds = sd + 1; FD_SET (sd, &mask); if (xselect (mfds, &mask, NULLFD, NULLFD, 1) == NOTOK) adios ("failed", "xselect x25"); if (FD_ISSET (sd, &mask)) { advise (LLOG_DEBUG, NULLCP, "x25 -> tcp"); shuffle (x25b, tcpb); } } #endif } /* \f */ static void shuffle (from, to) register struct tsapblk *from, *to; { register struct udvec *uv; register struct tsapkt *t; if ((t = fd2tpkt (from -> tb_fd, from -> tb_initfnx, from -> tb_readfnx)) == NULL || t -> t_errno != OK) adios (NULLCP, "fd2tpkt failed (%d)", t ? t -> t_errno : NOTOK); #ifdef DEBUG advise (LLOG_DEBUG, NULLCP, "read: code=0x%x user len=%d", TPDU_CODE (t), t -> t_qbuf ? t -> t_qbuf -> qb_len : 0); #endif uv = t -> t_udvec; if (t -> t_qbuf) { uv -> uv_base = t -> t_qbuf -> qb_data; uv -> uv_len = t -> t_qbuf -> qb_len; uv++; } uv -> uv_base = NULL; if (tpkt2fd (to -> tb_fd, t, to -> tb_writefnx) == NOTOK) adios (NULLCP, "tpkt2fd failed (%d)", t -> t_errno); freetpkt (t); } static void abortfd (fd) int fd; { int assocfd = sent2list[fd]; /* get fd that is listening on */ #ifdef DEBUG advise (LLOG_DEBUG, NULLCP, "Shutdown listen (%d,%d)", fd, assocfd); #endif FD_CLR (fd, &sentinel); FD_CLR (fd, &ifds); FD_CLR (assocfd, &ifds); (void) close_tcp_socket (fd); (void) close_x25_socket (assocfd); sent2list[fd] = -1; list2sent[assocfd] = -1; callbacks[assocfd] = emptyaddr; /* struct copy */ } /* \f */ static arginit (vec) char **vec; { int port; register char *ap; struct hostent *hp; struct servent *sp; if (myname = rindex (*vec, '/')) myname++; if (myname == NULL || *myname == NULL) myname = *vec; isodetailor (myname, 0); ll_hdinit (pgm_log, myname); (void) gethostname (myhost, sizeof myhost); if (hp = gethostbyname (myhost)) (void) strcpy (myhost, hp -> h_name); if ((sp = getservbyname (myservice, myprotocol)) == NULL) mainisock -> sin_port = x25_bridge_port; else mainisock -> sin_port = sp -> s_port; mainisock -> sin_family = AF_INET; mainisock -> sin_addr.s_addr = INADDR_ANY; if ((nbits = getdtablesize ()) > FD_SETSIZE) nbits = FD_SETSIZE; for (vec++; ap = *vec; vec++) { if (*ap == '-') switch (*++ap) { case 'd': options |= SO_DEBUG; pgm_log -> ll_events |= LLOG_ALL; continue; case 'p': if ((ap = *++vec) == NULL || *ap == '-' || (port = atoi (ap)) <= 0) adios (NULLCP, "usage: %s -p portno", myname); mainisock -> sin_port = htons ((u_short) port); continue; default: adios (NULLCP, "-%s: unknown switch", ap); } adios (NULLCP, "usage: %s [switches]", myname); } } /* \f */ static envinit () { int i, sd; if (!(debug = isatty (2))) { for (i = 0; i < 5; i++) { switch (fork ()) { case NOTOK: sleep (5); continue; case OK: break; default: _exit (0); } break; } (void) chdir ("/"); if ((sd = open ("/dev/null", O_RDWR)) == NOTOK) adios ("/dev/null", "unable to read"); if (sd != 0) (void) dup2 (sd, 0), (void) close (sd); (void) dup2 (0, 1); (void) dup2 (0, 2); #ifdef TIOCNOTTY if ((sd = open ("/dev/tty", O_RDWR)) != NOTOK) { (void) ioctl (sd, TIOCNOTTY, NULLCP); (void) close (sd); } #endif } else ll_dbinit (pgm_log, myname); #ifndef sun /* damn YP... */ for (sd = 3; sd < nbits; sd++) (void) close (sd); #endif (void) signal (SIGPIPE, SIG_IGN); ll_hdinit (pgm_log, myname); advise (LLOG_NOTICE, NULLCP, "starting"); #ifdef DEBUG advise (LLOG_DEBUG, NULLCP, "options=0x%x port=%d", options, ntohs (mainisock -> sin_port)); #endif } /* \f Berkeley UNIX: 4.2 */ #ifdef BSD42 #include <sys/wait.h> /* ARGSUSED */ static int chldser (sig, code, sc) int sig; long code; struct sigcontext *sc; { union wait status; while (wait3 (&status, WNOHANG, (struct rusage *) NULL) > 0) continue; } #else /* \f AT&T UNIX: 5 */ #include <setjmp.h> #define WAITSECS ((unsigned) 2) static jmp_buf jmpenv; /* ARGSUSED */ static int alrmser (sig) int sig; { (void) signal (SIGALRM, alrmser); longjmp (jmpenv, NOTOK); } static int mywait3 (status) int *status; { int result; switch (setjmp (jmpenv)) { case OK: (void) signal (SIGALRM, alrmser); (void) alarm (WAITSECS); result = wait (status); (void) alarm (0); break; default: result = NOTOK; break; } return result; } #endif /* \f */ static int readx (fd, buffer, n, readfnx) int fd; char *buffer; int n; IFP readfnx; { register int i, cc; register char *bp; for (bp = buffer, i = n; i > 0; bp += cc, i -= cc) { switch (cc = (*readfnx) (fd, bp, i)) { case NOTOK: return (i = bp - buffer) ? i : NOTOK; case OK: break; default: continue; } break; } return (bp - buffer); } /* \f ERRORS */ #ifndef lint void adios (va_alist) va_dcl { va_list ap; va_start (ap); _ll_log (pgm_log, LLOG_FATAL, ap); va_end (ap); _exit (1); } #else /* VARARGS */ void adios (what, fmt) char *what, *fmt; { adios (what, fmt); } #endif #ifndef lint void advise (va_alist) va_dcl { int code; va_list ap; va_start (ap); code = va_arg (ap, int); _ll_log (pgm_log, code, ap); va_end (ap); } #else /* VARARGS */ void advise (code, what, fmt) char *what, *fmt; int code; { advise (code, what, fmt); } #endif