home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
rxtelnet.zip
/
nvt
/
nvt.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-08-19
|
17KB
|
804 lines
#define INCL_DOS
#define INCL_DOSERRORS
#include <os2.h>
// #include <ctype.h>
#include <memory.h>
#include <stddef.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys\socket.h>
#include "telnet.h"
#include "nvt.h"
#include "ascii.h"
/* structure definitions */
#pragma pack(2)
typedef
struct _linkitem /* linked list items */
{
struct _linkitem *next; /* next in list */
short length; /* length of item */
char data[2]; /* start of item data */
}
linkitem;
typedef linkitem *linked;
#pragma pack()
typedef
struct _NVT /* NVT control area */
{
PVOID pool; /* common storage pool */
HEV available; /* storage available event */
HMTX lock; /* mutex lock semaphore */
HMTX sending; /* send() lock */
HEV ready; /* inbound data event */
linked pending; /* ready data queue */
short ind; /* operational indicators */
short echoing; /* echoes pending */
TID device; /* receiver thread id */
int sockit; /* socket handle */
unsigned long host; /* host address */
unsigned long port; /* port address */
}
NVT;
/* function prototypes */
#define intern static
intern int cmdkey( char *c );
intern char* cmdstr( int i );
intern unsigned long hostaddress( char *cp );
intern int pop( HMTX lock, linked *list, linked *item );
intern int push( HMTX lock, linked *list, linked item );
intern int queue( HMTX lock, linked *list, linked item );
intern int wait( HEV event, int timeout );
intern int post( HEV event );
intern void* allocpool( void );
intern void* relsepool( void* pool );
intern void* alloc( void* pool, int bufsize );
intern void* relse( void* pool, void* buf, int bufsize );
intern int nvtransmit( NVT *vt, char *buf, int bufsize, int crlf );
intern VOID APIENTRY nvtprotocol( ULONG parm );
intern int nvtenq( NVT *vt, char *buf, int bufsize );
intern int nvtdeq( NVT *vt, char *buf, int bufsize );
#define nvtptr(handle) (NVT*)((handle))
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
HNVT nvtopen( char *hostname, int port )
{
int rc = ERROR_NOT_ENOUGH_MEMORY;
NVT *vt = NULL;
PVOID pool = allocpool();
if ( pool )
{
vt = alloc( pool, sizeof(*vt) );
if ( vt )
{
memset( vt, 0, sizeof(*vt) );
vt->pool = pool;
rc = ( DosCreateEventSem( NULL, &(vt->available), 0, FALSE ) ||
DosCreateEventSem( NULL, &(vt->ready), 0, FALSE ) ||
DosCreateMutexSem( NULL, &(vt->sending), 0, FALSE ) ||
DosCreateMutexSem( NULL, &(vt->lock), 0, FALSE ) );
if ( !rc )
{
rc = DosCreateThread( &(vt->device),
nvtprotocol, (ULONG)vt,
CREATE_SUSPENDED |
STACK_SPARSE,
65536UL );
if ( !rc )
{
vt->host = hostaddress( hostname );
if ( vt->host == 0 || vt->host == INADDR_NONE )
rc = 1;
else
{
vt->sockit = socket( PF_INET, SOCK_STREAM, 0 );
if ( vt->sockit == -1 )
rc = 1;
else
{
struct sockaddr_in server;
memset( &server, 0, sizeof(server) );
vt->port = port ? port : DEFAULTPORT;
server.sin_family = AF_INET;
server.sin_port = htons(vt->port);
server.sin_addr.s_addr = vt->host;
rc = connect( vt->sockit,
(struct sockaddr *)&server,
sizeof(server) );
if ( !rc )
{
vt->pending = NULL;
vt->echoing = 0;
rc = DosResumeThread( vt->device );
}
}
}
}
}
if ( rc )
{
nvtclose( (HNVT)vt );
vt = NULL;
}
}
}
return (HNVT)vt;
}
int nvtclose( HNVT hnvt )
{
int rc;
NVT *vt = nvtptr(hnvt);
if ( vt->device )
rc = DosKillThread( vt->device );
if ( vt->available )
rc = DosCloseEventSem( vt->available );
if ( vt->ready )
rc = DosCloseEventSem( vt->ready );
if ( vt->sending )
rc = DosCloseMutexSem( vt->sending );
if ( vt->lock )
rc = DosCloseMutexSem( vt->lock );
if ( vt->sockit )
{
rc = shutdown( vt->sockit, 2 );
rc = soclose( vt->sockit );
}
if ( vt->pool )
relsepool( vt->pool );
return 0;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int nvtcommand( HNVT hnvt, char *command )
{
int count = 0;
char cmd[3];
cmd[0] = IAC;
cmd[1] = cmdkey( command );
if ( cmd[1] )
count = nvtransmit( nvtptr(hnvt), cmd, 2, FALSE );
return count;
}
int nvtquery( HNVT hnvt, LNVT* link )
{
if ( link )
{
NVT *vt = nvtptr(hnvt);
link->addr = vt->host;
link->port = vt->port;
link->socket = vt->sockit;
}
return sock_errno();
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int nvtputs( HNVT hnvt, char *buf, int bufsize )
{
NVT *vt = nvtptr(hnvt);
if ( vt->echoing )
vt->echoing += 1;
return nvtransmit( vt, buf, bufsize, TRUE );
}
int nvtgets( HNVT hnvt, char *buf, int bufsize )
{
int count = nvtdeq( nvtptr(hnvt), buf, bufsize-1 );
if ( count >= 0 )
buf[count] = '\0';
return count;
}
int nvtpeek( HNVT hnvt, int timeout )
{
NVT *vt = nvtptr(hnvt);
wait( vt->ready, timeout );
return vt->pending ? 1 : 0;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int nvtenq( NVT *vt, char *buf, int bufsize )
{
linked i = NULL;
do { i = alloc( vt->pool, bufsize + offsetof(linkitem,data) ); }
while ( !i && 0 == wait( vt->available, -1 ) );
if ( i )
{
if ( bufsize )
memcpy( i->data, buf, bufsize );
i->length = bufsize;
queue( vt->lock, &(vt->pending), i );
post( vt->ready );
}
else
{
bufsize = -bufsize;
}
return bufsize;
}
int nvtdeq( NVT *vt, char *buf, int bufsize )
{
linked i = NULL;
do { pop( vt->lock, &(vt->pending), &i ); }
while ( !i && 0 == wait( vt->ready, -1 ) );
if ( !i )
{
buf = '\0';
bufsize = 0;
}
else
{
if ( i->length > bufsize )
{
buf = '\0';
bufsize = -(i->length);
push( vt->lock, &(vt->pending), i );
}
else
{
if ( i->length )
{
memcpy( buf, i->data, i->length );
bufsize = i->length;
}
else
{
buf[0] = '\r';
bufsize = 1;
}
relse( vt->pool, i, i->length + offsetof(linkitem,data) );
post( vt->available );
}
}
return bufsize;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int nvtransmit( NVT *vt, char *buf, int bufsize, int crlf )
{
int count = 0;
int used = 0;
APIRET rc = DosRequestMutexSem( vt->sending, SEM_INDEFINITE_WAIT );
if ( !rc )
{
if ( !bufsize )
count = 1;
else
do
{
count = send( vt->sockit, buf, bufsize, 0 );
bufsize -= count;
buf += count;
used += count;
}
while ( count > 0 && bufsize );
if ( count > 0 )
{
count = used;
if ( crlf )
used = send( vt->sockit, "\r\n", 2, 0 );
}
rc = DosReleaseMutexSem( vt->sending );
}
return count;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#define TEXT (LO_ASCII)
#define NOTEXT (TEXT-1)
#define SB_END (HI_ASCII+1)
intern int copy( char *to, char *from )
{
int count = 0;
while ( *from ) { *to++ = *from++; count++; }
return count;
}
int nvtline( NVT *vt, char *line, int used )
{
if ( vt->echoing > 1 )
{
vt->echoing -= 1;
line -= 1;
used += 1;
line[0] = ACK;
}
if ( used )
used = nvtenq( vt, line, used );
return used;
}
VOID APIENTRY nvtprotocol( ULONG parm )
{
NVT *vt = nvtptr(parm);
char buf[MAXLINESIZE];
char *next;
char ch;
long timeout = RECVTIMEOUT;
int socks[1];
char will[4] = { IAC, WILL, 0, 0 };
char willnot[4] = { IAC, WONT, 0, 0 };
char donot[4] = { IAC, DONT, 0, 0 };
char text[MAXLINESIZE+1];
char *line = text+1;
int linesize = sizeof(text)-1;
char *current = line;
int used = 0;
int mode = TEXT;
int count = 0;
while( mode )
{
if ( count < 1 )
{
socks[0] = vt->sockit;
count = select( socks, 1, 0, 0, timeout );
if ( count == 0 )
{
timeout = -1;
if ( used )
buf[count++] = LF;
buf[count++] = EOT;
buf[count++] = LF;
}
else
if ( count > 0 )
{
timeout = RECVTIMEOUT;
count = recv( vt->sockit, buf, sizeof(buf)-1, 0 );
}
if ( count > 0 )
{
next = buf;
}
else
{
/* if count < 0 then socket error */
/* if count = 0 then socket closed */
mode = 0;
break;
}
}
/* begin telnet stream state machine */
ch = *next;
switch ( mode )
{
case TEXT: switch ( ch )
{
case IAC:
case CR: mode = ch;
goto NEXT;
case LF: goto CRLF;
case EOT: goto USE;
default: if ( ch < 0x80 ) goto USE; /* _isascii(ch) */
}
goto NEXT;
case CR: switch( ch )
{
case NUL:
case LF: mode = TEXT;
goto CRLF;
}
mode = TEXT;
goto NEXT;
case IAC: switch( ch )
{
case DO:
case DONT:
case WILL:
case WONT: mode = ch;
goto NEXT;
case SB: mode = ch;
goto NEXT;
case EC: if ( used ) { current--; used--; }
mode = TEXT;
goto NEXT;
case EL: mode = TEXT;
goto NL;
/* generate a command message */
case ABORT:
case AO:
case AYT:
case BREAK:
case EOR:
case xEOF:
case GA:
case IP:
case NOP:
case SUSP:
nvtline( vt, line, used );
line[0] = ENQ;
used = 1 + copy( line+1, cmdstr(ch) );
mode = TEXT;
goto CRLF;
case DM: mode = TEXT;
goto NL;
}
mode = TEXT;
goto NEXT;
case DO:
case DONT: willnot[2] = ch;
nvtransmit( vt, willnot, 3, FALSE );
mode = TEXT;
goto NEXT;
case WILL: switch( ch )
{
case TELOPT_ECHO: vt->echoing = 1;
}
mode = TEXT;
goto NEXT;
case WONT: switch( ch )
{
case TELOPT_ECHO: vt->echoing = 0;
}
mode = TEXT;
goto NEXT;
case SB: switch( ch )
{
case IAC: mode = SB_END;
goto NEXT;
}
goto NEXT;
case SB_END: switch( ch )
{
case SE: mode = TEXT;
goto NEXT;
}
mode = SB;
goto NEXT;
default: mode = TEXT;
goto NEXT;
}
USE:
*current = ch;
current++;
used++;
if ( used < linesize )
goto NEXT;
CRLF:
nvtline( vt, line, used );
NL:
current = line;
used = 0;
NEXT:
next++;
count--;
/* end telnet stream state machine */
}
nvtline( vt, line, used );
if ( count < 0 ) /* socket error */
{
line[0] = ENQ;
line[1] = 'E';
_itoa( sock_errno(), line+2, 10 );
used = strlen(line);
nvtline( vt, line, used );
}
DosPostEventSem( vt->ready );
DosCloseEventSem( vt->ready );
DosExit(0,0);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
typedef struct { int i; char *c; } tcmd;
intern tcmd tcmds[] = { GA, _GA,
AYT, _AYT,
AO, _AO,
IP, _IP,
BREAK, _BREAK,
NOP, _NOP,
EOR, _EOR,
ABORT, _ABORT,
SUSP, _SUSP,
xEOF, _EOF,
0, "?" };
intern int different( char* l, char* s )
{
while ( *l && *s && *l == ( *s & ~0x20 ) ) { l++; s++; } /* _toupper(*s) */
return ( *l || *s ) ? 1 : 0;
}
int cmdkey( char *c )
{
tcmd *t = tcmds;
while ( t->i && different(t->c,c) ) t++;
return t->i;
}
char* cmdstr( int i )
{
tcmd *t = tcmds;
while ( t->i && t->i != i ) t++;
return t->c;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int pop( HMTX lock, linked *list, linked *item )
{
linked i = NULL;
APIRET rc = DosRequestMutexSem( lock, SEM_INDEFINITE_WAIT );
if ( !rc )
{
i = *list;
if ( i ) *list = i->next;
rc = DosReleaseMutexSem( lock );
}
*item = i;
return rc ? 0 : 1;
}
int push( HMTX lock, linked *list, linked item )
{
APIRET rc = DosRequestMutexSem( lock, SEM_INDEFINITE_WAIT );
if ( !rc )
{
item->next = *list;
*list = item;
rc = DosReleaseMutexSem( lock );
}
return rc ? 0 : 1;
}
int queue( HMTX lock, linked *list, linked item )
{
APIRET rc = DosRequestMutexSem( lock, SEM_INDEFINITE_WAIT );
if ( !rc )
{
item->next = NULL;
if ( *list )
{
linked i = *list;
while ( i && i->next ) i = i->next;
i->next = item;
}
else
{
*list = item;
}
rc = DosReleaseMutexSem( lock );
}
return rc ? 0 : 1;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#define PAGESIZE 4096
void* allocpool()
{
APIRET rc;
PVOID pool = NULL;
rc = DosAllocMem( &pool,
PAGESIZE,
PAG_READ | PAG_WRITE );
if ( !rc )
rc = DosSubSetMem( pool,
DOSSUB_INIT |
DOSSUB_SERIALIZE |
DOSSUB_SPARSE_OBJ,
PAGESIZE );
return pool;
}
void* relsepool( void* pool )
{
APIRET rc;
if ( pool )
{
rc = DosSubUnsetMem( pool );
rc = DosFreeMem( pool );
pool = NULL;
}
return pool;
}
void* alloc( void* pool, int bufsize )
{
APIRET rc = 1;
PVOID buf;
if ( pool )
rc = DosSubAllocMem( pool, &buf, bufsize );
return rc ? NULL : buf;
}
void* relse( void* pool, void* buf, int bufsize )
{
APIRET rc = 1;
if ( pool )
rc = DosSubFreeMem( pool, buf, bufsize );
return rc ? buf : NULL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int wait( HEV event, int timeout )
{
int rc = DosWaitEventSem( event, timeout );
if ( !rc )
{
ULONG count;
rc = DosResetEventSem( event, &count );
}
return rc;
}
int post( HEV event )
{
return DosPostEventSem( event );
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
unsigned long hostaddress( char *cp )
{
unsigned long address = inet_addr( cp );
if ( address == 0 || address == INADDR_NONE )
{
struct hostent *hp = gethostbyname( cp );
if ( hp )
address = *((unsigned long *)(hp->h_addr));
}
return address;
}