DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T t

⟦3b08adf58⟧ TextFile

    Length: 32368 (0x7e70)
    Types: TextFile
    Names: »tsaplisten.c«

Derivation

└─⟦3d0c2be1b⟧ Bits:30001254 ISODE-5.0 Tape
    └─⟦eba4602b1⟧ »./isode-5.0.tar.Z« 
        └─⟦d3ac74d73⟧ 
            └─⟦this⟧ »isode-5.0/tsap/tsaplisten.c« 

TextFile

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

 */