|
|
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
*/