|
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: 32368 (0x7e70) Types: TextFile Names: »tsaplisten.c«
└─⟦3d0c2be1b⟧ Bits:30001254 ISODE-5.0 Tape └─⟦eba4602b1⟧ »./isode-5.0.tar.Z« └─⟦d3ac74d73⟧ └─⟦this⟧ »isode-5.0/tsap/tsaplisten.c«
/* tsaplisten.c - "network" listening */ #ifndef lint static char *rcsid = "$Header: /f/osi/tsap/RCS/tsaplisten.c,v 6.1 89/03/23 22:28:17 mrose Exp $"; #endif /* * $Header: /f/osi/tsap/RCS/tsaplisten.c,v 6.1 89/03/23 22:28:17 mrose Exp $ * * * $Log: tsaplisten.c,v $ * Revision 6.1 89/03/23 22:28:17 mrose * out-the-door * * Revision 6.0 89/03/18 23:45:33 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. * */ /* LINTLIBRARY */ #include <errno.h> #include <stdio.h> #include <signal.h> #include "tailor.h" #include "tpkt.h" #include <sys/ioctl.h> #ifdef BSD42 #include <sys/file.h> #endif #ifdef SYS5 #include <fcntl.h> #endif #ifdef TCP #include "internet.h" #endif #ifdef X25 #include "x25.h" #endif #ifdef CONS #include "cons.h" #endif #ifdef TP4 #include "tp4.h" #endif /* \f DATA */ struct listenblk { struct listenblk *lb_forw; /* doubly-linked list */ struct listenblk *lb_back; /* .. */ int lb_fd; /* network handle */ #define LISTEN_EXCEPTED (-2) /* magic value */ int lb_type; /* either listener, or exception handler */ #define LB_UNDEF 0 #define LB_LISTEN 1 #define LB_EXCEPTION 2 struct TSAPaddr lb_addr; /* transport address */ union { #ifdef TCP struct sockaddr_in lb_un_isock; #endif #if defined(X25) || defined(BRIDGE_X25) struct NSAPaddr lb_un_xsock; #endif #ifdef CONS struct NSAPaddr lb_un_nsock; #endif #ifdef TP4 struct TSAPaddr lb_un_tsock; #endif int lb_dummy; } lb_un1; #define lb_isock lb_un1.lb_un_isock #define lb_xsock lb_un1.lb_un_xsock #define lb_nsock lb_un1.lb_un_nsock #define lb_tsock lb_un1.lb_un_tsock union { IFP lb_un_accept; /* accept function */ IFP lb_un_except; /* exception function */ } lb_un2; #define lb_accept lb_un2.lb_un_accept #define lb_except lb_un2.lb_un_except IFP lb_close; /* close function */ }; #define NULLLBP ((struct listenblk *) 0) static int once_only = 0; static struct listenblk listenque; static struct listenblk *LHead = &listenque; struct listenblk *findlblk (), *newlblk (); /* * Event block abstraction. An event block is generated by interfaces * that might need to do things occasionally. Currently this is only * the bridge but other things should be slot inable. * The idea is you but a listenblk of the exception type on a fd. * If the fd `goes off' the listenblk is destroyed and an eventblk * created which will be called every 60 seconds for blocking listens, * and before each listen otherwise. */ struct eventblk { struct eventblk *ev_forw; /* doubly-linked list */ struct eventblk *ev_back; /* .. */ struct TSAPaddr ev_taddr; /* associated address */ IFP ev_eventfnc; /* the function to call */ }; #define NULLEVP ((struct eventblk *) 0) static struct eventblk eventqueue; static struct eventblk *EHead = &eventqueue; static int ev_onceonly = 0; static int ev_count = 0; struct eventblk *neweblk (); #define add_fd(fd) \ { \ if ((fd) >= acl_nfds) \ acl_nfds = (fd) + 1; \ if (acl_count++ == 0) \ FD_ZERO (&acl_mask); \ FD_SET (fd, &acl_mask); \ } #define del_fd(fd) \ { \ if ((fd) + 1 == acl_nfds) \ acl_nfds--; \ if (--acl_count == 0) \ acl_nfds = 0; \ FD_CLR (fd, &acl_mask); \ } static int acl_nfds = 0; static int acl_count = 0; static fd_set acl_mask; int startlb (), uniqlb (); /* \f */ #ifdef TCP int tcplisten (), tcpaccept (), tcpunique (); #endif #ifdef X25 int x25listen (), x25accept (), x25unique (); #endif #ifdef CONS int conslisten (), consaccept (), consunique (); #endif #ifdef BRIDGE_X25 int bridgelisten (), bridgeaccept (), bridgeunique (); int close_bridge_socket (), bridge_except (); #endif #ifdef TP4 int tp4listen (), tp4accept (), tp4unique (); #endif static struct nsapent { int ns_type; int ns_stack; IFP ns_listen; IFP ns_accept; IFP ns_unique; IFP ns_close; } nsaps[] = { #ifdef TCP NA_TCP, TS_TCP, tcplisten, tcpaccept, tcpunique, close_tcp_socket, #endif #ifdef X25 NA_X25, TS_X25, x25listen, x25accept, x25unique, close_x25_socket, #endif #ifdef CONS NA_NSAP, TS_CONS, conslisten, consaccept, consunique, close_cons_socket, #endif #ifdef BRIDGE_X25 NA_BRG, TS_BRG, bridgelisten, bridgeaccept, bridgeunique, close_bridge_socket, #endif #ifdef TP4 NA_NSAP, TS_TP4, tp4listen, tp4accept, tp4unique, close_tp4_socket, #endif NULL }; SFD chldser (); extern int errno; /* \f */ int TNetListen (ta, td) register struct TSAPaddr *ta; struct TSAPdisconnect *td; { return TNetWork (ta, td, startlb); } int TNetUnique (ta, td) register struct TSAPaddr *ta; struct TSAPdisconnect *td; { return TNetWork (ta, td, uniqlb); } /* \f */ static int TNetWork (ta, td, fnx) register struct TSAPaddr *ta; struct TSAPdisconnect *td; IFP fnx; { register int n; int fd, fds[NTADDR]; register struct NSAPaddr *na; register struct nsapent *ns; if ((n = ta -> ta_naddr) > NTADDR) return tsaplose (td, DR_PARAMETER, NULLCP, "illegal number of network addresses"); if (n == 0) { if (fnx == startlb) { for (ns = nsaps; ns -> ns_listen; ns++) if (ns -> ns_type == NA_NSAP && (ns -> ns_stack & ts_stacks)) break; if (!ns -> ns_listen) return tsaplose (td, DR_PARAMETER, NULLCP, "unsupported network address (%d)", NA_NSAP); return (*fnx) (ta, NULLNA, ns, td); } na = ta -> ta_addrs; for (ns = nsaps; ns -> ns_listen; ns++) if (ns -> ns_stack & ts_stacks) { na -> na_type = ns -> ns_type; na++; } if ((n = ta -> ta_naddr = na - ta -> ta_addrs) == 0) return tsaplose (td, DR_PARAMETER, NULLCP, "no transport stacks active!?!"); } for (na = ta -> ta_addrs; n > 0; na++) { for (ns = nsaps; ns -> ns_listen; ns++) if (ns -> ns_type == na -> na_type && (ns -> ns_stack & ts_stacks)) break; if (!ns -> ns_listen) { (void) tsaplose (td, DR_PARAMETER, NULLCP, "unsupported network address (%d) at offset %d", na -> na_type, n - 1); goto out; } if ((fd = (*fnx) (ta, na, ns, td)) == NOTOK) goto out; fds[--n] = fd; } return OK; out: ; while (n < ta -> ta_naddr) { register struct listenblk *lb; fd = fds[n++]; if (once_only == 0) continue; for (lb = LHead -> lb_forw; lb != LHead; lb = lb -> lb_forw) if (lb -> lb_fd == fd) { freelblk (lb); break; } } return NOTOK; } /* \f */ static int startlb (ta, na, ns, td) register struct TSAPaddr *ta; register struct NSAPaddr *na; register struct nsapent *ns; struct TSAPdisconnect *td; { struct TSAPaddr tas; register struct listenblk *lb; bzero ((char *) &tas, sizeof tas); bcopy (ta -> ta_selector, tas.ta_selector, tas.ta_selectlen = ta -> ta_selectlen); if (na) { tas.ta_naddr = 1; tas.ta_addrs[0] = *na; /* struct copy */ } ta = &tas; if (lb = findlblk (ta, LB_LISTEN)) return tsaplose (td, DR_OPERATION, NULLCP, "already listening on that transport address"); if ((lb = newlblk (LB_LISTEN, ta)) == NULLLBP) return tsaplose (td, DR_CONGEST, NULLCP, NULLCP); lb -> lb_accept = ns -> ns_accept; lb -> lb_close = ns -> ns_close; if ((lb -> lb_fd = (*ns -> ns_listen) (lb, ta, td)) == NOTOK) { freelblk (lb); return NOTOK; } else if (lb -> lb_fd == LISTEN_EXCEPTED) lb -> lb_fd = NOTOK; else add_fd (lb -> lb_fd); return OK; } /* \f */ static int uniqlb (ta, na, ns, td) register struct TSAPaddr *ta; register struct NSAPaddr *na; register struct nsapent *ns; struct TSAPdisconnect *td; { int fd; struct TSAPaddr tas; register struct listenblk *lb; bzero ((char *) &tas, sizeof tas); bcopy (ta -> ta_selector, tas.ta_selector, tas.ta_selectlen = ta -> ta_selectlen); tas.ta_naddr = 1; tas.ta_addrs[0] = *na; /* struct copy */ if ((fd = (*ns -> ns_unique) (&tas, td)) == NOTOK) return NOTOK; bcopy (tas.ta_selector, ta -> ta_selector, ta -> ta_selectlen = tas.ta_selectlen); *na = tas.ta_addrs[0]; /* struct copy */ ta = &tas; if ((lb = newlblk (LB_LISTEN, ta)) == NULLLBP) return tsaplose (td, DR_CONGEST, NULLCP, NULLCP); lb -> lb_fd = fd; lb -> lb_accept = ns -> ns_accept; lb -> lb_close = ns -> ns_close; add_fd (lb -> lb_fd); return OK; } /* \f */ int TNetAccept (vecp, vec, nfds, rfds, wfds, efds, secs, td) int *vecp; char **vec; int nfds; fd_set *rfds, *wfds, *efds; int secs; struct TSAPdisconnect *td; { int accepted, fd, n, xsecs; fd_set ifds, ofds, xfds; register struct listenblk *lb; static int inited = 0; if (!inited) { #ifdef BSD42 (void) signal (SIGCHLD, chldser); #else (void) signal (SIGCLD, SIG_IGN); #endif inited = 1; } *vecp = 0; *vec = NULL; if (acl_count == 0 && ev_count == 0) return xselect (nfds, rfds, wfds, efds, secs); ifds = acl_mask; FD_ZERO (&ofds); FD_ZERO (&xfds); if (acl_nfds >= nfds) nfds = acl_nfds + 1; if (rfds) for (fd = 0; fd < nfds; fd++) if (FD_ISSET (fd, rfds)) FD_SET (fd, &ifds); if (wfds) ofds = *wfds; /* struct copy */ if (efds) xfds = *efds; /* struct copy */ for (;;) { xsecs = secs; if (ev_count) { if (secs == NOTOK) xsecs = 60; /* infinite timeout, arrange for periodic */ else check_events (); /* single attempt */ } switch (n = xselect (nfds, &ifds, wfds, efds, xsecs)) { case OK: if (secs == NOTOK && ev_count) { /* just a timeout */ check_events (); goto next; } if (rfds) *rfds = ifds; /* struct copy */ return OK; case NOTOK: return tsaplose (td, DR_UNKNOWN, "failed", "xselect"); default: accepted = 0; for (lb = LHead -> lb_forw; lb != LHead; lb = lb -> lb_forw) { fd = lb -> lb_fd; if (FD_ISSET (fd, &ifds)) { switch (lb -> lb_type) { case LB_LISTEN: if ((*lb -> lb_accept) (lb, vecp, vec, td) == NOTOK) return NOTOK; if (n-- == 1 && *vecp == 0) goto next; accepted++; break; case LB_EXCEPTION: if (exception (lb, td) == NOTOK) return NOTOK; break; default: return tsaplose (td, DR_UNKNOWN, NULLCP, "invalid block type"); } FD_CLR (fd, &ifds); } } if (!accepted) { for (fd = 0 ; fd < nfds; fd++) if (FD_ISSET (fd, &ifds) || (wfds && FD_ISSET (fd, wfds)) || (efds && FD_ISSET (fd, efds))) break; if (fd >= nfds) goto next; } if (rfds) *rfds = ifds; return n; } next: ; if (acl_nfds >= nfds) nfds = acl_nfds + 1; ifds = acl_mask; if (rfds) for (fd = 0; fd < nfds; fd++) if (FD_ISSET (fd, rfds)) FD_SET (fd, &ifds); if (wfds) *wfds = ofds; if (efds) *efds = xfds; } } /* \f */ static int exception (lb, td) struct listenblk *lb; struct TSAPdisconnect *td; { register struct listenblk *lb2; register struct eventblk *eb; if ((lb2 = findlblk (&lb -> lb_addr, LB_LISTEN)) != NULLLBP) freelblk (lb2); if ((eb = neweblk (&lb -> lb_addr)) == NULLEVP) return tsaplose (td, DR_CONGEST, NULLCP, "Out of memory"); eb -> ev_eventfnc = lb -> lb_except; SLOG (tsap_log, LLOG_EXCEPTIONS, NULLCP, ("exception on %s", taddr2str (&lb -> lb_addr))); freelblk (lb); return OK; } static check_events () { register struct eventblk *eb; struct TSAPdisconnect tds; for (eb = EHead -> ev_forw; eb != EHead; eb = eb -> ev_forw) (void) (*eb -> ev_eventfnc) (eb, &tds); } /* \f */ int TNetClose (ta, td) register struct TSAPaddr *ta; struct TSAPdisconnect *td; { register struct listenblk *lb, *lp; if (ta == NULLTA) { if (once_only == 0) return OK; for (lb = LHead -> lb_forw; lb != LHead; lb = lp) { lp = lb -> lb_forw; freelblk (lb); } } else { if (ta -> ta_naddr > 1) { int gotone; register int n = ta -> ta_naddr; register struct NSAPaddr *na = ta -> ta_addrs; struct TSAPaddr tas; tas = *ta; /* struct copy */ tas.ta_naddr = 1; gotone = 0; for (na = ta -> ta_addrs, n = ta -> ta_naddr; n > 0; na++, n--) { tas.ta_addrs[0] = *na; /* struct copy */ if (lb = findlblk (&tas, LB_LISTEN)) { freelblk (lb); gotone = 1; } } if (!gotone) return tsaplose (td, DR_PARAMETER, NULLCP, "no such transport addressess"); return OK; } if ((lb = findlblk (ta, LB_LISTEN)) == NULLLBP) return tsaplose (td, DR_PARAMETER, NULLCP, "no such transport addressess"); freelblk (lb); } return OK; } /* \f */ #ifdef BSD42 #include <sys/wait.h> /* ARGSUSED */ static SFD chldser (sig, code, sc) int sig; long code; struct sigcontext *sc; { union wait status; while (wait3 (&status, WNOHANG, (struct rusage *) NULL) > 0) continue; } #endif /* \f */ int TNetFork (vecp, vec, td) int vecp; char **vec; struct TSAPdisconnect *td; { int pid; #ifdef TIOCNOTTY int sd; #endif switch (pid = fork ()) { case OK: break; case NOTOK: (void) tsaplose (td, DR_CONGEST, "connection", "unable to fork, so rejecting"); default: { struct TSAPstart tss; register struct TSAPstart *ts = &tss; register struct tsapblk *tb; if (TInit (vecp, vec, ts, td) == NOTOK) { SLOG (tsap_log, LLOG_EXCEPTIONS, NULLCP, ("TNetFork: TInit returns [%s]", TErrString (td -> td_reason))); return pid; } if ((tb = findtblk (ts -> ts_sd)) == NULL) { SLOG (tsap_log, LLOG_EXCEPTIONS, NULLCP, ("TNetFork: findtblk fails")); return pid; } (void) (*tb -> tb_closefnx) (tb -> tb_fd); tb -> tb_fd = NOTOK; freetblk (tb); } return pid; } (void) TNetClose (NULLTA, td); #ifdef TIOCNOTTY if ((sd = open ("/dev/tty", O_RDWR)) != NOTOK) { (void) ioctl (sd, TIOCNOTTY, NULLCP); (void) close (sd); } #else #ifdef SYS5 (void) setpgrp (); (void) signal (SIGINT, SIG_IGN); (void) signal (SIGQUIT, SIG_IGN); #endif #endif #ifdef BSD42 (void) signal (SIGCHLD, SIG_DFL); #else (void) signal (SIGCLD, SIG_DFL); #endif return OK; } /* \f TCP */ #ifdef TCP static int tcplisten (lb, ta, td) register struct listenblk *lb; register struct TSAPaddr *ta; struct TSAPdisconnect *td; { int fd; register struct sockaddr_in *isock = &lb -> lb_isock; register struct hostent *hp; register struct NSAPaddr *na; if (ta -> ta_naddr < 1) return tsaplose (td, DR_ADDRESS, NULLCP, "TCP address not specified"); na = ta -> ta_addrs; if (na -> na_domain[0]) { if ((hp = gethostbystring (na -> na_domain)) == NULL) return tsaplose (td, DR_ADDRESS, NULLCP, "%s: unknown host", na -> na_domain); } else hp = NULL; if (na -> na_port == 0) return tsaplose (td, DR_ADDRESS, NULLCP, "TCP port not specified"); bzero ((char *) isock, sizeof *isock); isock -> sin_family = hp ? hp -> h_addrtype : AF_INET; isock -> sin_port = na -> na_port; if (hp) inaddr_copy (hp, isock); switch (na -> na_tset) { case NA_TSET_TCP: default: if ((fd = start_tcp_server (isock, SOMAXCONN, 0, SO_KEEPALIVE)) == NOTOK) return tsaplose (td, DR_CONGEST, "failed", "start_tcp_server"); break; } lb -> lb_addr.ta_addrs -> na_tset = na -> na_tset; return fd; } /* \f */ static int tcpaccept (lb, vecp, vec, td) register struct listenblk *lb; int *vecp; char **vec; struct TSAPdisconnect *td; { int fd, tset = lb -> lb_addr.ta_addrs -> na_tset; #ifdef SOCKETS int len; #endif char buffer1[BUFSIZ], buffer2[BUFSIZ]; #ifdef SOCKETS struct sockaddr_in in_socket; struct sockaddr_in *isock = &in_socket; #endif struct sockaddr_in out_socket; register struct sockaddr_in *osock = &out_socket; struct hostent *hp; register struct tsapblk *tb; register struct tsapkt *t = NULL; switch (tset) { case NA_TSET_TCP: default: if ((fd = join_tcp_client (lb -> lb_fd, osock)) == NOTOK) return tsaplose (td, DR_NETWORK, "failed", "join_tcp_client"); #ifdef EXOS del_fd (lb -> lb_fd); if ((lb -> lb_fd = start_tcp_server (&lb -> lb_isock, SOMAXCONN, 0, SO_KEEPALIVE)) != NOTOK) { add_fd (lb -> lb_fd); } #endif break; } hp = gethostbyaddr ((char *) &osock -> sin_addr, sizeof osock -> sin_addr, osock -> sin_family); (void) strcpy (buffer1, hp ? hp -> h_name : inet_ntoa (osock -> sin_addr)); #ifdef SOCKETS len = sizeof *isock; if (getsockname (fd, (struct sockaddr *) isock, &len) != NOTOK) { hp = gethostbyaddr ((char *) &isock -> sin_addr, sizeof isock -> sin_addr, isock -> sin_family); (void) strcpy (buffer2, hp ? hp -> h_name : inet_ntoa (isock -> sin_addr)); } else #endif (void) strcpy (buffer2, TLocalHostName ()); if ((tb = newtblk ()) == NULL) { (void) tsaplose (td, DR_CONGEST, NULLCP, "out of memory"); goto out; } tb -> tb_fd = fd; (void) TTService (tb); if ((t = fd2tpkt (tb -> tb_fd, tb -> tb_initfnx, tb -> tb_readfnx)) == NULL || t -> t_errno != OK) { (void) tpktlose (tb, td, t ? t -> t_errno : DR_CONGEST, NULLCP, NULLCP); goto out; } if (TPDU_CODE (t) != TPDU_CR) { (void) tpktlose (tb, td, DR_PROTOCOL, NULLCP, "transport protocol mangled: expecting 0x%x, got 0x%x", TPDU_CR, TPDU_CODE (t)); goto out; } vec[0] = "tsaplisten"; /* any value will do */ if ((vec[1] = tcpsave (tb -> tb_fd, osock, buffer1, buffer2, td)) == NULL) goto out; if ((vec[2] = tpkt2str (t)) == NULL) { (void) tsaplose (td, DR_CONGEST, NULLCP, NULLCP); goto out; } vec[*vecp = 3] = NULLCP; tb -> tb_fd = NOTOK; freetblk (tb); freetpkt (t); return OK; out: ; if (tb) { tb -> tb_fd = NOTOK; freetblk (tb); } freetpkt (t); (void) (*lb -> lb_close) (fd); return NOTOK; } /* \f */ static int tcpunique (ta, td) register struct TSAPaddr *ta; struct TSAPdisconnect *td; { int fd; char *cp; struct sockaddr_in in_socket; register struct sockaddr_in *isock = &in_socket; register struct hostent *hp; register struct NSAPaddr *na = ta -> ta_addrs; cp = na -> na_domain[0] ? na -> na_domain : TLocalHostName (); if ((hp = gethostbystring (cp)) == NULL) return tsaplose (td, DR_ADDRESS, NULLCP, "%s: unknown host", cp); bzero ((char *) isock, sizeof *isock); isock -> sin_family = hp -> h_addrtype; inaddr_copy (hp, isock); switch (na -> na_tset) { case NA_TSET_TCP: default: if ((fd = start_tcp_server (isock, SOMAXCONN, 0, SO_KEEPALIVE)) == NOTOK) return tsaplose (td, DR_CONGEST, "failed", "start_tcp_server"); break; } #ifdef notdef (void) strncpy (na -> na_domain, hp -> h_name, sizeof na -> na_domain); #else (void) strcpy (na -> na_domain, inet_ntoa (isock -> sin_addr)); #endif na -> na_port = isock -> sin_port; return fd; } #endif /* \f X.25 */ #ifdef X25 /* ARGSUSED */ static int x25listen (lb, ta, td) struct listenblk *lb; struct TSAPaddr *ta; struct TSAPdisconnect *td; { int fd; if (ta -> ta_naddr < 1) return tsaplose (td, DR_ADDRESS, NULLCP, "X.121 DTE not specified"); if ((fd = start_x25_server (ta -> ta_addrs, SOMAXCONN, 0, SO_KEEPALIVE)) == NOTOK) return tsaplose (td, DR_CONGEST, "failed", "start_x25_server"); lb -> lb_xsock = *ta -> ta_addrs; return fd; } /* \f */ static int x25accept (lb, vecp, vec, td) register struct listenblk *lb; int *vecp; char **vec; struct TSAPdisconnect *td; { int fd; struct NSAPaddr out_socket; register struct NSAPaddr *osock = &out_socket; register struct NSAPaddr *xsock = &lb -> lb_xsock; register struct tsapblk *tb; register struct tsapkt *t = NULL; if ((fd = join_x25_client (lb -> lb_fd, osock)) == NOTOK) return tsaplose (td, DR_NETWORK, "failed", "join_x25_client"); if ((tb = newtblk ()) == NULL) { (void) tsaplose (td, DR_CONGEST, NULLCP, "out of memory"); goto out; } tb -> tb_fd = fd; (void) XTService (tb); if ((t = fd2tpkt (tb -> tb_fd, tb -> tb_initfnx, tb -> tb_readfnx)) == NULL || t -> t_errno != OK) { (void) tpktlose (tb, td, t ? t -> t_errno : DR_CONGEST, NULLCP, NULLCP); goto out; } if (TPDU_CODE (t) != TPDU_CR) { (void) tpktlose (tb, td, DR_PROTOCOL, NULLCP, "transport protocol mangled: expecting 0x%x, got 0x%x", TPDU_CR, TPDU_CODE (t)); goto out; } vec[0] = "tsaplisten"; /* any value will do */ if ((vec[1] = x25save (tb -> tb_fd, osock -> na_dte, osock -> na_dtelen, xsock -> na_dte, xsock -> na_dtelen, td)) == NULL) goto out; if ((vec[2] = tpkt2str (t)) == NULL) { (void) tsaplose (td, DR_CONGEST, NULLCP, NULLCP); goto out; } vec[*vecp = 3] = NULLCP; tb -> tb_fd = NOTOK; freetblk (tb); freetpkt (t); return OK; out: ; if (tb) { tb -> tb_fd = NOTOK; freetblk (tb); } freetpkt (t); (void) (*lb -> lb_close) (fd); return NOTOK; } /* \f */ static int x25unique (ta, td) struct TSAPaddr *ta; struct TSAPdisconnect *td; { int fd; register struct NSAPaddr *na = ta -> ta_addrs; bzero ((char *) na, sizeof *na); na -> na_type = NA_X25; if ((fd = start_x25_server (na, SOMAXCONN, 0, SO_KEEPALIVE)) == NOTOK) return tsaplose (td, DR_CONGEST, "failed", "start_x25_server"); return fd; } #endif /* \f */ #ifdef BRIDGE_X25 /* ARGSUSED */ static int bridgelisten (lb, ta, td) register struct listenblk *lb; register struct TSAPaddr *ta; struct TSAPdisconnect *td; { int fd; register struct eventblk *eb; if ((fd = bridgelisten_aux (lb, ta, td)) != NOTOK) return fd; if ((eb = neweblk (ta)) == NULLEVP) return tsaplose (td, DR_CONGEST, NULLCP, "out of memory"); eb -> ev_eventfnc = bridge_except; return LISTEN_EXCEPTED; } static int bridge_except (eb, td) register struct eventblk *eb; struct TSAPdisconnect *td; { register struct listenblk *lb; register struct TSAPaddr *ta = &eb -> ev_taddr; if ((lb = newlblk (LB_LISTEN, ta)) == NULLLBP) return tsaplose (td, DR_CONGEST, NULLCP, "out of memory"); if ((lb -> lb_fd = bridgelisten_aux (lb, ta, td)) == NOTOK) { freelblk (lb); return OK; } SLOG (tsap_log, LLOG_EXCEPTIONS, NULLCP, ("reconnection on %s", taddr2str (ta))); freeeblk (eb); lb -> lb_close = close_bridge_socket; lb -> lb_accept = bridgeaccept; add_fd (lb -> lb_fd); return OK; } static int bridgelisten_aux (lb, ta, td) register struct listenblk *lb; register struct TSAPaddr *ta; struct TSAPdisconnect *td; { int fd; register struct listenblk *lb2; if (ta -> ta_naddr < 1) return tsaplose (td, DR_ADDRESS, NULLCP, "X.121 DTE not specified"); if ((fd = start_bridge_server (ta -> ta_addrs, SOMAXCONN, 0, SO_KEEPALIVE)) == NOTOK) return tsaplose (td, DR_CONGEST, "failed", "start_bridge_server"); lb -> lb_xsock = *ta -> ta_addrs; if ((lb2 = newlblk (LB_EXCEPTION, ta)) == NULLLBP) { close_bridge_socket (fd); return NOTOK; } lb2 -> lb_fd = get_bridge_assfd (fd); lb2 -> lb_except = bridge_except; lb2 -> lb_close = close_bridge_socket; add_fd (lb2 -> lb_fd); return fd; } /* \f */ static int bridgeaccept (lb, vecp, vec, td) register struct listenblk *lb; int *vecp; char **vec; struct TSAPdisconnect *td; { int fd; struct NSAPaddr out_socket; register struct NSAPaddr *osock = &out_socket; register struct NSAPaddr *xsock = &lb -> lb_xsock; register struct tsapblk *tb; register struct tsapkt *t = NULL; if ((fd = join_bridge_client (lb -> lb_fd, osock)) == NOTOK) return tsaplose (td, DR_NETWORK, "failed", "join_bridge_client"); if ((tb = newtblk ()) == NULL) { (void) tsaplose (td, DR_CONGEST, NULLCP, "out of memory"); goto out; } tb -> tb_fd = fd; (void) BTService (tb); if ((t = fd2tpkt (tb -> tb_fd, tb -> tb_initfnx, tb -> tb_readfnx)) == NULL || t -> t_errno != OK) { (void) tpktlose (tb, td, t ? t -> t_errno : DR_CONGEST, NULLCP, NULLCP); goto out; } if (TPDU_CODE (t) != TPDU_CR) { (void) tpktlose (tb, td, DR_PROTOCOL, NULLCP, "transport protocol mangled: expecting 0x%x, got 0x%x", TPDU_CR, TPDU_CODE (t)); goto out; } vec[0] = "tsaplisten"; /* any value will do */ if ((vec[1] = bridgesave (tb -> tb_fd, osock -> na_dte, osock -> na_dtelen, xsock -> na_dte, xsock -> na_dtelen, td)) == NULL) goto out; if ((vec[2] = tpkt2str (t)) == NULL) { (void) tsaplose (td, DR_CONGEST, NULLCP, NULLCP); goto out; } vec[*vecp = 3] = NULLCP; tb -> tb_fd = NOTOK; freetblk (tb); freetpkt (t); return OK; out: ; if (tb) { tb -> tb_fd = NOTOK; freetblk (tb); } freetpkt (t); (void) (*lb -> lb_close) (fd); return NOTOK; } /* \f */ /* ARGSUSED */ static int bridgeunique (ta, td) struct TSAPaddr *ta; struct TSAPdisconnect *td; { return tsaplose (td, DR_ADDRESS, NULLCP, "unique listens not supported at the X.25 bridge"); } #endif /* \f CONS */ #ifdef CONS /* ARGSUSED */ static int conslisten (lb, ta, td) struct listenblk *lb; struct TSAPaddr *ta; struct TSAPdisconnect *td; { int fd; if ((fd = start_cons_server (ta -> ta_addrs, SOMAXCONN, 0, SO_KEEPALIVE)) == NOTOK) return tsaplose (td, DR_CONGEST, "failed", "start_cons_server"); lb -> lb_nsock = *ta -> ta_addrs; return fd; } /* \f */ static int consaccept (lb, vecp, vec, td) register struct listenblk *lb; int *vecp; char **vec; struct TSAPdisconnect *td; { int fd; struct NSAPaddr out_socket; register struct NSAPaddr *osock = &out_socket; register struct NSAPaddr *nsock = &lb -> lb_nsock; register struct tsapblk *tb; register struct tsapkt *t; if ((fd = join_cons_client (lb -> lb_fd, osock)) == NOTOK) return tsaplose (td, DR_NETWORK, "failed", "join_cons_client"); if ((tb = newtblk ()) == NULL) { (void) tsaplose (td, DR_CONGEST, NULLCP, "out of memory"); goto out; } tb -> tb_fd = fd; (void) nTService (tb); if ((t = fd2tpkt (tb -> tb_fd, tb -> tb_initfnx, tb -> tb_readfnx)) == NULL || t -> t_errno != OK) { (void) tpktlose (tb, td, t ? t -> t_errno : DR_CONGEST, NULLCP, NULLCP); goto out; } if (TPDU_CODE (t) != TPDU_CR) { (void) tpktlose (tb, td, DR_PROTOCOL, NULLCP, "transport protocol mangled: expecting 0x%x, got 0x%x", TPDU_CR, TPDU_CODE (t)); goto out; } vec[0] = "tsaplisten"; /* any value will do */ if ((vec[1] = conssave (tb -> tb_fd, osock -> na_address, osock -> na_addrlen, nsock -> na_address, nsock -> na_addrlen, td)) == NULL) goto out; if ((vec[2] = tpkt2str (t)) == NULL) { (void) tsaplose (td, DR_CONGEST, NULLCP, NULLCP); goto out; } vec[*vecp = 3] = NULLCP; tb -> tb_fd = NOTOK; freetblk (tb); return OK; out: ; if (tb) { tb -> tb_fd = NOTOK; freetblk (tb); } (void) (*lb -> lb_close) (fd); return NOTOK; } /* \f */ static int consunique (na, td) struct NSAPaddr *na; struct TSAPdisconnect *td; { int fd; struct NSAPaddr insock; register struct NSAPaddr *na = ta -> ta_addrs; bzero ((char *) na, sizeof *na); na -> na_type = NA_NSAP; if ((fd = start_cons_server (na, SOMAXCONN, 0, SO_KEEPALIVE)) == NOTOK) return tsaplose (td, DR_CONGEST, "failed", "start_cons_server"); return fd; } #endif /* \f TP4 from TLI */ #ifdef TP4 /* \f TP4 from SunLink OSI */ #ifdef SUN_TP4 /* ARGSUSED */ static int tp4listen (lb, ta, td) struct listenblk *lb; register struct TSAPaddr *ta; struct TSAPdisconnect *td; { return start_tp4_server (ta, SOMAXCONN, 0, 0, td); } /* \f */ static int tp4accept (lb, vecp, vec, td) register struct listenblk *lb; int *vecp; char **vec; struct TSAPdisconnect *td; { int cc, fd, header_len, len; char data[TC_SIZE]; register struct tsapblk *tb; struct TSAPaddr tas; register struct TSAPaddr *ta = &tas; register struct tp4pkt *tp = NULL; static char buffer[BUFSIZ]; if ((fd = join_tp4_client (lb -> lb_fd, ta, td)) == NOTOK) return NOTOK; if ((tb = newtblk ()) == NULL) { (void) tsaplose (td, DR_CONGEST, NULLCP, "out of memory"); goto out; } tb -> tb_fd = fd; (void) tp4init (tb); if ((tp = newtp4pkt ((TP_EVENT) 0)) == NULL) { (void) tsaplose (td, DR_CONGEST, NULLCP, NULLCP); goto out; } header_len = sizeof (TP_MSG_CONNECT); if ((cc = recvfrom (fd, data, sizeof data, 0, (struct sockaddr *) tp, &header_len)) == NOTOK) { (void) tpktlose (tb, td, DR_CONGEST, "failed", "recvfrom"); goto out; } if (tp -> tp4_event != TP_CONNECT_IND) { (void) tpktlose (tb, td, DR_REMOTE, NULLCP, "transport protocol mangled: expecting 0x%x got 0x%x", TP_CONNECT_IND, tp -> tp4_event); goto out; } (void) tp42gen (&tb -> tb_responding, &tp -> tp4_called, 0); (void) tp42gen (&tb -> tb_initiating, &tp -> tp4_calling, 0); vec[0] = "tsaplisten"; /* any value will do */ if ((vec[1] = tp4save (tb -> tb_fd, td)) == NULL) goto out; len = explode (buffer, (u_char *) tp, sizeof (TP_MSG_CONNECT)); if (cc > 0) len += explode (buffer + len, (u_char *) data, cc); buffer[len] = NULL; vec[2] = buffer; vec[*vecp = 3] = NULLCP; tb -> tb_fd = NOTOK; freetblk (tb); freetp4pkt (tp); return OK; out: ; if (tb) { tb -> tb_fd = NOTOK; freetblk (tb); } if (tp) freetp4pkt (tp); (void) (lb -> lb_close) (fd); return NOTOK; } /* \f */ /* ARGSUSED */ static int tp4unique (ta, td) struct TSAPaddr *ta; struct TSAPdisconnect *td; { return tsaplose (td, DR_ADDRESS, NULLCP, "unique listens not yet supported with SunLink OSI"); } #endif #endif /* \f INTERNAL */ static struct listenblk *newlblk (type, ta) int type; struct TSAPaddr *ta; { register struct listenblk *lb; lb = (struct listenblk *) calloc (1, sizeof *lb); if (lb == NULLLBP) return lb; lb -> lb_fd = NOTOK; lb -> lb_addr = *ta; /* struct copy */ lb -> lb_type = type; if (once_only == 0) { LHead -> lb_forw = LHead -> lb_back = LHead; once_only++; } insque (lb, LHead -> lb_back); return lb; } static freelblk (lb) register struct listenblk *lb; { if (lb == NULLLBP) return; if (lb -> lb_fd != NOTOK) { del_fd (lb -> lb_fd); (void) (*lb -> lb_close) (lb -> lb_fd); } remque (lb); free ((char *) lb); } /* \f */ static struct listenblk *findlblk (ta, type) register struct TSAPaddr *ta; int type; { register struct listenblk *lb; if (once_only == 0) return NULLLBP; for (lb = LHead -> lb_forw; lb != LHead; lb = lb -> lb_forw) if (lb -> lb_type == type && bcmp ((char *) &lb -> lb_addr, (char *) ta, sizeof *ta) == 0) return lb; return NULLLBP; } /* \f */ static struct eventblk *neweblk (ta) struct TSAPaddr *ta; { register struct eventblk *eb; eb = (struct eventblk *) calloc (1, sizeof *eb); if (eb == NULLEVP) return eb; eb -> ev_taddr = *ta; /* struct copy */ if (ev_onceonly == 0) { EHead -> ev_forw = EHead -> ev_back = EHead; ev_onceonly++; } insque (eb, EHead -> ev_back); ev_count++; return eb; } #ifdef BRIDGE_X25 static freeeblk (eb) register struct eventblk *eb; { if (eb == NULLEVP) return; remque (eb); free ((char *) eb); ev_count--; } #endif /* \f */