BBN-Vax-TCP/src/telnet/tel.c

Compare this file to the similar file:
Show the results in this format:

#include "signal.h"
#include "netlib.h"
#ifdef NCP
#include "ncpopen.h"
#endif
#ifdef TCP
#include "con.h"
#include "errno.h"
#define SIGINR SIGURG
#endif
#include "tnio.h"
#include "telnet.h"

static NETCONN *curconn;    /* Current connection */
int AutoFlush = 1;
int AutoFill = 1;
int telwtlog = -1;
int telrdlog = -1;

/*
 * -------------------------- T E L I N I T ------------------------- */
/*
 * telinit(fd) assumes that fd has been opened to a network file descriptor
 * and initializes everything accordingly.
 */
NETCONN *
telinit(fd)
    int fd;
{
    register NETCONN *np;
    int i;
    NETCONN *prev_conn;
    extern NoAct(), AYTdefault(), BREAKdefault(), IPdefault();
    extern RcvSynch();
    extern char *malloc();

    np = (NETCONN *)malloc(sizeof(*np));
    if (np == NULL)
	return(NULL);

    prev_conn = curconn;
    curconn = np;   /* Save for RcvSynch() */
    np->NextConP = prev_conn;	/* And put in list */
    np->NetFD = fd;

#   ifdef TCP
      np->UrgCnt = 0;
      np->UrgInput = 0;
#   endif TCP
#   ifdef NCP
      np->INSCount = 0;
#   endif NCP
    np->ECf = NoAct;
    np->ELf = NoAct;
    np->AOf = NoAct;
    np->IPf = IPdefault;
    np->AYTf = AYTdefault;
    np->BREAKf = BREAKdefault;
    np->GAf = NoAct;
    np->SYNCHf = NoAct;
    Bsetbuf(np->ToUsrBuf, NULL, 0);
    Bfill(np->FmNetBuf, NULL, 0);
    Bsetbuf(np->ToNetBuf, NULL, 0);
    telflush(np);   /* Just to initialize ToNetBuf properly */
    np->ProtState = PROTINIT;
    for (i = 0; i < N_OPTIONS; i++)
    {
	np->OptState[i][0] = 0;
	np->OptState[i][1] = 0;
	np->Orig[i][0] = 0;
	np->Orig[i][1] = 0;
    }
    signal(SIGINR, RcvSynch);
    return(np);
}

/*
 * -------------------------- T E L R E A D ------------------------- */
/*
 * telread processes characters from the network,
 * handling TELNET controls via NetChar. Normal text is passed to the user.
 * Returns number of chars for user (which could be 0), or TELEOF or TELERR.
 */
telread(connp, bufp, bufsize)
    register NETCONN *connp;
    char *bufp;
    int bufsize;
{
    extern int AutoFlush;   /* Nonzero to enable auto telflush */
    extern int AutoFill;    /* Nonzero to enable auto telfill */
    extern int telrdlog;    /* >= 0 to enable logging of incoming data */

    if (bufsize <= 0)
    {
	extern int errno;

	errno = EINVAL;
	return(TELERR);
    }

    Bsetbuf(connp->ToUsrBuf, bufp, bufsize);
    if (Bleft(connp->FmNetBuf) == 0)
	if (AutoFill)
	{
	    int nfill;

	    nfill = telfill(connp);
	    if (nfill == TELEOF || nfill == TELERR)
		return(nfill);
	}

    while (Bleft(connp->FmNetBuf) > 0 && Bfree(connp->ToUsrBuf) > 0)
    {
	if (connp->ProtState != PROTINIT && Bfree(connp->ToNetBuf) < PROTMAX)
	    if (AutoFlush)
		telflush(connp);
	    else
		break;
	if (connp->ProtState != PROTINIT && Blen(connp->ToUsrBuf) > 0)
	    break;
	NetChar(connp, Bgetc(connp->FmNetBuf));
    }

    if (Blen(connp->ToNetBuf) > 0 && AutoFlush)
	telflush(connp);
    return(Blen(connp->ToUsrBuf));
}

/*
 * -------------------------- T E L F I L L ------------------------- */
/*
 * Fills FmNetBuf, if it is empty. Returns 0 if did nothing
 * (because FmNetBuf had data in it), TELERR, TELEOF, or # characters read.
 */
telfill(connp)
    register NETCONN * connp;
{
    int nread;
    extern int errno;

    if (Bleft(connp->FmNetBuf) == 0)
    {

#    ifdef TCP
	if (connp->UrgInput) connp->UrgInput = ChkUrgent(connp);
#    endif TCP

    RETRY:
	nread = read(connp->NetFD, connp->FmNetData, sizeof(connp->FmNetData));
	switch(nread)
	{
	default:
	    break;
	case 0:
#	ifdef TCP
	    {
		struct netstate tstat;
		ioctl(connp->NetFD,NETGETS, &tstat);
		if (tstat.n_state & 0377)
		    printf (" (Strange read completion. %o) ",
			tstat.n_state);
		else printf(" (Remote close.) ");
	    }
	
#	endif TCP
	    return(TELEOF);
	case -1:
	    if (errno == EINTR)
		goto RETRY;
#       ifdef TCP
	    else if (errno == ENETSTAT) {
		struct netstate tstat;
		ioctl(connp->NetFD,NETGETS, &tstat);
		if (tstat.n_state & URXTIMO) {
			printf("\nForeign host not responding\n");
			goto RETRY;
		} else if (tstat.n_state & URESET)
			printf("\nForeign host reset connection\n");
		else if (tstat.n_state & UURGENT)
			goto RETRY;
		cmderr(0, "error return from network (status %o).\n", 
			   tstat.n_state);
		return(TELERR);
	     }
#       endif TCP
	    else
	     {
		cmderr(errno, "error return from network.");
		return(TELERR);
	      }
	}
	if (telrdlog >= 0)
	    write(telrdlog, connp->FmNetData, sizeof(connp->FmNetData));
	Bfill(connp->FmNetBuf, connp->FmNetData, nread);
	return(nread);
    }
    return(0);
}

/*
 * -------------------------- T E L F L U S H ----------------------- */
/*
 * Flush accumulated data in ToNetBuf. Return values:
 *	0 - nothing to write;
 *	TELERR - error while writing;
 *	positive value - amount written
 */
telflush(connp)
    register NETCONN *connp;
{
    int nwrite;
    int retval;
    extern int errno;
    extern int telwtlog;

    retval = 0;
    if (Blen(connp->ToNetBuf) != 0)
    {
#	ifdef TCP
	if (connp->UrgCnt)
	 {			       /* send some bytes urgently */
	   nwrite =
	     write(connp->NetFD, Baddr(connp->ToNetBuf), connp->UrgCnt);
	   ioctl(connp->NetFD, NETRSETU, NULL);
	   connp->UrgCnt = 0;	       /* NETSETU was done by SendUrg */
	 } else nwrite = 0;
	if (nwrite >= 0) nwrite +=
	   write(connp->NetFD, Baddr(connp->ToNetBuf) + connp->UrgCnt,
	    Blen(connp->ToNetBuf) - connp->UrgCnt);
#	endif TCP
#	ifdef NCP
	 nwrite =
	 write(connp->NetFD, Baddr(connp->ToNetBuf), Blen(connp->ToNetBuf));
#	endif NCP

	switch(nwrite)
	{
	default:
	    retval = nwrite;
	    if (telwtlog >= 0)
		write(telwtlog, Baddr(connp->ToNetBuf), Blen(connp->ToNetBuf));
	    break;
	case 0:
	    errno = 0;
	    retval = TELERR;
	    break;
	case -1:
	    retval = TELERR;
	    break;
	}
    }
    Bsetbuf(connp->ToNetBuf, connp->ToNetData, sizeof(connp->ToNetData));
    return(retval);
}

/*
 * -------------------------- T E L W R I T E ----------------------- */
/*
 * Write the specified data onto the net. Doubles IACs.
 * Returns # characters from user actually written, or TELERR.
 * The number will be equal to the number supplied.
 * If AutoFlush is turned off, TELERR will be returned if the entire buffer
 * cannot all be written.
 */
telwrite(connp, bufp, bufsize)
    register NETCONN *connp;
    char * bufp;
    int bufsize;
{
    struct GBuffer fm_user;
    struct PBuffer to_net;
    extern int AutoFlush;

/* Save ToNetBuf if we might have to back up */

    PBcopy(connp->ToNetBuf, to_net);

/* Put the data in ToNetBuf */

    Bfill(fm_user, bufp, bufsize);
    while (Bleft(fm_user) > 0)
    {	register int c;

	if (Bfree(connp->ToNetBuf) < 2)    /* Allow room for doubled IAC */
	    if (AutoFlush)
		telflush(connp);
	    else
		break;
	c = Bgetc(fm_user);
	Bputc(c, connp->ToNetBuf);
	if (c == IAC)
	    Bputc(c, connp->ToNetBuf);
    }

    if (AutoFlush && Blen(connp->ToNetBuf) > 0)
	telflush(connp);

    if (Bleft(fm_user) > 0)
    {
	PBcopy(to_net, connp->ToNetBuf);
	return(TELERR);
    }
    else
	return(bufsize);
}

/*
 * -------------------------- S E N D C ----------------------------- */
/*
 * Sends one character, by putting it in ToNetBuf. Calls telflush if necessary.
 */
SendC(connp, c)
    register NETCONN * connp;
    int c;
{
    if (Bfree(connp->ToNetBuf) == 0)
	if (AutoFlush)
	    telflush(connp);

    Bputc(c, connp->ToNetBuf);
}

/*
 * -------------------------- R C V S Y N C H ------------------- */
/*
 * Called when an NCP INS signal is received. Since it is a signal,
 * there's no way to know what connection it came in on.
 * Just assume it's the current connection.
 */
RcvSynch()
{
    register NETCONN *connp;

    signal(SIGINR, RcvSynch);
    connp = curconn;	/* Saved by telinit */
#   ifdef NCP
	connp->INSCount++;
#   endif NCP
#   ifdef TCP
	if (!(connp->UrgInput))
	    connp->UrgInput=ChkUrgent(connp);
#   endif TCP
    (*(connp->SYNCHf))(connp);
}

/*
 * -------------------------- T E L F I N I S H --------------------- */
/*
 * Free up resources allocated to the given connection.
 * If we can, flush pending data.
 */
telfinish(connp)
    register NETCONN *connp;
{
    register NETCONN * * pp;
    extern int AutoFlush;

    if (AutoFlush)
	telflush(connp);

#   ifdef TCP
	    ioctl(connp->NetFD, NETCLOSE, NULL);
#   endif TCP

    for (pp = &curconn; *pp != NULL; pp = &((*pp)->NextConP))
	if (*pp == connp)
	{
	    *pp = connp->NextConP;
	    break;
	}

    free(connp);
}

/*
 * -------------------------- T E L C L O S E ----------------------- */
/*
 * Close a TELNET connection opened via telopen().
 */
telclose(connp)
    register NETCONN *connp;
{
    int fd;

    fd = connp->NetFD;
    telfinish(connp);
    close(fd);
}

/*
 * -------------------------- S E N D U R G ------------------------- */
/*
 * Called to send urgent notification on the given connection.
 * For NCP, this is just a sendins().
 */
SendUrg(connp)
    register NETCONN *connp;
{
#   ifdef NCP
    sendins(connp->NetFD);
#endif NCP
#ifdef TCP		/* urgent on, eols still on. */
    if (!(connp->UrgCnt))
	 ioctl(connp->NetFD, NETSETU, NULL);
    connp->UrgCnt = Blen(connp->ToNetBuf);
    telflush(connp);
#endif TCP
}
/*
 * ----------------------- C h k U r g e n t ------------------------
 *
 * called to check if connection is still in urgent state.
 *
 */

#ifdef TCP
ChkUrgent(connp)
   register NETCONN *connp;
{
	struct netstate tstat;
	ioctl(connp->NetFD,NETGETS, &tstat);
	return(tstat.n_state & UURGENT);
 } 
#endif TCP
/*
 * -------------------------- T E L E M P T Y ----------------------- */
/*
 * Return status of buffers.
 */
telempty(connp)
    register NETCONN * connp;
{
    int retval;

    retval = 0;
    if (Bleft(connp->FmNetBuf) > 0)
	retval += 1;
    if (Blen(connp->ToNetBuf) > 0)
	retval += 2;
    return(retval);
}

/*
 * -------------------------- T E L F D ----------------------------- */
/*
 * Return the file descriptor of the connection.
 */
telfd(connp)
    register NETCONN * connp;
{
    return(connp->NetFD);
}

/* -------------------------- A U T O F I L L ----------------------- */

autofill(flag)
    int flag;
{
    AutoFill = flag;
}

/* -------------------------- A U T O F L U S H --------------------- */

autoflush(flag)
    int flag;
{
    AutoFlush = flag;
}

/*
 * -------------------------- T E L F U N C ------------------------- */
/*
 * Set function handler.
 */
typedef int func();
func *telfunc(connp, control, handler)
    register NETCONN * connp;
    int control;
    int (*handler)();
{
    int (*old_handler)();

    switch(control)
    {
    case EC:
	old_handler = connp->ECf;
	connp->ECf = handler;
	break;
    case EL:
	old_handler = connp->ELf;
	connp->ELf = handler;
	break;
    case AO:
	old_handler = connp->AOf;
	connp->AOf = handler;
	break;
    case IP:
	old_handler = connp->IPf;
	connp->IPf = handler;
	break;
    case BREAK:
	old_handler = connp->BREAKf;
	connp->BREAKf = handler;
	break;
    case AYT:
	old_handler = connp->AYTf;
	connp->AYTf = handler;
	break;
    case GA:
	old_handler = connp->GAf;
	connp->GAf = handler;
	break;
    case SYNCH:
	old_handler = connp->SYNCHf;
	connp->SYNCHf = handler;
	break;
    default:
	old_handler = NULL;
	break;
    }
    return(old_handler);
}

/*
 * -------------------------- T E L O P E N ------------------------- */
/*
 * telopen(hostnum) opens a connection to the specified host.
 */
NETCONN *
telopen(hostnum)
netaddr	hostnum;
{
    int fd;
#   ifdef NCP
     static struct ncpopen openparams;
#   endif NCP
#   ifdef TCP
     static struct con openparams;
#   endif TCP;
    extern int errno;

#   ifdef NCP
        openparams.o_type = 0;
        openparams.o_fskt = SERVER_SOCKET;
        openparams.o_lskt = 0;
        openparams.o_nomall = 0;
        openparams.o_host = hostnum;
    
        fd = open("/dev/net/ncp", &openparams);
#   endif NCP
#   ifdef TCP
        openparams.c_mode = CONTCP | CONACT;
        openparams.c_fport = SERVER_SOCKET;
        openparams.c_lport = 0;
        openparams.c_sbufs = 1;
	openparams.c_rbufs = 2;
        openparams.c_lo = openparams.c_hi = 0;
        openparams.c_fcon = hostnum;
	mkanyhost(openparams.c_lcon);
	openparams.c_timeo = 0;
    
        if ((fd = open("/dev/net/tcp", &openparams)) >= 0)
	    ioctl(fd, NETSETE, NULL);/* urgent assumed off, eols on. */
#   endif TCP
    if (fd == -1)
	return(NULL);
    return(telinit(fd));
}

/* ------------------------------------------------------------------ */