SRI-NOSC/ncpp/tel-s/svrtel.c

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

#/*
Module Name:
 
    N     N  EEEEEEE  TTTTTTT   GGGGG   RRRRRR   FFFFFFF
    NN    N  E           T     G     G  R     R  F
    N N   N  E           T     G     G  R     R  F
    N  N  N  EEEEEE      T     G        RRRRR    FFFFFF
    N   N N  E           T     G   GGG  R    R   F
    N    NN  E           T     G     G  R     R  F
    N     N  EEEEEEE     T      GGGGG   R     R  F      
	   
 
	Network Graphics Server for UNIX

Installation:
	if $1x = finalx goto final
	cc -c svrtel.c
	if ! -r svrtel.o exit
	cc svrtel.o /usr/net/hnumcvt.c -lj
	rm -f svrtel.o hnumcvt.o
	exit
: final
	cc -O -c svrtel.c
	if ! -r svrtel.o exit
	cc -O -n -s svrtel.o /usr/net/hnumcvt.c -lj
	if ! -r a.out exit
	if ! -r ncpp/tel-s/svrtel.c goto same
	if { cmp -s svrtel.c ncpp/tel-s/svrtel.c } goto same
	su cp svrtel.c ncpp/tel-s/svrtel.c
	rm -f svrtel.c
: same
	if -r /usr/net/etc/svrtel su rm -f /usr/net/etc/svrtel
	su cp a.out /usr/net/etc/svrtel
	e - ncpp/tel-s/svrtel.c
1i
#define OLDTLNT
. 
w /tmp/svrtel.c
q
	cc -O -s -n /tmp/svrtel.c hnumcvt.o -lj
	if -r /usr/net/etc/srvrtelnet su rm -f /usr/net/etc/srvrtelnet
	su cp a.out /usr/net/etc/srvrtelnet
	rm -f a.out svrtel.o hnumcvt.o /tmp/svrtel.c
	chdir /usr/net/etc
	su chmod 744 svrtel srvrtelnet
	su chown root svrtel srvrtelnet
	su chgrp system svrtel srvrtelnet

Synopsis:

Function:

Restrictions:

Diagnostics:

Files:

See Also:

Bugs:

Globals contained:

Routines contained:

Modules referenced:

Modules referencing:

Compile time parameters and effects:

Module History:
*/
/* Parameters */
#define SIGINR  15      /* Interrupt-by-sender (INS) */
#define NETBUFSIZE 60	/* Number of characters in network buffer */
char ptys[] "ABCEDFGH";	/* Suffix characters of psuedo-teletypes */
 
/* TELNET Opcodes */
#define SE 0360		/* Subnegotiation_end */
#define NOP 0361	/* Nop */
#define DATAM 0362	/* Data_mark */
#define BREAK 0363	/* Break */
#define IP 0364		/* Interrupt_Process */
#define AO 0365		/* Abort_Output */
#define AYT 0366	/* Are_You_There */
#define EC 0367		/* Erase_Character */
#define EL 0370		/* Erase_Line */
#define GA 0371		/* Go_Ahead */
#define SB 0372		/* Subnegotiation_Begin */
#define WILL 0373	/* Will */
#define WONT 0374	/* Wont */
#define DO 0375		/* Do */
#define DONT 0376	/* Dont */
#define IAC 0377	/* Interpet_As_Command */

#ifdef OLDTLNT
/* Old TELNET Opcodes */
#define ODATAM 128      /* Data_mark */
#define OBREAK 129      /* Break */
#define ONOP   130      /* Nop */
#define OIECHO 131      /* I echo */
#define OUECHO 132      /* You echo */
#define OHYI   133      /* Hide your input */
#endif

/*  TELNET Options
TELOPT($BINO,0,Transmit_binary);
TELOPT($ECHO,1,Echo);
TELOPT($RCP,2,Prepare_to_reconnect);
TELOPT($SGA,3,Suppress_go_ahead);
TELOPT($NAMS,4,Negotiate_approximate_message_size);
TELOPT($STATUS,5,Status_of_TELNET_options);
TELOPT($TIMRK,6,Timing_Mark);
TELOPT($RCTE,7,Remote_Controled_Transmission_and_Echoing);
TELOPT($NAOL,10,Negotiate_About_Output_Line_width);
TELOPT($NAOP,11,Negotiate_About_Output_Page_Size);
TELOPT($EXTASC,17,Extended_ASCII);
TELOPT($EXOPL,377,Extended_Options_List);
*/
 
/*
Global variables			*/
 
int pid;		/* Process ID of subsidiary fork */
int netchan;		/* Channel descriptor for network */
			/* channel used for TELNET data */
int ptychan;		/* Channel number of PTY */
char echoflag;		/* Indicates 'will echo' has been sent */
int junk;		/* Somewhere to throw away things */
int pty;                /* Pty name */
char *arg1p;            /* Pointer to arg[1] */
int inter;              /* Indication that an interrupt came in */
int ins();              /* INS interrupt routine */
 
struct openparams	/* struct for parameterized network opens */
{
  char o_op;		/* opcode for kernel & daemon - unused here */
  char o_type;		/* Type for connection.  See defines below */
  int o_id;		/* ID of file for kernel & daemon, unused here */
  int o_lskt;		/* Local socket number either abs or rel */
  int o_fskt[2];	/* Foreign socket either abs or rel */
  char o_frnhost;	/* Foreign host number */
  char o_bsize;		/* bytesize for the connection */
  int o_nomall;		/* nominal allocation for the connection */
  int o_timeo;		/* Number of seconds before time out */
  int o_relid;		/* fid of file to base a data connection on */
} openparams;
 
#define o_direct        01      /* icp |~  direct */
#define o_server        02      /* user | server */
#define o_init          04      /* listen | init */
#define o_specific      010     /* general  | specific */
#define o_duplex        020     /* simplex | duplex */
#define o_relative      040     /* absolute | relative */
 
struct ttymode
{ char ispeed, ospeed;
  char erase, kill;
  int mode;
};

/*
main   - Handles new connections		*/
 
int foochan;		/* Due to crock in close */
main(argcnt,argvec)
int argcnt;
char *argvec[];
{
	log("Awaiting connection\n");
	signal(1,1);			/* Ignore quits */
	signal(2,1);			/* Ignore hangups */
	signal(SIGINR,1);             /* Ignore ins interrupts */
	if(argcnt > 1) arg1p = argvec[1];
	for (;;) {
		openparams.o_type = o_server;	/* Server ICP */
		openparams.o_fskt[0] = 0;	/* Clear any crud */
		openparams.o_fskt[1] = 0;
#ifndef OLDTLNT
		openparams.o_lskt = 23;	 /* Use socket 23 */
#endif
#ifdef OLDTLNT
		openparams.o_lskt = 1;	 /* Use socket 1 */
#endif
		netchan = open("/dev/net/anyhost",&openparams);
		if (netchan < 0) {
			log("Open failure.\n");
			continue;
		}
		foochan = dup(netchan);	/* Bagbiting close!!! */
		if ((pid = fork())<0) {
			log("No processes left!\n"); }
		else if (pid==0) {
			netgrf();
			exit(0);
		}
		else {		/* More logger */
			wait(&junk);	/* Wait for server to become orphan */
			close(foochan);	/* Flush extra channel */
			close(netchan);	/* And real channel, then wait for */
		}			/* another user */
	}
}
 
/*
netgrf - Sets up processes for NGP server	*/
 
netgrf()
{
  /* Fork another level deep so parent can die and leave the server as */
  /* an orphan to be inherited by /etc/init.  Otherwise, zombies are */
  /* left lying around because the logger (i.e. main) cannot afford to */
  /* do a wait. */
	switch(pid=fork()) {
	case -1:
		log("No processes left!\n");
		write(netchan,"Sorry, not enough resources available.\r\n",41);
		exit(1);	/* Failure return */
	default:
		exit(0);	/* Continues logger */
	case 0:		/* child continues on.... */
		break;
	}
	if (openpty()<0) {
		log("No ptys\n");
		write(netchan,"Sorry, no ptys\r\n",16);
		exit(1);	/* Failure return */
	}
	setss();
	if ((pid = fork()) < 0) {
		log("No processes left!\n");
		write(netchan,"Sorry, no processes\r\n",21);
		exit(1);	/* Failure return */
	}
	close(foochan);	/* Two process have it open now (bagbitting close!) */
	if (pid==0)
		telxmt();	/* Child handles transmit side */
	else
		telrcv();	/* Parent handles recieve side */
}
 
/*
telrcv - TELNET recieve side			*/
 
telrcv()
{
	int c;

/*	signal(SIGINR,&ins);  ***/
	sleep(2);		/* Give getty a chance to do stty */
	for(;;) {
		c = telgetc();		/* Fetch a character */
		if (c==IAC)		/* IAC? */
			telcmd();	/* Yes, handle special command */
#ifdef OLDTLNT
		else if (c >=128 )
			otelcmd(c);
#endif
		else {
			write(ptychan,&c,1);	/* Otherwise, just enter it */
			if (c=='\r') {		/* Special case? */
				c = telgetc();	/* Yes, look for LF */
				if (c && c!='\n') /* If different, enter */
					write(ptychan,&c,1);	/* it too! */
			}
		}
	}
}
 
#ifdef OLDTLNT
/*
otelcmd - Handle old TELNET commands */

otelcmd(c)
int c;
{
	struct ttymode status;		/* Buffer for stty and gtty */

	switch(c)  {
	case OBREAK:
		gtty(ptychan,&status);	/* return NUL in raw mode, else DEL */
		write(ptychan,(status.mode&040) ? "\0" : "\177",1);
		break;
	case OIECHO:
	case OUECHO:
		gtty(ptychan,&status);
		status.ispeed = status.ospeed = ( (c == OIECHO) ? 4 : 11 );
		stty(ptychan,&status);
		break;
	 }
}
#endif

/*
telcmd - Handle new TELNET commands */
 
telcmd()
{
	char negbuf[3];
	int command;
	struct ttymode status;		/* Buffer for stty and gtty */

	command = telgetc();		/* Get a character */
	switch(command)  {
	case BREAK:
	case IP:
		gtty(ptychan,&status);	/* output NUL in raw mode, else DEL */
		write(ptychan,(status.mode&040) ? "\0" : "\177",1);
		break;
	case AYT:
		write(netchan,"\007",1);
		break;
	case EC:
	case EL:
		gtty(ptychan,&status);
		write(ptychan,(command == EC) ? &status.erase : &status.kill, 1);
		break;
	case SB:	/* Begin subnegotiation? */
		/* Look for end of subnegotiation */
		do {
			while(command != IAC)
				command = telgetc();
		} while telgetc() != SE;
		break;
	case WILL:
	case WONT:
	case DO:
	case DONT:
		/* Negotiate.	Always give negative acknowledgement */
		negbuf[0] = IAC;		/* Interpete As Command */
		negbuf[1] = DONT+WONT-((command+1)&0376);   /* Negative ack. */
		negbuf[2] = telgetc();	/* Set code for option */
		if (negbuf[2]==1 &&		/* Echo option? */
		   (negbuf[1]&0377) == WONT) {
			gtty(ptychan,&status);
			if (command == DO) {	/* User wants us to echo */
				status.ispeed = status.ospeed = 11; /* 2400 baud echos */
				negbuf[1] = WILL;
			} else {	/* User doesn't want us to echo */
				status.ispeed = status.ospeed = 4;	/* 134.5 baud doesn't echo */
				negbuf[1] = WONT;
			}
			stty(ptychan,&status);	/* Set desired echo mode */
			if (echoflag == 0) {	/* Was this a response to our WILL ECHO? */
				echoflag++;	/* If so don't do anything */
				break;
			}
		}
		write(netchan,negbuf,3);	/* Send off confirmation/denial to net */
		break;
	case IAC:		/* Not really a command */
		write(ptychan,&command,1);	/* but a character */
		break;
	}
}
/*
telxmt - TELNET transmit side			*/
 
char ttybuf[NETBUFSIZE+1];	/* This size is best for NetUNIX */
 
telxmt()
{
	register int bytcnt;
	register char *s1,*s2;
	int retries;
	struct ttymode status;

	/* Send 'WILL ECHO' and a reminder */
#ifdef OLDTLNT
	write(netchan,"\203\r\n",3);
#endif
#ifndef OLDTLNT
	write(netchan,"\377\373\001\r\n",5);
#endif
	log("connection on tty%c", pty);
	if(arg1p) printf(" from %s", &arg1p[10]);
	printf(".\n");  flush();

	/* Copy characters from output buffer to network */
	retries = 10;
	for(;;) switch(bytcnt = read(ptychan,ttybuf,sizeof ttybuf)) {
	case -1:	/* error returned; time to quit! */
		exit(0);
	case 0:		/* EOF -- other side closed */
		gtty(ptychan, &status);
		if(status.mode&1 || --retries == 0)
			exit(0);
		sleep(1);	/* give a chance to re-open */
		continue;
	default:
		retries = 5;
		for (s1 = s2 = ttybuf, ttybuf[bytcnt] = 0; *s1; s1++)
			if (*s1 == IAC) {
				write(netchan,s2,s1-s2+1);
				s2 = s1;
			}
		write(netchan,s2,s1-s2);
	}
}
/*
openpty- Find a usable PTY			*/
 
char *ptyname "/dev/ptyx";	/* Where to look for pseudo-teletypes */
 
int openpty()	/* Find an available pseudo-teletype */
{
	register char *p;

	for (p = ptys; ptyname[8] = *p++;) {
		ptychan = open(ptyname,2);	/* Try this PTY */
		if (ptychan>=0) {
			pty = ptyname[8]&0177;
			return(ptychan);
		}
	}
	return -1;
}

/*setss - Set arguments to appear in ss */

char argstr[] "ttyX host ";
 
setss()
{       register char *p, *q;
	struct openparams statparams;

	if ((q=arg1p) == 0) return;
	argstr[3] = pty;
	p = argstr;
	while (*p) { if (*q) *q++ = *p++; else return; }
	if (fstat(netchan,&statparams) >= 0) {
		p = hnumcnv(statparams.o_frnhost&0377);
		while (*p) { if (*q) *q++ = *p++; else return; }
	}
	*q = '\0';
}
/*
telgetc- Get a character from TELNET stream 	*/
 
telgetc()
{
	char c;
	register int i;
	int ttytype[3];

	i = read(netchan,&c,1);
	if (inter) {		/* check for interrupts */
		inter = 0;	/* DM will be ignored */
		gtty(ptychan,ttytype);	/* return NUL in raw mode, else DEL */
		return( (ttytype[2]&040) ? 0 : 0177);
	}
	if (i != 1) {
/*DEBUG*/if(pid==0)log("PID not set!  This can't happen!\n");else
		kill(pid,9);		/* Kill other side */
		exit(1);
	} else {
		return(c&0377);
	}
}
 

ins()
{       inter++;                /* note that an interrupt has occurred */
	signal(SIGINR,&ins);
}

log(txt, a, b, c, d)
char *txt;
{
	long t;			/* gets the result from time */

	time(&t);		/* get system time */
#ifndef OLDTLNT
	printf ("%-16.16sNew Telnet server: ",
#endif
#ifdef OLDTLNT
	printf ("%-16.16sOld Telnet server: ",
#endif
		ctime(&t)+4);	/* Mmm dd hh:mm:ss */
	printf(txt, a, b, c, d);
	flush();
}