home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
kermit.columbia.edu
/
kermit.columbia.edu.tar
/
kermit.columbia.edu
/
tmp9
/
ckoslp.c
< prev
next >
Wrap
C/C++ Source or Header
|
2011-07-19
|
48KB
|
1,193 lines
/* C K O S L P -- Kermit interface to the IBM SLIP driver */
/*
Authors: Jeffrey Altman (jaltman@secure-endpoints.com),
Secure Endpoints Inc., New York City.
David Bolen (db3l@ans.net)
Copyright (C) 1985, 2004, Trustees of Columbia University in the City of New
York.
*/
#include "ckcdeb.h"
#ifndef NT
#define INCL_ERRORS
#define INCL_DOSMISC
#define INCL_DOSPROCESS
#define INCL_DOSSEMAPHORES
#define INCL_DOSNMPIPES
#include <os2.h>
#undef COMMENT
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include "ckoslp.h"
/*--------------------------------------------------------------------------*/
/* Definitions used for interface information */
/*--------------------------------------------------------------------------*/
/* VJ Compression Options */
#define slc_NOCOMPRESSION 0 /* No compression at all */
#define slc_COMPRESSION 1 /* Always send compression */
#define slc_AUTOCOMPRESSION 2 /* Enable compression when received */
/*--------------------------------------------------------------------------*/
/* Interface structure (used to return interface configuration information) */
/*--------------------------------------------------------------------------*/
typedef struct slcS_INTERFACE_ {
/* -- INET Attachment Information -- */
char if_name[4]; /* sl? (?=0-9) */
unsigned short if_mtu; /* MTU for interface */
unsigned short if_rtt; /* Estimated rtt, rttvar and rttmin */
unsigned short if_rttvar; /* for routes making use of this */
unsigned short if_rttmin; /* interface (in ms) */
unsigned short if_sendpipe; /* Maximum send/recv pipes (socket */
unsigned short if_recvpipe; /* buffers and TCP windows) */
unsigned short if_ssthresh; /* Slow-start threshold (segments) */
unsigned short if_maxqueue; /* Maximum interface queue size */
unsigned short if_maxfastq; /* Maximum fast queue size */
/* -- Other Interface Settings -- */
int allowfastq, /* Should fast queueing be used */
compression; /* VJ compression options */
char *device; /* OS/2 device for interface */
/* -- Interface Command Scripts -- */
char *attachcmd,
*attachparms; /* and their parameters */
struct slcS_INTERFACE_ *next; /* Pointer to next parsed interface */
} slcS_INTERFACE, *slcPS_INTERFACE;
/*--------------------------------------------------------------------------*/
/* Function prototypes. */
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------*/
/* Parsing Functions */
/*--------------------------------------------------*/
int slcParseConfiguration (char *Filename, slcPS_INTERFACE *Interfaces);
int slcFreeConfiguration (slcPS_INTERFACE *Interfaces);
/*
* Variables
*/
/* Semaphores and Pipe for communicating with SLIP.EXE */
HEV hevSlipMonitor = 0,
hevSlipPause = 0,
hevSlipPaused = 0,
hevSlipContinue = 0;
HPIPE hpipeSlip = 0 ;
PSZ
SlipCfgFile( void )
{
static PSZ slipcfgfile = 0 ; /* Config file name */
char * etc ;
if ( slipcfgfile )
return slipcfgfile ;
if ( ( etc = getenv( "ETC" ) ) == NULL ) {
slipcfgfile = "" ;
return slipcfgfile ;
}
slipcfgfile = malloc( strlen( etc ) + 10 ) ;
strcpy( slipcfgfile, etc ) ;
strcat( slipcfgfile, "\\slip.cfg" ) ;
return slipcfgfile ;
}
PSZ
PPPCfgFile( void )
{
static PSZ pppcfgfile = 0 ; /* Config file name */
char * etc ;
if ( pppcfgfile )
return pppcfgfile ;
if ( ( etc = getenv( "ETC" ) ) == NULL ) {
pppcfgfile = "" ;
return pppcfgfile ;
}
pppcfgfile = malloc( strlen( etc ) + 10 ) ;
strcpy( pppcfgfile, etc ) ;
strcat( pppcfgfile, "\\ppp.cfg" ) ;
return pppcfgfile ;
}
APIRET
SlipOpen( char * device )
{
APIRET rc ;
ULONG action, actual ;
char interface[4] ;
slcPS_INTERFACE pInterfaces = 0,
pInterface = 0 ; /* Ptr to S_INTERFACE structure */
if ( rc = slcParseConfiguration ( SlipCfgFile(), &pInterfaces ) ) {
printf("Unable to parse %s\n",SlipCfgFile() );
return rc ;
}
/* Find the proper interface to use */
interface[0] = '\0' ;
pInterface = pInterfaces ;
do
{
if ( !strcmp( strlwr(pInterface->device), device ) ) {
strcpy( interface, pInterface->if_name ) ;
break;
}
pInterface = pInterface->next ;
}
while ( pInterface != NULL );
if ( interface[0] == '\0' ) {
printf("%s is not listed in %s\n",device,SlipCfgFile());
slcFreeConfiguration( &pInterfaces ) ;
return 1 ;
}
if (!(rc = DosOpenEventSem( "\\sem32\\slip\\monitor",
&hevSlipMonitor )))
if(!(rc = DosOpenEventSem( "\\sem32\\slip\\com\\pause",
&hevSlipPause )))
if(!(rc = DosOpenEventSem( "\\sem32\\slip\\com\\paused",
&hevSlipPaused)))
if (!(rc = DosOpenEventSem( "\\sem32\\slip\\com\\continue",
&hevSlipContinue)))
rc = DosOpen( "\\pipe\\slip", &hpipeSlip, &action, 0,
FILE_NORMAL, FILE_OPEN, OPEN_ACCESS_READWRITE |
OPEN_SHARE_DENYNONE, NULL ) ;
if ( !rc ) {
int PauseCount = 0 ;
DosWrite( hpipeSlip, interface, 4, &actual ) ;
do {
if (PauseCount)
msleep(500);
PauseCount++ ;
rc = DosPostEventSem( hevSlipPause ) ;
} while ( PauseCount <= 10 && rc == ERROR_ALREADY_POSTED ) ;
if (!rc)
rc =DosWaitEventSem( hevSlipPaused, SEM_INDEFINITE_WAIT ) ;
}
slcFreeConfiguration( &pInterfaces ) ;
return rc ;
}
APIRET
PPPOpen( char * device )
{
extern int ttppp;
APIRET rc ;
ULONG action, actual ;
UCHAR MonitorSem[32] ;
UCHAR PauseSem[32];
UCHAR PausedSem[32];
UCHAR ContinueSem[32];
char interface[8] ;
slcPS_INTERFACE pInterfaces = 0,
pInterface = 0 ; /* Ptr to S_INTERFACE structure */
sprintf(interface, "ppp%d", ttppp-1 );
/* Create the Sem strings to use */
sprintf(MonitorSem, "\\sem32\\ppp%d\\monitor", ttppp-1);
sprintf(PauseSem, "\\sem32\\ppp%d\\pause", ttppp-1);
sprintf(PausedSem, "\\sem32\\ppp%d\\paused", ttppp-1);
sprintf(ContinueSem, "\\sem32\\ppp%d\\continue", ttppp-1);
/* Find the proper interface to use */
if (!(rc = DosOpenEventSem( MonitorSem, &hevSlipMonitor )))
if(!(rc = DosOpenEventSem( PauseSem, &hevSlipPause )))
if(!(rc = DosOpenEventSem( PausedSem, &hevSlipPaused)))
if (!(rc = DosOpenEventSem( ContinueSem, &hevSlipContinue)))
rc = DosOpen( "\\pipe\\ppp", &hpipeSlip, &action, 0,
FILE_NORMAL, FILE_OPEN, OPEN_ACCESS_READWRITE |
OPEN_SHARE_DENYNONE, NULL ) ;
if ( !rc ) {
int PauseCount = 0 ;
DosWrite( hpipeSlip, interface, 4, &actual ) ;
do {
if (PauseCount)
msleep(500);
PauseCount++ ;
rc = DosPostEventSem( hevSlipPause ) ;
} while ( PauseCount <= 10 && rc == ERROR_ALREADY_POSTED ) ;
if (!rc)
rc =DosWaitEventSem( hevSlipPaused, SEM_INDEFINITE_WAIT ) ;
}
return rc ;
}
void
PPPSlipClose( void )
{
if ( hevSlipMonitor )
{
DosPostEventSem( hevSlipContinue ) ; /* give the port back */
/* to the slip driver */
DosCloseEventSem( hevSlipContinue ) ;
DosCloseEventSem( hevSlipPaused ) ;
DosCloseEventSem( hevSlipPause ) ;
DosCloseEventSem( hevSlipMonitor ) ;
hevSlipMonitor = 0 ;
hevSlipPaused = 0 ;
hevSlipPause = 0 ;
hevSlipContinue = 0 ;
}
if ( hpipeSlip ) {
DosClose( hpipeSlip ) ;
hpipeSlip = 0 ;
}
}
/*==========================================================================*/
/* */
/* -------------------------------------------------- */
/* */
/* PRIVATE DATA/FUNCTIONS */
/* */
/* -------------------------------------------------- */
/* */
/*==========================================================================*/
/*--------------------------------------------------------------------------*/
/* Macro/Constant definitions */
/*--------------------------------------------------------------------------*/
#define _slcC_BUFSIZE 512 /* Maximum "chunks" used for config file */
#define _slcC_ERRSIZE 256 /* Maximum size for a single error message */
#define _slcC_TOKSIZE 64 /* Maximum size for "tokens" in config file */
#define _slcC_TOKEN_NONE 0 /* Token types */
#define _slcC_TOKEN_TOOLONG 1
#define _slcC_TOKEN_ERROR 1 /* < this indicates an error token */
#define _slcC_TOKEN_EOF 10 /* Success tokens */
#define _slcC_TOKEN_TEXT 11
#define _slcC_TOKEN_EQUAL 12
#define _slcC_TOKEN_LBRACE 13
#define _slcC_TOKEN_RBRACE 14
#define _slcC_TOKENTBL_TERM 1000 /* Must be > max entries in any table */
/*--------------------------------------------------------------------------*/
/* Structure declarations */
/*--------------------------------------------------------------------------*/
typedef struct _slcS_TOKEN_ {
int type, length; /* Type of token and text length */
char text[_slcC_TOKSIZE+1]; /* Remember room for terminating NULL */
} _slcS_TOKEN, *_slcPS_TOKEN;
typedef struct _slcS_TOKENTBL_ { /* Map of text tokens to cmd/parm values */
int command; /* Really an _slcE* type */
char *name; /* Actual text of the cmd/element/value */
int valuetype, /* For parms, >0 means need value. 1 is */
minimum, maximum; /* string, 2=number what range is ok */
} _slcS_TOKENTBL, *_slcPS_TOKENTBL;
/*--------------------------------------------------------------------------*/
/* Declarations for commands/elements and values allowed within the */
/* configuration file. */
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------*/
/* Configuration file commands */
/*--------------------------------------------------*/
#define _slcA_CMD_INTERFACE "interface"
typedef enum {cmd_interface} _slcE_CMD;
/*--------------------------------------------------*/
/* "Interface" command parameters */
/*--------------------------------------------------*/
#define _slcA_INTF_DEVICE "device"
#define _slcA_INTF_MTU "mtu"
#define _slcA_INTF_RTT "rtt"
#define _slcA_INTF_RTTVAR "rttvar"
#define _slcA_INTF_RTTMIN "rttmin"
#define _slcA_INTF_SENDPIPE "sendpipe"
#define _slcA_INTF_RECVPIPE "recvpipe"
#define _slcA_INTF_SSTHRESH "ssthresh"
#define _slcA_INTF_QUEUESIZE "queuesize"
#define _slcA_INTF_FASTQUEUESIZE "fastqueuesize"
#define _slcA_INTF_FASTQUEUE "fastqueue"
#define _slcA_INTF_NOFASTQUEUE "nofastqueue"
#define _slcA_INTF_COMPRESSION "compression"
#define _slcA_INTF_ATTACHCMD "attachcmd"
#define _slcA_INTF_ATTACHPARMS "attachparms"
typedef enum {intf_device, intf_mtu, intf_rtt, intf_rttvar, intf_rttmin,
intf_sendpipe, intf_recvpipe, intf_ssthresh,
intf_queuesize, intf_fastqueuesize, intf_fastqueue,
intf_nofastqueue, intf_compression, intf_attachcmd,
intf_attachparms} _slcE_INTF;
/*--------------------------------------------------------------------------*/
/* Module-global data */
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------*/
/* Token error table */
/*--------------------------------------------------*/
char *_slc_TokenErrorTable[] = { /* WARNING: Keep in same order as codes */
"No token", "Token too long" };
/*--------------------------------------------------*/
/* Token tables for commands/parameters */
/*--------------------------------------------------*/
_slcS_TOKENTBL _slc_CmdTable[] = {
{cmd_interface, _slcA_CMD_INTERFACE,0},
{_slcC_TOKENTBL_TERM, "",0} };
_slcS_TOKENTBL _slc_IntfTable[] = {
{intf_device, _slcA_INTF_DEVICE,1},
{intf_mtu, _slcA_INTF_MTU,2,64,2048},
{intf_rtt, _slcA_INTF_RTT,2,0,65536},
{intf_rttvar, _slcA_INTF_RTTVAR,2,0,65536},
{intf_rttmin, _slcA_INTF_RTTMIN,3,0,65536},
{intf_sendpipe, _slcA_INTF_SENDPIPE,2,0,65536},
{intf_recvpipe, _slcA_INTF_RECVPIPE,2,0,65536},
{intf_ssthresh, _slcA_INTF_SSTHRESH,2,0,65536},
{intf_queuesize, _slcA_INTF_QUEUESIZE,2,4,52},
{intf_fastqueuesize, _slcA_INTF_FASTQUEUESIZE,2,4,52},
{intf_fastqueue, _slcA_INTF_FASTQUEUE,0},
{intf_nofastqueue, _slcA_INTF_NOFASTQUEUE,0},
{intf_compression, _slcA_INTF_COMPRESSION,1},
{intf_attachcmd, _slcA_INTF_ATTACHCMD,1},
{intf_attachparms, _slcA_INTF_ATTACHPARMS,1},
{_slcC_TOKENTBL_TERM,""} };
/*--------------------------------------------------------------------------*/
/* int _slcGetCh (FILE *RuleFile; int SkipWS, MergeWS, *Line, *Pos) */
/*..........................................................................*/
/* */
/* Retrieves the next "character" from the rule file, fetching new lines */
/* from the file as necessary. If MergeWS is 1, then any whitespace (tabs, */
/* spaces or newlines) is always returned as a space. If SkipWS is 1, then */
/* any grouping of whitespace is returned as a single space character (or */
/* whatever WS character is first in the group if MergeWS is 0). */
/* */
/* Comments are set via the # character and can appear anywhere within a */
/* line. Any text following the # will be ignored. */
/* */
/* Parsing state information is returned in one or both of the Line and Pos */
/* parameters (if they are non-NULL). Line represents the line number in */
/* the file and Pos the position within the line (both origin 1) of the */
/* character being returned by this function. */
/* */
/* The function returns EOF when end of file is reached. */
/* */
/* To avoid having to export parsing state information from this function, */
/* a special calling convention of RuleFile==NULL is used in order to */
/* initializing the internal buffer and counters for a new file. */
/* */
/*--------------------------------------------------------------------------*/
int _slcGetCh (FILE *RuleFile, int SkipWS, int MergeWS,
int *Line, int *Pos)
{
static char buffer[_slcC_BUFSIZE], *curch;
static int full_line, /* Does buffer represent a full line */
in_comment, /* Current buffer holds partial comment */
curline, /* Current line/position information */
curpos;
int done, result;
char *ch;
/* Special argument of RuleFile==NULL means initialize */
if (RuleFile == NULL) {
curline = curpos = in_comment = 0;
buffer[0] = '\0';
curch = buffer;
full_line = 0;
return(0);
}
/* Run until we have a suitable character to return */
done = 0;
result = EOF;
while (!done) {
/*--------------------------------------------------*/
/* 1. If we need a new line from the file go get it */
/*--------------------------------------------------*/
if (*curch == '\0') {
buffer[_slcC_BUFSIZE-2] = '\0'; /* For quick full_line check */
/* For now a read error and EOF are both returned as EOF, */
/* so I just check for NULL and don't bother with feof() */
if (fgets(buffer,_slcC_BUFSIZE,RuleFile) == NULL) {
result = EOF;
break; /* EOF - get out of here */
} else {
/* Reset current character pointer */
curch = buffer;
/* If last line was full, bump linecount, and init pos count */
if (full_line) {
curline++;
curpos = 0;
}
/* Then decide if we got a whole line this time. By checking */
/* the next to last character (initialized above), we avoid */
/* the need to call strlen for each line read. */
full_line = (buffer[_slcC_BUFSIZE-2] == '\0' ||
buffer[_slcC_BUFSIZE-2] == '\n');
/* Early-out. If already in comment (true if a line with # is */
/* >_slcC_BUFSIZE characters), just ignore this line entirely, */
/* resetting in_comment only if we got all of rest of line. */
if (in_comment) {
if (full_line) in_comment = 0;
/* Nullify line - don't worry about WS - the leading # on */
/* this comment would already have been treated as a ' '. */
buffer[0] = '\0';
} else {
/* Otherwise, check for \n or #. If found, convert to space */
/* and terminate the string at that point. We need a space */
/* to insure parsing "aa\n\nbb" separates "aa" and "bb". */
ch = buffer;
while (*ch) {
if (*ch == '#' || *ch == '\n') {
/* Might need to set flag for long comments */
if (*ch == '#' && !full_line) in_comment = 1;
*ch++ = ' ';
*ch = '\0';
break;
} else {
ch++;
}
}
} /* \n and # scan */
} /* if got good line */
continue; /* back and keep trying */
}
/*--------------------------------------------------*/
/* 2. Now we have a null terminated buffer. If on */
/* WS find first non-WS, otherwise bump curch */
/* by 1. Then if SkipWS always return non-WS, */
/* otherwise return space if we started on a WS. */
/* Note that we only set result if it isn't set */
/* already since this may run several times in */
/* order to skip over lines of whitespace. */
/*--------------------------------------------------*/
if (result == EOF) {
result = *curch;
if (MergeWS && isspace(result)) result = ' ';
/* If caller wants, store line/position information for this char */
/* (remembering that we are origin 0, but returning origin 1) */
if (Line != NULL) *Line = curline+1;
if (Pos != NULL) *Pos = curpos+1;
}
if (isspace(result) && SkipWS) {
/* Find first non-WS */
while (*curch && isspace(*curch)) {
/* Account for tabs here - assume standard expansion of 8 */
if (*curch == '\t') {
curpos = ((curpos / 8)+1) * 8;
} else {
curpos++;
}
curch++;
}
done = (*curch); /* We're only done if we didn't run out */
} else {
curch++;
curpos++;
done = 1;
}
} /* while !done */
return(result);
}
/*--------------------------------------------------------------------------*/
/* int _slcGetToken (FILE *RuleFile; _slcPS_TOKEN Token; int *Line, *Pos) */
/*..........................................................................*/
/* */
/* Grabs the next "token" from the specified file, identifies it, and */
/* returns it in the supplied token structure. The maximum number of */
/* characters in a token cannot exceed _slcC_TOKSIZE. */
/* */
/* The rules for breaking apart tokens is pretty simple. The following */
/* characters are treated specially: */
/* WS | , Separates tokens */
/* = Special token - separates a rule element from its value. */
/* { Special token - begins a list of rule elements. */
/* } Special token - terminates a list of rule elements. */
/* The text that created the special tokens is still stored in Token.text. */
/* */
/* Any of these characters may be quoted with the use of the \ character */
/* (\\ for \ itself), or may be enclosed within double quotes (") to quote */
/* an entire string. Note that the \ character is processed even inside */
/* quotes, so it must be doubled to yield itself or can also be used to */
/* quote a quote, so to speak. */
/* */
/* If either of the Line or Pos parameters is non-NULL, then the file line */
/* and character position of the start of the returned token are stored in */
/* the address(es) they point to. */
/* */
/*--------------------------------------------------------------------------*/
#define _slc_ADDCHAR(token,ch) if (chcount<_slcC_TOKSIZE) { \
token->text[chcount++] = ch; \
line = pos = NULL; \
} else { \
token->type = _slcC_TOKEN_TOOLONG; \
break; \
}
int _slcGetToken (FILE *RuleFile, _slcPS_TOKEN Token, int *Line, int *Pos)
{
static int lastch=EOF;
char *curch;
int ch, chcount=0, intoken=1, skipws=1, inbslash=0, inquote=0;
int *line, *pos;
curch = Token->text;
line = Line;
pos = Pos;
while (intoken) {
if (lastch != EOF) {
ch = lastch;
lastch = EOF;
} else {
ch = _slcGetCh(RuleFile,skipws,skipws,line,pos);
}
/* Handle special quoting stuff first */
if (inbslash) { /* \ always quotes next character, even \ */
/* NEED EOF CHECK */
_slc_ADDCHAR(Token,ch);
inbslash = 0;
skipws = !inquote;
continue;
}
if (ch == '\\') { /* Prepare to quote next character */
inbslash = 1;
skipws = 0;
continue;
}
if (inquote) { /* Unless terminating ", just add next char */
/* NEED EOF CHECK */
if (ch == '"') {
inquote = 0;
skipws = 1;
} else {
_slc_ADDCHAR(Token,ch);
}
continue;
}
/* Then normal character processing */
switch (ch) {
case EOF: /* We've hit end of input file */
if (chcount > 0) {
Token->type = _slcC_TOKEN_TEXT;
lastch = ch; /* this avoids calling GetCh again */
} else {
Token->type = _slcC_TOKEN_EOF;
}
intoken = 0;
break;
case ' ': /* Whitespace */
case ',': /* Or comma */
if (chcount > 0) {
Token->type = _slcC_TOKEN_TEXT;
intoken = 0;
}
break;
case '"': /* Start quoting */
inquote = 1;
skipws = 0;
break;
case '{': /* Start of rule elements */
if (chcount > 0) {
Token->type = _slcC_TOKEN_TEXT;
lastch = ch;
} else {
Token->type = _slcC_TOKEN_LBRACE;
Token->text[0] = ch;
chcount++;
}
intoken = 0;
break;
case '}': /* End of rule elements */
if (chcount > 0) {
Token->type = _slcC_TOKEN_TEXT;
lastch = ch;
} else {
Token->type = _slcC_TOKEN_RBRACE;
Token->text[0] = ch;
chcount++;
}
intoken = 0;
break;
case '=': /* Rule element/value separator */
if (chcount > 0) {
Token->type = _slcC_TOKEN_TEXT;
lastch = ch;
} else {
Token->type = _slcC_TOKEN_EQUAL;
Token->text[0] = ch;
chcount++;
}
intoken = 0;
break;
default: /* Normal character for token */
_slc_ADDCHAR(Token,ch);
break;
} /* switch (ch) */
} /* while in token */
/* Terminate any stuff put into the text field */
Token->length = chcount;
Token->text[chcount] = '\0';
return(0);
}
/*--------------------------------------------------------------------------*/
/* int _slcMatchToken (_slcPS_TOKEN Token; _slcS_TOKENTBL TokenTable[]) */
/*..........................................................................*/
/* */
/* Function to attempt to locate the supplied text token in the token table */
/* supplied by the TokenTable parameter. If a match is found, the index */
/* of the token table entry is returned (0-n), otherwise -1. */
/* */
/* (Note - this needs to be improved in the future to accept any number of */
/* token table parameters - and probably return a pointer to the correct */
/* entry rather than an index into the table) */
/* */
/*--------------------------------------------------------------------------*/
int _slcMatchToken (_slcPS_TOKEN Token, _slcS_TOKENTBL TokenTable[])
{
char tokentext[_slcC_TOKSIZE+1], *src, *dest;
int index;
/* Copy over token text, lowercasing it for simpler comparison */
dest = tokentext;
src = Token->text;
while (*dest++ = tolower(*src++))
;
/* Now run through table for comparision */
index = 0;
while (TokenTable[index].command != _slcC_TOKENTBL_TERM) {
if (strcmp(TokenTable[index].name,tokentext) == 0) break;
index++;
}
if (TokenTable[index].command == _slcC_TOKENTBL_TERM) index = -1;
return(index);
}
/*--------------------------------------------------------------------------*/
/* int _slcErrorMessage (char *Filename; int Line, Pos; */
/* char *MsgFormat, ...) */
/*..........................................................................*/
/* */
/* Routine for displaying an error message for the specified Filename, */
/* using the same semantics as printf. If the supplied Line/Pos parameters */
/* are >0, they are used automatically as a standard preface to the error */
/* message. */
/* */
/* Since this function actually processes the output string, the maximum */
/* size of the resulting message is _slcC_ERRSIZE characters. */
/* */
/* (Right now this goes to stderr) */
/* */
/*--------------------------------------------------------------------------*/
int _slcErrorMessage (char *Filename, int Line, int Pos,
char *MsgFormat, ...)
{
char errmsg[_slcC_ERRSIZE], syslogmsg[_slcC_ERRSIZE];
va_list args;
sprintf(errmsg,"SL-Config: Error Parsing File \"%s\"",Filename);
if (Line > 0 || Pos > 0) {
strcat(errmsg," (");
}
if (Line > 0) {
sprintf(&errmsg[strlen(errmsg)],"Line=%d",Line);
}
if (Line > 0 && Pos > 0) {
strcat(errmsg,", ");
}
if (Pos > 0) {
sprintf(&errmsg[strlen(errmsg)],"Position=%d",Pos);
}
if (Line > 0 || Pos > 0) {
strcat(errmsg,")");
}
fprintf(stderr,"%s\n",errmsg);
va_start(args,MsgFormat);
vsprintf(errmsg,MsgFormat,args);
fprintf(stderr,"SL-Config: %s\n",errmsg);
return(0);
}
/*--------------------------------------------------------------------------*/
/* int _slcSetIntfParm (slcPS_INTERFACE Interface, */
/* _slcPS_TOKENTBL Parameter, */
/* _slcPS_TOKEN Value) */
/*..........................................................................*/
/* */
/* */
/*--------------------------------------------------------------------------*/
int _slcSetIntfParm (slcPS_INTERFACE Interface, _slcPS_TOKENTBL Parameter,
_slcPS_TOKEN Value)
{
int result = 0, index, value;
switch (Parameter->valuetype) {
case 0:
/* No value arguments - just set appropriate flags */
switch (Parameter->command) {
case intf_nofastqueue:
Interface->allowfastq = 0;
break;
case intf_fastqueue:
Interface->allowfastq = 1;
break;
default:
/* Should never happen */
result = 4;
break;
}
break;
case 1:
/* String parameter */
switch (Parameter->command) {
case intf_device:
if (Interface->device) {
free(Interface->device);
}
Interface->device = strdup(Value->text);
if (Interface->device == NULL) {
result = 3;
}
break;
case intf_compression:
if (!stricmp("on",Value->text)) {
Interface->compression = slc_COMPRESSION;
if (Interface->if_mtu == 0) {
/* Set mtu (since not set already) to smaller chunks */
Interface->if_mtu = 296;
}
} else if (!stricmp("off",Value->text)) {
Interface->compression = slc_NOCOMPRESSION;
} else if (!stricmp("auto",Value->text)) {
Interface->compression = slc_AUTOCOMPRESSION;
} else {
result = 1;
}
break;
case intf_attachcmd:
if (Interface->attachcmd) {
free(Interface->attachcmd);
}
Interface->attachcmd = strdup(Value->text);
if (Interface->attachcmd == NULL) {
result = 3;
}
break;
case intf_attachparms:
if (Interface->attachparms) {
free(Interface->attachparms);
}
Interface->attachparms = strdup(Value->text);
if (Interface->attachparms == NULL) {
result = 3;
}
break;
}
break;
case 2:
/* Numeric argument with valid range */
for (index=0; index < Value->length && !result; index++) {
if (!isdigit(Value->text[index])) {
result = 1;
}
}
if (result)
break;
value = atoi(Value->text);
if (value < Parameter->minimum || value > Parameter->maximum) {
result = 2;
}
if (result)
break;
/* Store resulting value into interface structure */
switch (Parameter->command) {
case intf_mtu:
Interface->if_mtu = value;
break;
case intf_rtt:
Interface->if_rtt = value;
break;
case intf_rttvar:
Interface->if_rttvar = value;
break;
case intf_rttmin:
Interface->if_rttmin = value;
break;
case intf_sendpipe:
Interface->if_sendpipe = value;
break;
case intf_recvpipe:
Interface->if_recvpipe = value;
break;
case intf_ssthresh:
Interface->if_ssthresh = value;
break;
case intf_queuesize:
Interface->if_maxqueue = value;
break;
case intf_fastqueuesize:
Interface->if_maxfastq = value;
break;
default:
/* Should never happen */
result = 4;
break;
}
}
return(result);
}
/*==========================================================================*/
/* */
/* -------------------------------------------------- */
/* */
/* PUBLIC FUNCTIONS */
/* */
/* -------------------------------------------------- */
/* */
/*==========================================================================*/
/*--------------------------------------------------------------------------*/
/* int slcParseConfiguration (char *Filename; slcPS_INTERFACE *Interfaces) */
/*..........................................................................*/
/* */
/* Parses a SLIP configuration file, building a linked list of interface */
/* structures to hold the interface configuration information. */
/* */
/* */
/* This function is currently geared to process files of the form: */
/* */
/* interface sl# | default { */
/* parameter=value [,] parameter=value [,] ... */
/* } */
/* */
/* */
/*--------------------------------------------------------------------------*/
#define _slc_ERRMSG _slcErrorMessage
#define _slc_ERRHDR Filename,line,pos
#define _slc_NEXT_TOKEN _slcGetToken(configfile,&token,&line,&pos)
int slcParseConfiguration (char *Filename, slcPS_INTERFACE *Interfaces)
{
int result=0;
_slcS_TOKEN token;
slcS_INTERFACE intf_default;
slcPS_INTERFACE curinterface, lastinterface=NULL;
FILE *configfile;
int done=0, allowvalue=0, wantvalue=0, invalue=0,
index, line, pos, parameter, rc;
int curcommand;
/* Clear default structure */
memset(&intf_default,'\0',sizeof(intf_default));
/* And then insert fundamental defaults */
intf_default.if_recvpipe = 4096;
intf_default.if_maxqueue = 12;
intf_default.if_maxfastq = 24;
intf_default.allowfastq = 1;
intf_default.compression = slc_NOCOMPRESSION;
if ((configfile = fopen(Filename,"r")) == NULL) {
result = 1;
} else {
/* Make sure any previous parses are flushed */
_slcGetCh(NULL,0,0,0,0);
/* Main rule processing loop - handle a command at a time */
while (!done) {
/* Fetch next token */
_slc_NEXT_TOKEN;
/* If EOF here, then we're done */
if (token.type == _slcC_TOKEN_EOF) {
done = 1;
break;
}
/* If not text or text but not in command table, generate error */
if (token.type != _slcC_TOKEN_TEXT ||
(index = _slcMatchToken(&token,_slc_CmdTable)) < 0) {
_slc_ERRMSG(_slc_ERRHDR,"Invalid command encountered - \"%s\"",
token.text);
result = done = 1;
break;
}
/* We have an interface command (eventually, this will have to */
/* handle more than just an interface command. */
/* Grab next token - should be "sl#" (#=0-9) or "default" */
_slc_NEXT_TOKEN;
if (token.type != _slcC_TOKEN_TEXT) {
_slc_ERRMSG(_slc_ERRHDR,"Missing interface name");
result = done = 1;
break;
} else {
if (token.length == 3 &&
tolower(token.text[0]) == 's' &&
tolower(token.text[1]) == 'l' &&
token.text[2] == '0') { /* currently only 'sl0' allowed */
/* Normal "sl#" interface - lowercase interface name */
/* and then make sure that we haven't already used it */
strlwr(token.text);
curinterface = *Interfaces;
while (curinterface) {
if (!strcmp(curinterface->if_name,token.text)) {
_slc_ERRMSG(_slc_ERRHDR,"Duplicate interface \"%s\"",
token.text);
result = done = 1;
break;
}
curinterface = curinterface->next;
}
/* Unique - allocate room for new interface */
if (lastinterface == NULL) {
lastinterface = (slcPS_INTERFACE)
calloc(1,sizeof(slcS_INTERFACE));
curinterface = *Interfaces = lastinterface;
} else {
lastinterface->next = (slcPS_INTERFACE)
calloc(1,sizeof(slcS_INTERFACE));
curinterface = lastinterface = lastinterface->next;
}
if (curinterface == NULL) {
_slc_ERRMSG(_slc_ERRHDR,
"Error allocating space for new interface");
result = done = 1;
break;
}
/* Copy over default block for initial values */
memcpy(curinterface,&intf_default,sizeof(intf_default));
/* Update interface name and insert default device name */
strcpy(curinterface->if_name,token.text);
curinterface->device = malloc(5);
strcpy(curinterface->device,"com");
curinterface->device[3] = token.text[2]+1;
curinterface->device[4] = '\0';
} else if (!stricmp(token.text,"default")) {
/* Default interface */
curinterface = &intf_default;
} else {
_slc_ERRMSG(_slc_ERRHDR,"Invalid interface \"%s\" "
"(use sl0 or 'default')", token.text);
result = done = 1;
break;
}
}
/* This is a kludge - TBD: work on control flow in here */
if (done) break;
/* Process any parameters for this interface - First, make */
/* sure that the next parseable element is the brace ({). */
_slc_NEXT_TOKEN;
if (token.type != _slcC_TOKEN_LBRACE) {
_slc_ERRMSG(_slc_ERRHDR,"Expecting {, read \"%s\"",token.text);
result = 1;
break;
}
/* Ok - we're into the elements - go until right brace (EOF=error) */
do {
_slc_NEXT_TOKEN;
switch (token.type) {
case _slcC_TOKEN_TEXT:
/* This is either element name or value, according to */
/* wantvalue variable - verify in either case. */
if (wantvalue) {
if (rc = _slcSetIntfParm(curinterface,
&_slc_IntfTable[parameter],
&token)) {
switch (rc) {
case 1:
_slc_ERRMSG(_slc_ERRHDR,
"Invalid parameter value \"%s\"",
token.text);
break;
case 2:
_slc_ERRMSG(_slc_ERRHDR,"Parameter value (%s) "
"out of range (%d-%d)",token.text,
_slc_IntfTable[parameter].minimum,
_slc_IntfTable[parameter].maximum);
break;
case 3:
_slc_ERRMSG(_slc_ERRHDR,"Memory allocation "
"failure while parsing parameter");
break;
case 4:
_slc_ERRMSG(_slc_ERRHDR,"Internal error - "
"unknown parameter");
break;
default:
_slc_ERRMSG(_slc_ERRHDR,"Internal error - "
"unknown result (%d) from "
"_slcSetIntfParm",rc);
break;
}
result = done = 1;
}
invalue = 1;
} else {
if ((parameter = _slcMatchToken(&token,
_slc_IntfTable)) < 0) {
_slc_ERRMSG(_slc_ERRHDR,"Invalid parameter \"%s\"",
token.text);
result = done = 1;
} else {
allowvalue = _slc_IntfTable[parameter].valuetype > 0;
if (!allowvalue) {
_slcSetIntfParm(curinterface,
&_slc_IntfTable[parameter],NULL);
}
}
invalue = 0;
}
wantvalue = 0;
break;
case _slcC_TOKEN_EQUAL:
/* this is only valid if we don't yet want a value */
/* and we're allowed a value. */
if (wantvalue) {
_slc_ERRMSG(_slc_ERRHDR,
"Expecting parameter, read \"%s\"",
token.text);
result = done = 1;
} else if (!allowvalue) {
_slc_ERRMSG(_slc_ERRHDR,
"Parameter \"%s\" does not require a value",
_slc_IntfTable[parameter].name);
result = done = 1;
} else {
wantvalue = 1;
}
break;
case _slcC_TOKEN_RBRACE:
/* Error if we are waiting for a value */
if (wantvalue) {
_slc_ERRMSG(_slc_ERRHDR,
"Expecting parameter value, read \"%s\"",
token.text);
result = done = 1;
} else {
invalue = 0;
}
break;
case _slcC_TOKEN_EOF:
_slc_ERRMSG(_slc_ERRHDR,"Expecting }%s, got End-Of-File",
wantvalue ? "" : " or =");
result = done = 1;
break;
default:
if (token.type <= _slcC_TOKEN_ERROR) {
_slc_ERRMSG(_slc_ERRHDR,
"Tokenize error %d (%s) while reading file.",
token.type,_slc_TokenErrorTable[token.type]);
} else {
_slc_ERRMSG(_slc_ERRHDR,"Expecting }%s, read \"%s\"",
wantvalue ? "" : " or =",token.text);
}
result = done = 1;
break;
} /* switch token.type */
} while (token.type != _slcC_TOKEN_RBRACE && !done);
if (curinterface->if_mtu == 0) {
curinterface->if_mtu = 1006; /* Default if not set otherwise */
}
} /* while !done */
fclose(configfile);
} /* if file ok */
return(result);
}
/*--------------------------------------------------------------------------*/
/* int slcFreeConfiguration (slcPS_INTERFACE *Interfaces) */
/*..........................................................................*/
/* */
/* Frees up a previously parsed interface configuration. */
/* */
/*--------------------------------------------------------------------------*/
int slcFreeConfiguration (slcPS_INTERFACE *Interfaces)
{
slcPS_INTERFACE curptr, delptr;
curptr = *Interfaces;
while (curptr) {
if (curptr->device) {
free(curptr->device);
}
delptr = curptr;
curptr = curptr->next;
free(delptr);
}
*Interfaces = NULL;
return(0);
}
#endif /* NT */