home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
GEMini Atari
/
GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso
/
files
/
telecomm
/
nhclb120
/
telunix.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-09-26
|
7KB
|
361 lines
#include <stdio.h>
#include "global.h"
#include "config.h"
#include "mbuf.h"
#include "timer.h"
#include "icmp.h"
#include "netuser.h"
#include "tcp.h"
#include "telnet.h"
#include "session.h"
#ifndef _MEMORY_H
char *memchr();
#endif
static void tnix_state();
#define TUMAXSCAN 3 /* max number of telunix clients active */
#define TURQSIZ 512 /* max data we will request from pty at once */
struct tcb *tnix_tcb = NULLTCB;
struct tcb *tnixtcb[TUMAXSCAN]; /* savebuf for tcb ptrs for scan routines */
extern int errno;
#ifdef SYS5
extern unsigned long selmask;
#endif
/* Start telnet-unix server */
tnix1(argc,argv)
char *argv[];
{
struct socket lsocket;
extern int32 ip_addr;
void tnix_state();
/* Incoming Telnet */
lsocket.address = ip_addr;
if(argc < 2)
lsocket.port = TELNET_PORT;
else
lsocket.port = atoi(argv[1]);
tnix_tcb = open_tcp(&lsocket,NULLSOCK,TCP_SERVER,0,
NULLVFP,NULLVFP,tnix_state,0,(char *)NULL);
if(tnix_tcb == NULLTCB)
fprintf(stderr,"start telunix fails rsn %d.\n",net_error);
else
log(tnix_tcb,"STARTED Telunix - (%d %x)",
lsocket.port,tnix_tcb);
}
/* Shut down Telnet server */
tnix0()
{
if(tnix_tcb != NULLTCB) {
log(tnix_tcb,"STOPPED Telunix - (%x)",tnix_tcb);
close_tcp(tnix_tcb);
} else
fprintf(stderr,"stop telunix fails -- no server active.\n");
}
/* Handle incoming Telnet-Unix connect requests */
static void
tnix_state(tcb,old,new)
struct tcb *tcb;
char old,new;
{
register struct telnet *tn;
int tnix_addscan();
extern void tnix_rmvscan();
extern int send_tcp();
extern struct mbuf *free_p();
extern int del_tcp();
extern int close_tcp();
#ifdef SYS5
#ifndef free
extern void free();
#endif
#endif
tn = (struct telnet *)tcb->user;
switch(new){
case ESTABLISHED:
/* Create and initialize a Telnet protocol descriptor */
if((tn = (struct telnet *)calloc(1,sizeof(struct telnet))) == NULLTN){
log(tcb,"reject Telunix - no space");
sndmsg(tcb,"Rejected; no space on remote\n");
close_tcp(tcb);
return;
}
tn->session = NULLSESSION;
tn->state = TS_DATA;
tcb->user = (char *)tn; /* Upward pointer */
tn->tcb = tcb; /* Downward pointer */
tn->inbuf = NULLBUF;
tn->outbuf = NULLBUF;
if(tnix_addscan(tcb) < 0 ||
(tn->fd = OpenPty()) < 3) { /* barf if <= stderr */
tnix_rmvscan(tcb);
log(tcb,"reject Telunix - no Unix ports");
sndmsg(tcb,
"Rejected; no ports available on remote\n");
close_tcp(tcb);
return;
}
#ifdef SYS5
selmask |= (1 << tn->fd);
#endif
log(tcb,"open Telunix - (%d %x %d %d)",tn->fd,tcb,old,new);
break;
case FINWAIT1:
case FINWAIT2:
case CLOSING:
case LAST_ACK:
case TIME_WAIT:
if(tn != NULLTN &&
tn->fd > 2) {
log(tcb,"close Telunix - (%d %x %d %d)",
tn->fd,tcb,old,new);
close(tn->fd);
#ifdef SYS5
selmask &= ~(1 << tn->fd);
#endif
tn->fd = 0;
}
tnix_rmvscan(tcb);
break;
case CLOSE_WAIT:
/* flush that last buffer */
if(tn != NULLTN &&
tn->outbuf != NULLBUF &&
tn->outbuf->cnt != 0) {
send_tcp(tcb,tn->outbuf);
tn->outbuf = NULLBUF;
}
close_tcp(tcb);
break;
case CLOSED:
if(tn != NULLTN) {
if(tn->fd > 2) {
log(tcb,"close Telunix - (%d %x %d %d)",
tn->fd,tcb,old,new);
close(tn->fd);
#ifdef SYS5
selmask &= ~(1 << tn->fd);
#endif
tn->fd = 0;
}
if(tn->inbuf != NULLBUF)
free_p(tn->inbuf);
if(tn->outbuf != NULLBUF)
free_p(tn->outbuf);
free((char *)tn);
}
tnix_rmvscan(tcb);
del_tcp(tcb);
if(tcb == tnix_tcb)
tnix_tcb = NULLTCB;
break;
}
}
/* Telunix io interface. Called periodically to process any waiting io. */
void
tnix_try(tcb)
register struct tcb *tcb;
{
extern void tnix_rmvscan();
extern int recv_tcp();
extern int send_tcp();
extern void tnix_input();
register struct telnet *tn;
register int i;
if((tn = (struct telnet *)tcb->user) == NULLTN || tn->fd < 3) {
/* Unknown connection - remove it from queue */
log(tcb,"error Telnet - tnix_try (%d)", tn);
tnix_rmvscan(tcb);
return;
}
/*
* First, check if there is any pending io for the pty:
*/
if(tn->inbuf != NULLBUF) {
tnix_input(tn);
}
if(tn->inbuf == NULLBUF) {
if(tcb->rcvcnt > 0 &&
recv_tcp(tcb,&(tn->inbuf),0) > 0)
tnix_input(tn);
}
/*
* Next, check if there is any io for tcp:
*/
do {
if(tn->outbuf == NULLBUF &&
(tn->outbuf = alloc_mbuf(TURQSIZ)) == NULLBUF)
return; /* can't do much without a buffer */
if(tn->outbuf->cnt < TURQSIZ) {
if((i = read(tn->fd, tn->outbuf->data + tn->outbuf->cnt,
(int)(TURQSIZ - tn->outbuf->cnt))) == -1) {
log(tcb,"error Telunix - read (%d %d %d)",
errno, tn->fd,
TURQSIZ - tn->outbuf->cnt);
close_tcp(tcb);
return;
}
if((tn->outbuf->cnt += i) < TURQSIZ)
i = 0; /* didn't fill buffer so don't retry */
} else {
i = -1; /* any nonzero value will do */
}
if(tn->outbuf->cnt == 0 || /* nothing to send */
tcb->sndcnt > tcb->window) /* too congested to send */
return;
if(send_tcp(tcb,tn->outbuf) < 0) {
log(tcb,"error Telunix - send_tcp (%d %d %d)",
net_error, tn->fd, tn->outbuf->cnt);
close_tcp(tcb);
tn->outbuf = NULLBUF;
return;
}
tn->outbuf = NULLBUF;
} while(i);
}
/* Process incoming TELNET characters */
void
tnix_input(tn)
register struct telnet *tn;
{
void doopt(),dontopt(),willopt(),wontopt(),answer();
register int i;
register struct mbuf *bp;
char c;
bp = tn->inbuf;
/* Optimization for very common special case -- no special chars */
if(tn->state == TS_DATA){
while(bp != NULLBUF &&
memchr(bp->data,IAC,(int)bp->cnt) == NULLCHAR) {
if((i = write(tn->fd, bp->data, (int)bp->cnt)) == bp->cnt) {
tn->inbuf = bp = free_mbuf(bp);
} else if(i == -1) {
log(tn->tcb,"error Telunix - write (%d %d %d)",
errno, tn->fd, bp->cnt);
close_tcp(tn->tcb);
return;
} else {
bp->cnt -= i;
bp->data += i;
return;
}
}
if(bp == NULLBUF)
return;
}
while(pullup(&(tn->inbuf),&c,1) == 1){
bp = tn->inbuf;
switch(tn->state){
case TS_DATA:
if(uchar(c) == IAC){
tn->state = TS_IAC;
} else {
if(!tn->remote[TN_TRANSMIT_BINARY])
c &= 0x7f;
if(write(tn->fd, &c, 1) != 1) {
/* we drop a character here */
return;
}
}
break;
case TS_IAC:
switch(uchar(c)){
case WILL:
tn->state = TS_WILL;
break;
case WONT:
tn->state = TS_WONT;
break;
case DO:
tn->state = TS_DO;
break;
case DONT:
tn->state = TS_DONT;
break;
case IAC:
if(write(tn->fd, &c, 1) != 1) {
/* we drop a character here */
return;
}
tn->state = TS_DATA;
break;
default:
tn->state = TS_DATA;
break;
}
break;
case TS_WILL:
willopt(tn,c);
tn->state = TS_DATA;
break;
case TS_WONT:
wontopt(tn,c);
tn->state = TS_DATA;
break;
case TS_DO:
doopt(tn,c);
tn->state = TS_DATA;
break;
case TS_DONT:
dontopt(tn,c);
tn->state = TS_DATA;
break;
}
}
}
/* called periodically from main loop */
void
tnix_scan()
{
void tnix_try();
register int i;
for(i = 0; i < TUMAXSCAN; i += 1)
if(tnixtcb[i] != NULLTCB)
tnix_try(tnixtcb[i]);
}
int
tnix_addscan(tcb)
struct tcb *tcb;
{
register int i;
for(i = 0; i < TUMAXSCAN; i += 1)
if(tnixtcb[i] == NULLTCB) {
tnixtcb[i] = tcb;
return i;
}
return -1;
}
void
tnix_rmvscan(tcb)
struct tcb *tcb;
{
register int i;
for(i = 0; i < TUMAXSCAN; i += 1)
if(tnixtcb[i] == tcb)
tnixtcb[i] = NULLTCB;
}