Files
sics/conman.c
cvs bc02cb79e7 - made fixes to hkl
- Introduced a help system
- introduced a module for handling automatic updates of files during
  long measurements
- Added a circular buffer and handling facilities to varlog
- Upgraded documentation


SKIPPED:
	psi/faverage.h
	psi/nxamor.tex
	psi/pimotor.h
	psi/pimotor.tex
2003-12-10 13:50:44 +00:00

1821 lines
46 KiB
C

/*--------------------------------------------------------------------------
Connection management for SICS. This is one the core files for
SICS. Does a lot. See the descriptions with individual functions
below.
Mark Koennecke, October 1996
SMInvoke added. Mark Koennecke, April 1997
Seriously revised and extended for new structure with Tasker:
Mark Koennecke, September 1997
Support for writing telnet compatible strings ins SCWrite added.
Mark Koennecke, January 1998
SCWriteBinary added. Mark Koennecke, April 1998
Revamped login to non telnet connection.
Added compressed writing method.
Mark Koennecke, October 2000
Added simulation mode
Mark Koennecke, March 2003
Copyright: see copyright.h
-----------------------------------------------------------------------------*/
#include "fortify.h"
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <zlib.h>
#include <tcl.h>
#include <time.h>
#include "lld.h"
#include "sics.h"
#include "passwd.h"
#include "splitter.h"
#include "macro.h"
#include "servlog.h"
#include "status.h"
#include "interrupt.h"
#include "ifile.h"
#include "token.h"
#include "uubuffer.h"
#include "commandlog.h"
/*
#define UUDEB 1
define UUDEB , for buffer writing for checking encoding */
extern pServer pServ;
/*------ Max Size of Command Stack */
#define MAXSTACK 100
/*---------- Magic ID Header */
#define CONMAGIC 26051958
/*-------------------------------------------------------------------------
a structure for holding callback info
*/
typedef struct {
long lID;
pICallBack pInterface;
} Item;
/*------------- a number for generating automatic names --------------------*/
static int iName = 0;
static int SCNormalWrite(SConnection *self, char *buffer, int iOut);
/*===========================================================================*/
SConnection *SCreateConnection(SicsInterp *pSics,mkChannel *pSock, int iUser)
{
int i;
SConnection *pRes = NULL;
char pBueffel[253];
char pHost[132];
pRes = (SConnection *)malloc(sizeof(SConnection));
if(!pRes)
{
/* This is a serious, very serious error! */
SICSLogWrite("ERROR: No memory to allocate connection!!",eInternal);
return NULL;
}
memset(pRes,0,sizeof(SConnection));
/* a descriptor */
pRes->pDes = CreateDescriptor("Connection");
if(!pRes->pDes)
{
/* This is a serious, very serious error! */
SICSLogWrite("ERROR: No memory to allocate connection!!",eInternal);
free(pRes);
return NULL;
}
/* new name */
sprintf(pBueffel,"CON%4.4d",iName);
iName++;
if(iName > 9999)
{
iName = 0;
}
/* the callback registry */
pRes->iList = LLDcreate(sizeof(Item));
/* the command stack */
pRes->pStack = CreateCommandStack();
if( (pRes->iList <0) || (!pRes->pStack))
{
/* This is a serious, very serious error! */
SICSLogWrite("ERROR: No memory to allocate connection!!",eInternal);
DeleteDescriptor(pRes->pDes);
free(pRes);
return NULL;
}
SetCommandStackMaxSize(pRes->pStack,MAXSTACK);
pRes->pName = strdup(pBueffel);
pRes->pSock = pSock;
pRes->iUserRights = iUser;
pRes->iOutput = eInError; /* gets everything except internal messages */
pRes->iFiles = 0; /* default: no logfiles */
pRes->inUse = 0;
pRes->iMacro = 0;
pRes->iGrab = TokenGrabActive();
pRes->iTelnet = 0;
pRes->pSics = pSics;
pRes->eInterrupt = eContinue;
pRes->lMagic = CONMAGIC;
pRes->iLogin = 0;
pRes->conStart = time(NULL);
pRes->write = SCNormalWrite;
for(i = 0; i < 10; i++)
{
pRes->pFiles[i] = NULL;
}
if(pRes->pSock)
{
NETInfo(pRes->pSock,pHost,131);
sprintf(pBueffel,"Accepted connection on socket %d from %s",
pRes->pSock->sockid, pHost);
SICSLogWrite(pBueffel,eInternal);
WriteToCommandLog("SYS >", pBueffel);
}
else
{
SICSLogWrite("Accepted dummy connection ",eInternal);
}
/* install command */
AddCommand(pRes->pSics, pRes->pName, ConSicsAction, NULL,pRes);
return pRes;
}
/*--------------------------------------------------------------------------*/
SConnection *SCCreateDummyConnection(SicsInterp *pSics)
{
int i;
SConnection *pRes = NULL;
char pBueffel[132];
pRes = (SConnection *)malloc(sizeof(SConnection));
if(!pRes)
{
/* This is a serious, very serious error! */
SICSLogWrite("ERROR: No memory to allocate connection!!",eInternal);
return NULL;
}
memset(pRes,0,sizeof(SConnection));
/* a descriptor */
pRes->pDes = CreateDescriptor("Connection");
if(!pRes->pDes)
{
/* This is a serious, very serious error! */
SICSLogWrite("ERROR: No memory to allocate connection!!",eInternal);
free(pRes);
return NULL;
}
/* new name */
sprintf(pBueffel,"CON%4.4d",iName);
iName++;
if(iName > 9999)
{
iName = 0;
}
/* the callback registry */
pRes->iList = LLDcreate(sizeof(Item));
/* the command stack */
pRes->pStack = CreateCommandStack();
if( (pRes->iList <0) || (!pRes->pStack))
{
/* This is a serious, very serious error! */
SICSLogWrite("ERROR: No memory to allocate connection!!",eInternal);
DeleteDescriptor(pRes->pDes);
free(pRes);
return NULL;
}
pRes->pName = strdup(pBueffel);
pRes->pSock = NULL;
pRes->iUserRights = usInternal;
pRes->iOutput = eInError; /* gets everything except internal messages */
pRes->iFiles = 0; /* default: no logfiles */
pRes->inUse = 0;
pRes->iTelnet = 0;
pRes->iGrab = 0;
pRes->iMacro = 0;
pRes->pSics = pSics;
pRes->lMagic = CONMAGIC;
pRes->eInterrupt = eContinue;
pRes->iLogin = 0;
pRes->conStart = time(NULL);
pRes->write = SCNormalWrite;
for(i = 0; i < 10; i++)
{
pRes->pFiles[i] = NULL;
}
if(pRes->pSock)
{
sprintf(pBueffel,"Accepted connection on socket %d",pRes->pSock->sockid);
SICSLogWrite(pBueffel,eInternal);
}
else
{
SICSLogWrite("Accepted dummy connection ",eInternal);
}
/* install command */
AddCommand(pRes->pSics, pRes->pName, ConSicsAction, NULL,pRes);
return pRes;
}
/*--------------------------------------------------------------------------*/
static int VerifyConnection(SConnection *self)
{
if(!self)
{
SICSLogWrite("MAGICERROR: Invalid call to NULL connection",eError);
return 0;
}
if(self->lMagic != CONMAGIC)
{
SICSLogWrite("MAGICERROR: corrupted connection object",eError);
return 0;
}
return 1;
}
/*----------------------------------------------------------------------------*/
int SCAddLogFile(SConnection *self, char *name)
{
char pBueffel[256];
int iNum, i;
if(!VerifyConnection(self))
{
return 0;
}
/* find an empty number */
if(self->iFiles < MAXLOGFILES)
{
iNum = self->iFiles;
self->iFiles++;
}
else /* scan for an empty slot */
{
iNum = -1;
for(i = 0; i < self->iFiles; i++)
{
if(self->pFiles[i] == NULL)
{
iNum = i;
break;
}
}
}
/* nothing found ? */
if(iNum < 0)
{
SCWrite(self,"ERROR: maximum number of logfiles exhausted",eError);
return -1;
}
/* do the job */
self->pFiles[iNum] = fopen(name,"a+");
if(self->pFiles[iNum] == NULL)
{
sprintf(pBueffel,"ERROR Could not open logfile - %s -",name);
SCWrite(self,pBueffel, 10);
return -1; /* false */
}
else
{
return iNum; /* success */
}
}
/*--------------------------------------------------------------------------*/
int SCDelLogFile(SConnection *self, int iNum)
{
if(!VerifyConnection(self))
{
return 0;
}
if( (iNum >= 0) && (iNum < MAXLOGFILES) )
{
if(self->pFiles[iNum])
{
fclose(self->pFiles[iNum]);
self->pFiles[iNum] = NULL;
return 1;
}
}
return 0;
}
/*----------------------------------------------------------------------------*/
void SCSetOutputClass(SConnection *self, int iClass)
{
if(!VerifyConnection(self))
{
return;
}
self->iOutput = iClass;
}
/*---------------------------------------------------------------------------*/
int SCinMacro(SConnection *self)
{
if(!VerifyConnection(self))
{
return 0;
}
if(self->iMacro)
{
return 1;
}
else
{
return 0;
}
}
/*---------------------------------------------------------------------------*/
int SCsetMacro(SConnection *self, int iMode)
{
if(!VerifyConnection(self))
{
return 0;
}
assert( (iMode == 0) || (iMode == 1));
self->iMacro = iMode;
return 1;
}
/*---------------------------------------------------------------------------*/
void SCDeleteConnection(void *pData)
{
int i, iRet;
char pBueffel[132];
SConnection *pVictim = NULL;
Item sItem;
pVictim = (SConnection *)pData;
if(!VerifyConnection(pVictim))
{
return;
}
if(pVictim->inUse > 0)
{
SCnoSock(pVictim);
if(pVictim->pSock)
{
NETClosePort(pVictim->pSock);
free(pVictim->pSock);
pVictim->pSock = NULL;
}
WriteToCommandLog("SYS> ",
"ERROR: Erraneous deletion of used Connection stopped");
return;
}
/* remove the connection from the server log if it has captured
something
*/
KillCapture(pVictim);
/*
If we have a grab, release it !
*/
if(!pVictim->iGrab)
{
if(pServ->pTasker)
{
TaskSignal(pServ->pTasker,TOKENRELEASE,NULL);
TokenRelease();
}
}
/* log the kill */
if(pVictim->pSock)
{
sprintf(pBueffel,"Deleting connection %d",pVictim->pSock->sockid);
WriteToCommandLog("SYS>",pBueffel);
SICSLogWrite(pBueffel,eInternal);
}
/* close all open files and sockets */
if(pVictim->pSock)
{
NETWrite(pVictim->pSock,"SICSCLOSE",sizeof("SICSCLOSE"));
NETClosePort(pVictim->pSock);
free(pVictim->pSock);
}
for(i = 0; i < pVictim->iFiles; i++)
{
fclose(pVictim->pFiles[i]);
}
if(pVictim->pName)
{
RemoveCommand(pVictim->pSics,pVictim->pName);
free(pVictim->pName);
}
if(pVictim->pDes)
{
DeleteDescriptor(pVictim->pDes);
}
/* remove all callbacks on this connection */
iRet = LLDnodePtr2First(pVictim->iList);
while(iRet != 0)
{
LLDnodeDataTo(pVictim->iList,&sItem);
RemoveCallback(sItem.pInterface, sItem.lID);
iRet = LLDnodePtr2Next(pVictim->iList);
}
LLDdelete(pVictim->iList);
/* remove standing data connections */
if(pVictim->pDataSock)
{
NETClosePort(pVictim->pDataSock);
free(pVictim->pDataSock);
free(pVictim->pDataComp);
}
/* remove command stack */
if(pVictim->pStack)
{
DeleteCommandStack(pVictim->pStack);
}
/* finally free pVictim*/
free(pVictim);
}
/*---------------------------------------------------------------------------*/
static int HasNL(char *buffer)
{
int i;
for(i = strlen(buffer); i > 0; i--)
{
if(isprint(buffer[i]))
{
break;
}
if(buffer[i] == '\n')
{
return 1;
}
}
return 0;
}
/*-------------------------------------------------------------------------
TelnetWrite makes sure, that all lines are properly terminated with a
<cr><lf> as required by the telnet protocoll.
There may be a problem here at long messages. 7.5.1998 MK
--------------------------------------------------------------------------*/
#define TXT 0
#define LF 1
int TelnetWrite(mkChannel *pSock, char *pBuffer)
{
char *pStart = NULL, *pPtr;
int iCount, iState;
int iRet = 1;
pStart = pBuffer;
pPtr = pStart;
iState = TXT;
iCount = 0;
while(*pPtr != '\0')
{
switch(iState)
{
case TXT:
if( (*pPtr == '\r') || (*pPtr == '\n') )
{
iState = LF;
iRet = NETWrite(pSock,pStart,iCount);
iRet = NETWrite(pSock,"\r\n",2);
iCount = 0;
}
else
{
iCount++;
}
break;
case LF:
if( (*pPtr != '\r') && (*pPtr != '\n') )
{
pStart = pPtr;
iCount = 1;
iState = TXT;
}
else
{
/* do nothing */
}
break;
}
pPtr++;
}
if(iCount > 0)
{
iRet = NETWrite(pSock,pStart,iCount);
iRet = NETWrite(pSock,"\r\n",2);
}
return iRet;
}
/*-------------------------------------------------------------------------*/
int SCWrite(SConnection *self, char *pBuffer, int iOut)
{
if(!VerifyConnection(self))
{
return 0;
}
/*
Do not die if no data
*/
if(pBuffer == NULL)
{
return 0;
}
return self->write(self,pBuffer,iOut);
}
/*-------------------------------------------------------------------------*/
writeFunc SCGetWriteFunc(SConnection *self)
{
if(!VerifyConnection(self))
{
return 0;
}
return self->write;
}
/*-------------------------------------------------------------------------*/
void SCSetWriteFunc(SConnection *self, writeFunc x)
{
if(!VerifyConnection(self))
{
return;
}
self->write = x;
}
/*--------------------------------------------------------------------------*/
static int SCNormalWrite(SConnection *self, char *buffer, int iOut)
{
int i, iPtr, iRet;
char pBueffel[80];
if(!VerifyConnection(self))
{
return 0;
}
/* log it for any case */
if(self->pSock)
{
iRet = self->pSock->sockid;
}
else
{
iRet = 0;
}
sprintf(pBueffel,"Next line intended for socket: %d",iRet);
SICSLogWrite(pBueffel,eInternal);
SICSLogWrite(buffer,iOut);
/* write to commandlog if user or manager privilege */
if(SCGetRights(self) <= usUser)
{
sprintf(pBueffel,"To sock %d :",iRet);
WriteToCommandLog(pBueffel,buffer);
}
/* put it into the interpreter if present */
if(SCinMacro(self))
{
InterpWrite(self->pSics,buffer);
/* print it to client if error message */
if((iOut== eError) || (iOut == eWarning) )
{
if(self->pSock)
{
if(self->iTelnet)
{
iRet = TelnetWrite(self->pSock,buffer);
}
else
{
iRet = NETWrite(self->pSock,buffer,strlen(buffer));
if(!HasNL(buffer))
{
iRet = NETWrite(self->pSock,"\n",sizeof("\n"));
}
}
if(!iRet)
{
SCnoSock(self);
WriteToCommandLog("SYS> ","Connection broken on send");
}
}
else
{
puts(buffer);
}
}
}
else /* not in interpreter, normal logic */
{
/* is this really to be printed ? */
if(iOut < self->iOutput)
return 0;
/* first the socket */
if(self->pSock)
{
if(self->iTelnet)
{
iRet = TelnetWrite(self->pSock,buffer);
}
else
{
iRet = NETWrite(self->pSock,buffer,strlen(buffer));
if(!HasNL(buffer))
{
iRet = NETWrite(self->pSock,"\n",strlen("\n"));
}
}
if(!iRet)
{
SCnoSock(self);
WriteToCommandLog("SYS> ","Send broken to connection");
}
}
else
{
printf("%s \n",buffer);
}
/* now all the possible logfiles */
for(i = 0; i < self->iFiles; i++)
{
if(self->pFiles[i])
{
fputs(buffer,self->pFiles[i]);
if(! HasNL(buffer))
{
fputs("\n",self->pFiles[i]);
fflush(self->pFiles[i]);
}
}
}
}
return 1;
}
/*--------------------------------------------------------------------------*/
int SCOnlySockWrite(SConnection *self, char *buffer, int iOut)
{
int i, iPtr, iRet;
char pBueffel[80];
if(!VerifyConnection(self))
{
return 0;
}
/* log it for any case */
if(self->pSock)
{
iRet = self->pSock->sockid;
}
else
{
iRet = 0;
}
sprintf(pBueffel,"Next line intended for socket: %d",iRet);
SICSLogWrite(pBueffel,eInternal);
SICSLogWrite(buffer,iOut);
/* put it into the interpreter if present */
if(SCinMacro(self))
{
InterpWrite(self->pSics,buffer);
}
else /* not in interpreter, normal logic */
{
/* is this really to be printed ? */
if(iOut < self->iOutput)
return 0;
/* the socket */
if(self->pSock)
{
if(self->iTelnet)
{
iRet = TelnetWrite(self->pSock,buffer);
}
else
{
iRet = NETWrite(self->pSock,buffer,strlen(buffer));
if(!HasNL(buffer))
{
iRet = NETWrite(self->pSock,"\n",sizeof("\n"));
}
}
if(!iRet)
{
SCnoSock(self);
WriteToCommandLog("SYS> ","Send broken to connection");
}
}
else
{
printf("%s \n",buffer);
}
}
return 1;
}
/*--------------------------------------------------------------------------*/
int SCNotWrite(SConnection *self, char *buffer, int iOut)
{
int i, iPtr, iRet;
char pBueffel[80];
if(!VerifyConnection(self))
{
return 0;
}
/* log it for any case */
if(self->pSock)
{
iRet = self->pSock->sockid;
}
else
{
iRet = 0;
}
sprintf(pBueffel,"Next line intended for socket: %d",iRet);
SICSLogWrite(pBueffel,eInternal);
SICSLogWrite(buffer,iOut);
return 1;
}
/*--------------------------------------------------------------------------
This version writes only to configured log files but not to sockets.
Used for automatic file execution for the WWW interface
*/
static int SCFileWrite(SConnection *self, char *buffer, int iOut)
{
int i, iPtr, iRet;
char pBueffel[80];
if(!VerifyConnection(self))
{
return 0;
}
/* put into Serverlog */
sprintf(pBueffel,"Next line intended for socket: %d",-10);
SICSLogWrite(pBueffel,eInternal);
SICSLogWrite(buffer,iOut);
/* write to commandlog if user or manager privilege */
if(SCGetRights(self) <= usUser)
{
sprintf(pBueffel,"To sock %d :",-10);
WriteToCommandLog(pBueffel,buffer);
}
/* put it into the interpreter if present */
if(SCinMacro(self))
{
InterpWrite(self->pSics,buffer);
}
else /* not in interpreter, normal logic */
{
/* is this really to be printed ? */
if(iOut < self->iOutput)
return 0;
/* now all the possible logfiles */
for(i = 0; i < self->iFiles; i++)
{
if(self->pFiles[i])
{
fputs(buffer,self->pFiles[i]);
if(! HasNL(buffer))
{
fputs("\n",self->pFiles[i]);
fflush(self->pFiles[i]);
}
}
}
}
return 1;
}
/*-----------------------------------------------------------------------*/
int SCnoSock(SConnection *self)
{
if(!VerifyConnection(self))
{
return 0;
}
self->write = SCFileWrite;
}
/*-------------------------------------------------------------------------*/
int SCWriteBinary(SConnection *pCon, char *pComputer, int iPort,
void *pData, int iDataLen)
{
int iRet;
char pBueffel[1024];
mkChannel *pChan = NULL;
assert(pCon);
/* do we have an identical connection already */
if(pCon->pDataSock)
{
if(strcmp(pComputer,pCon->pDataComp) == 0 && (pCon->iDataPort == iPort))
{
pChan = pCon->pDataSock;
}
else /* rubbish, kill it */
{
NETClosePort(pCon->pDataSock);
free(pCon->pDataSock);
free(pCon->pDataComp);
pCon->pDataSock = NULL;
pCon->pDataComp = NULL;
}
}
/* we have none, open it! */
if(!pChan)
{
pChan = NETConnect(pComputer, iPort);
if(!pChan)
{
sprintf(pBueffel,"ERROR: cannot connect to %s %d",pComputer, iPort);
SCWrite(pCon,pBueffel,eError);
SCWrite(pCon,"EOFBINARYERROR",eValue);
return 0;
}
pCon->pDataSock = pChan;
pCon->pDataComp = strdup(pComputer);
pCon->iDataPort = iPort;
}
/* do the writing */
iRet = NETWrite(pChan,pData,iDataLen);
if(iRet != 1)
{
sprintf(pBueffel,"ERROR: failed to write data to %s %d",pComputer, iPort);
SCWrite(pCon,pBueffel,eError);
SCWrite(pCon,"EOFBINARYERROR",eValue);
NETClosePort(pChan);
free(pCon->pDataSock);
free(pCon->pDataComp);
pCon->pDataSock = NULL;
pCon->pDataComp = NULL;
return 0;
}
SCWrite(pCon,"EOFBINARYOK",eValue);
return 1;
}
/*------------------------------------------------------------------------*/
int SCWriteUUencoded(SConnection *pCon, char *pName, void *pData,
int iDataLen)
{
void *pPtr = NULL;
int iLength = 0;
int iRet = 1;
FILE *fd;
char *pTest;
iRet = UUencodeBuffer(pData,iDataLen,pName, &pPtr, &iLength);
if(iRet != 1)
{
SCWrite(pCon,"ERROR: no memory for uuencoder",eError);
return 0;
}
pTest = (char *)pPtr;
/* the uuencoder ensures proper telnet <cr><lf> */
if(pCon->iTelnet)
{
NETWrite(pCon->pSock,pPtr,iLength);
}
else
{
NETWrite(pCon->pSock,pPtr,iLength);
}
#ifdef UUDEB
fd = fopen("uubuffer.uu","w");
fputs(pPtr,fd);
fclose(fd);
#endif
free(pPtr);
return iRet;
}
/*------------------------------------------------------------------------*/
#define ZIPBUF 8192
int SCWriteZipped(SConnection *self, char *pName, void *pData, int iDataLen)
{
char outBuf[65546], *pBuf = NULL, noutBuf[ZIPBUF], *pHeader = NULL;
int compressedLength, iRet, iRet2, iCount;
z_stream compStream;
/* check for a valid connection */
if(!VerifyConnection(self))
{
return 0;
}
/* a telnet connection will corrupt the compressed stream, so
stop it!
*/
if(self->iTelnet)
{
SCWrite(self,
"ERROR: the telnet protocoll will currupt compressed data!",
eError);
return 0;
}
/* initialize the compression stuff */
compStream.zalloc = (alloc_func)NULL;
compStream.zfree = (free_func)NULL;
compStream.opaque = (voidpf)NULL;
iRet = deflateInit(&compStream,Z_DEFAULT_COMPRESSION);
if(iRet != Z_OK)
{
sprintf(outBuf,"ERROR: zlib error: %d",iRet);
SCWrite(self,outBuf,eError);
return 0;
}
/* first pass: find out how the long the compressed buffer will be */
compressedLength = 0;
compStream.next_in = (Bytef *)pData;
compStream.next_out = (Bytef *)outBuf;
compStream.avail_in = iDataLen;
compStream.avail_out = 65536;
while(compStream.total_in < iDataLen)
{
iRet = deflate(&compStream,Z_NO_FLUSH);
if(iRet != Z_OK)
{
sprintf(outBuf,"ERROR: zlib error: %d",iRet);
SCWrite(self,outBuf,eError);
return 0;
}
compStream.next_out = (Bytef *)outBuf;
compStream.avail_out = 65536;
}
for(;;)
{
iRet = deflate(&compStream,Z_FINISH);
if(iRet == Z_STREAM_END) break;
if(iRet != Z_OK)
{
sprintf(outBuf,"ERROR: zlib error: %d",iRet);
SCWrite(self,outBuf,eError);
return 0;
}
}
compressedLength = compStream.total_out;
deflateEnd(&compStream);
/* write header line */
memset(outBuf,0,65536);
sprintf(outBuf,"SICSBIN ZIP %s %d\r\n",pName,compressedLength);
pHeader = strdup(outBuf);
if(pHeader == NULL)
{
SCWrite(self,"ERROR: out of memory in SCWriteZipped",eError);
return 0;
}
/* now reset the deflater and do the same with writing data */
compStream.zalloc = (alloc_func)NULL;
compStream.zfree = (free_func)NULL;
compStream.opaque = (voidpf)NULL;
/*
This is writing everything in one go as I found that writing in
several chunks did not ensure that all the data arrived at the
Java side.
*/
iRet = deflateInit(&compStream,Z_DEFAULT_COMPRESSION);
if(iRet != Z_OK)
{
sprintf(outBuf,"ERROR: zlib error: %d",iRet);
SCWrite(self,outBuf,eError);
return 0;
}
pBuf = (char *)malloc((iDataLen + iDataLen/10 + 50)*sizeof(char));
memset(pBuf,0,(iDataLen + iDataLen/10 + 50)*sizeof(char) );
compStream.next_in = (Bytef *)pData;
compStream.next_out = (Bytef *)pBuf;
compStream.avail_in = iDataLen;
compStream.avail_out = iDataLen + iDataLen/10 + 50;
iRet = deflate(&compStream,Z_FINISH);
if(iRet != Z_STREAM_END)
{
sprintf(outBuf,"ERROR: zlib error: %d",iRet);
SCWrite(self,outBuf,eError);
return 0;
}
iRet = NETWrite(self->pSock,pHeader,strlen(pHeader));
iRet = NETWrite(self->pSock,pBuf,compStream.total_out);
if(iRet != 1)
{
sprintf(outBuf,"ERROR: network error %d on zipped send",iRet);
SCWrite(self,outBuf,eError);
return 0;
}
deflateEnd(&compStream);
free(pHeader);
free(pBuf);
/*
Writing smaller buffers. Seems not to be working properly
with Java.
*/
/*
compStream.next_in = (Bytef *)pData;
compStream.avail_in = iDataLen;
compStream.avail_out = ZIPBUF;
compStream.next_out = (Bytef *)noutBuf;
iCount = 0;
while(compStream.total_in < iDataLen)
{
iRet = deflate(&compStream,Z_NO_FLUSH);
if(iRet != Z_OK)
{
sprintf(outBuf,"ERROR: zlib error: %d",iRet);
SCWrite(self,outBuf,eError);
return 0;
}
iRet = NETWrite(self->pSock,noutBuf,ZIPBUF - compStream.avail_out);
if(iRet != 1)
{
sprintf(outBuf,"ERROR: network error %d on zipped send",iRet);
SCWrite(self,outBuf,eError);
return 0;
}
iCount += ZIPBUF - compStream.avail_out;
compStream.next_out = (Bytef *)noutBuf;
compStream.avail_out = ZIPBUF;
}
for(;;)
{
iRet = deflate(&compStream,Z_FINISH);
iRet2 = NETWrite(self->pSock,noutBuf,ZIPBUF - compStream.avail_out);
if(iRet2 != 1)
{
sprintf(outBuf,"ERROR: network error %d on zipped send",iRet);
SCWrite(self,outBuf,eError);
return 0;
}
iCount += ZIPBUF - compStream.avail_out;
if(iRet == Z_STREAM_END) break;
if(iRet != Z_OK)
{
sprintf(outBuf,"ERROR: zlib error: %d",iRet);
SCWrite(self,outBuf,eError);
return 0;
}
compStream.next_out = (Bytef *)noutBuf;
compStream.avail_out = ZIPBUF;
}
deflateEnd(&compStream);
*/
return 1;
}
/*-------------------------------------------------------------------------*/
int SCSendOK(SConnection *self)
{
return SCWrite(self,"OK",eStatus);
}
/*--------------------------------------------------------------------------*/
int SCRead(SConnection *self, char *buffer, int iLen)
{
int iRet;
if(!VerifyConnection(self))
{
return 0;
}
if(self->pSock == NULL)
{
printf("SICS>> ");
fgets(buffer,iLen-1,stdin);
return 1;
}
if(self->pSock)
{
iRet = NETRead(self->pSock,buffer,iLen,10);
if(iRet == 0) /* no data */
{
return 0;
}
else if(iRet < 0) /* eof */
{
return EOF;
}
else /* data */
{
return 1;
}
}
else
{
return EOF;
/* fgets(buffer,iLen,stdin); */
}
return 1;
}
/*----------------------------------------------------------------------------*/
int SCMatchRights(SConnection *pCon, int iCode)
{
char pBueffel[132];
if(!VerifyConnection(pCon))
{
return 0;
}
if(iCode < SCGetRights(pCon))
{
sprintf(pBueffel,"ERROR: you are not authorised for this operation");
SCWrite(pCon, pBueffel, eError);
return 0;
}
if(pCon->iGrab)
{
sprintf(pBueffel,
"ERROR: Request refused, control has been grabbed by somebody else");
SCWrite(pCon,pBueffel,eError);
return 0;
}
return 1;
}
/*----------------------------------------------------------------------------*/
int SCPrompt(SConnection *pCon, char *pPrompt, char *pResult, int iLen)
{
int iRet, i;
char *pPtr = NULL;
char pFrom[50];
Status eOld;
if(!VerifyConnection(pCon))
{
return 0;
}
SCWrite(pCon,pPrompt,eWarning);
eOld = GetStatus();
SetStatus(eInput);
CostaUnlock(pCon->pStack);
while(1)
{
/* wait a second */
SicsWait(1);
/* is there an interrupt pending ? */
if(SCGetInterrupt(pCon) != eContinue)
{
break;
}
/* do we have data ? */
iRet = CostaPop(pCon->pStack,&pPtr);
if(iRet == 1)
{
SetStatus(eOld);
CostaLock(pCon->pStack);
strncpy(pResult,pPtr,iLen);
sprintf(pFrom,"Prompted from sock %2.2d: ", pCon->pSock->sockid);
WriteToCommandLog(pFrom,pPtr);
return 1;
}
}
SetStatus(eOld);
CostaLock(pCon->pStack);
return 0;
}
/*---------------------------------------------------------------------------*/
int SCGetRights(SConnection *self)
{
if(!VerifyConnection(self))
{
return 0;
}
return self->iUserRights;
}
/*---------------------------------------------------------------------------*/
int SCGetGrab(SConnection *self)
{
if(!VerifyConnection(self))
{
return 0;
}
return self->iGrab;
}
/*--------------------------------------------------------------------------*/
int SCSetRights(SConnection *self, int iNew)
{
if(!VerifyConnection(self))
{
return 0;
}
assert(iNew >= usInternal);
assert(iNew <= usSpy);
self->iUserRights = iNew;
return 1;
}
/*---------------------------------------------------------------------------*/
int SCGetOutClass(SConnection *self)
{
if(!VerifyConnection(self))
{
return 0;
}
return self->iOutput;
}
/*--------------------------------------------------------------------------*/
void SCSetInterrupt(SConnection *self, int eCode)
{
if(!VerifyConnection(self))
{
return;
}
self->eInterrupt = eCode;
}
/*---------------------------------------------------------------------------*/
int SCGetInterrupt(SConnection *self)
{
if(!VerifyConnection(self))
{
return 0;
}
return self->eInterrupt;
}
/* --------------------------------------------------------------------------*/
int SCInvoke(SConnection *self, SicsInterp *pInter, char *pCommand)
{
int iRet;
long lLen;
const char *pResult = NULL;
char *pBuffer = NULL, *pFile = NULL;
char pBueffel[80];
int i, iSpace;
if(!VerifyConnection(self))
{
return 0;
}
assert(pInter);
/* print command to log files */
for( i = 0; i < self->iFiles; i++)
{
if(self->pFiles[i])
{
fprintf(self->pFiles[i],"SICS>> %s\n",pCommand);
}
}
/* print to command log if user or manager */
if(SCGetRights(self) <= usUser)
{
if(self->pSock != NULL)
{
sprintf(pBueffel,"sock %d>>",self->pSock->sockid);
}
else
{
strcat(pBueffel,"CONT or CRON>> ");
}
WriteToCommandLog(pBueffel,pCommand);
}
/* invoke */
self->inUse++;
self->eInterrupt = eContinue;
self->parameterChange = 0;
iRet = InterpExecute(pInter,self,pCommand);
if(self->parameterChange == 1)
{
/*
automatically save changed parameters
*/
pFile = IFindOption(pSICSOptions,"statusfile");
if(pFile != NULL)
{
WriteSicsStatus(pInter,pFile,0);
self->parameterChange = 0;
}
}
self->inUse--;
return iRet;
}
/*---------------------------------------------------------------------------
For configuring connections. Syntax:
config OutCode val sets an new output code
config Rights User Password sets and verifies new user rights
config File Filename Logs to another file
*/
#include "outcode.c" /* text for OutCode */
int ConfigCon(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
char pBueffel[512];
int i, iRet;
int iNum;
if(!VerifyConnection(pCon))
{
return 0;
}
assert(pSics);
/* check no of args */
if(argc < 2)
{
sprintf(pBueffel,"Insufficient number of args to %s",argv[0]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
/* handle list*/
strtolower(argv[1]);
if(strcmp(argv[1],"list") == 0)
{
sprintf(pBueffel,"OutCode = %s\nUserRights = %d",
pCode[pCon->iOutput], SCGetRights(pCon));
SCWrite(pCon,pBueffel,eStatus);
return 1;
}
else if(strcmp(argv[1],"myname") == 0)
{
sprintf(pBueffel,"MyName = %s",pCon->pName);
SCWrite(pCon,pBueffel,eValue);
return 1;
}
else if(strcmp(argv[1],"myrights") == 0)
{
sprintf(pBueffel,"UserRights = %d",SCGetRights(pCon));
SCWrite(pCon,pBueffel,eValue);
return 1;
}
/* check no or args */
if(argc < 3)
{
sprintf(pBueffel,"Insufficient number of args to %s",argv[0]);
SCWrite(pCon,pBueffel,eInError);
return 0;
}
/* decide what to do */
if(strcmp(argv[1],"file") == 0)
{
iRet = SCAddLogFile(pCon,argv[2]);
if(iRet >= 0 )
{
sprintf(pBueffel,"File = %d",iRet);
SCWrite(pCon,pBueffel,eStatus);
return 1;
}
}
if(strcmp(argv[1],"close") == 0) /* close file */
{
iNum = atoi(argv[2]);
if( (iNum >= 0) && (iNum < MAXLOGFILES))
{
if(pCon->pFiles[iNum])
{
fclose(pCon->pFiles[iNum]);
pCon->pFiles[iNum] = NULL;
SCSendOK(pCon);
return 1;
}
}
else
{
SCWrite(pCon, "Invalid file number specified ",eError);
return 0;
}
}
else if(strcmp(argv[1],"outcode") == 0)
{
i = 0;
strtolower(argv[2]);
while(pCode[i] != NULL)
{
if(strcmp(pCode[i],argv[2]) == 0)
{
break;
}
i++;
}
if( i > iNoCodes)
{
sprintf(pBueffel,"OutCode %s not recognized",argv[2]);
SCWrite(pCon,pBueffel,eInError);
return 0;
}
pCon->iOutput = i;
SCSendOK(pCon);
return 1;
}
else if(strcmp(argv[1],"rights") == 0)
{
if(argc < 4)
{
sprintf(pBueffel,"Insufficient number of args to %s",argv[0]);
SCWrite(pCon,pBueffel,eInError);
return 0;
}
i = IsValidUser(argv[2],argv[3]);
if(i < 0)
{
sprintf(pBueffel," %s with password ****** is NO valid User on SICS",
argv[2]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
pCon->iUserRights = i;
sprintf(pBueffel,"User %s socket %d switched to %d privilege",
argv[2],pCon->pSock->sockid,i);
WriteToCommandLog("SYS>",pBueffel);
SCWrite(pCon,"Change of Authorisation Acknowledged",eWarning);
return 1;
}
SCWrite(pCon,"Command not recognized",eError);
return 0;
}
/*----------------------------------------------------------------------*/
int SCRegister(SConnection *pCon, SicsInterp *pSics,
void *pData, long lID)
{
pICallBack pInter = NULL;
Item sItem;
pInter = (pICallBack)pData;
if(!VerifyConnection(pCon))
{
return 0;
}
assert(pSics);
assert(pInter);
sItem.lID = lID;
sItem.pInterface = pInter;
LLDnodeAppendFrom(pCon->iList,&sItem);
return 1;
}
/*----------------------------------------------------------------------*/
int SCUnregister(SConnection *pCon, void *pData)
{
int iRet;
Item sItem;
pICallBack pInter;
if(!VerifyConnection(pCon))
{
return 0;
}
pInter = (pICallBack)pData;
iRet = LLDnodePtr2First(pCon->iList);
while(iRet != 0)
{
LLDnodeDataTo(pCon->iList,&sItem);
if(sItem.pInterface == pInter)
{
LLDnodeDelete(pCon->iList);
LLDnodePtr2Prev(pCon->iList);
}
iRet = LLDnodePtr2Next(pCon->iList);
}
return 1;
}
/*---------------------- The callback data structure --------------------*/
typedef struct {
SConnection *pCon;
SicsInterp *pSics;
char *pAction;
} CBAction, *pCBAction;
/*---------------------- CBKill -----------------------------------------*/
static void CBKill(void *pData)
{
pCBAction self = NULL;
self = (pCBAction)pData;
if(self == NULL)
{
return;
}
if(self->pAction)
{
free(self->pAction);
}
free(self);
}
/*-------------------------------------------------------------------------
The callback function for connection callbacks. Invokes command
given at registration time.
*/
static int ConCallBack(int iEvent, void *pEventData, void *pUserData)
{
pCBAction self = NULL;
self = (pCBAction)pUserData;
assert(self);
if(self->pAction)
{
InterpExecute(self->pSics,self->pCon,self->pAction);
}
return 1;
}
/*--------------------------------------------------------------------------
The only command currently understood is: put args
writes the args to the client
*/
int ConSicsAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
SConnection *self = NULL;
pICallBack pInterface = NULL;
char pBueffel[1024];
pDummy pDum;
int iEvent;
Item sItem;
pCBAction pCB = NULL;
CommandList *pCom = NULL;
int iMacro;
self = (SConnection *)pData;
if(!VerifyConnection(self))
{
return 0;
}
if(argc > 1)
{
/* put */
if(strcmp(argv[1],"put") == 0)
{
Arg2Text(argc-2,&argv[2],pBueffel,1023);
iMacro = SCinMacro(pCon);
SCsetMacro(pCon,0);
SCWrite(self,pBueffel,eWarning);
SCsetMacro(pCon,iMacro);
return 1;
}
/* register object event action */
if(strcmp(argv[1],"register") == 0)
{
if(argc < 5)
{
SCWrite(pCon,"ERROR: Insufficient arguments to register",eError);
return 0;
}
/* get object */
pCom = FindCommand(pSics,argv[2]);
if(!pCom)
{
sprintf(pBueffel,"ERROR: object %s NOT found",argv[2]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
/* get CallBack interface */
pDum = (pDummy)pCom->pData;
assert(pDum);
pInterface = (pICallBack)pDum->pDescriptor->GetInterface(pDum,CALLBACKINTERFACE);
if(!pInterface)
{
sprintf(pBueffel,"ERROR: %s does not support CallBacks",
argv[2]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
/* get Event */
iEvent = Text2Event(argv[3]);
if(iEvent < 0)
{
sprintf(pBueffel,"ERROR: Unknown event code %s",argv[3]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
/* now we can install the callback */
pCB = (pCBAction)malloc(sizeof(CBAction));
if(!pCB)
{
SCWrite(pCon,"ERROR: memory exhausted in SConnection",eError);
return 0;
}
Arg2Text(argc-4, &argv[4],pBueffel,1023);
pCB->pCon = pCon;
pCB->pSics = pSics;
pCB->pAction = strdup(pBueffel);
sItem.pInterface = pInterface;
sItem.lID = RegisterCallback(pInterface, iEvent, ConCallBack,
pCB, CBKill);
LLDnodeAppendFrom(self->iList,&sItem);
SCSendOK(pCon);
return 1;
}
}
return 0;
}
/*--------------------------------------------------------------------------*/
int SCTaskFunction(void *pData)
{
SConnection *self = NULL;
char *pPtr = NULL;
int iRet;
char *pUser = NULL, *pPassword = NULL;
self = (SConnection *)pData;
if(!VerifyConnection(self))
{
return 0;
}
if(self->iEnd)
{
if(self->inUse != 0)
{
return 1;
}
else
{
return 0;
}
}
/* a timeout check on logins */
if(!self->iLogin && time(NULL) > self->conStart + 120)
{
NetReadRemove(pServ->pReader,self->pSock);
SCWrite(self, "No valid login in two minutes, closing..",eError);
self->iEnd = 1;
return 1;
}
/* pop and execute */
iRet = CostaPop(self->pStack,&pPtr);
if(iRet)
{
if(pPtr)
{
if(self->iLogin)
{
/*
normal processing, logged in
but check for logoff
*/
if(strstr(pPtr,"logoff") != NULL)
{
NetReadRemove(pServ->pReader,self->pSock);
self->iEnd = 1;
free(pPtr);
return 1;
}
/* invoke command */
CostaLock(self->pStack);
SCInvoke(self,self->pSics,pPtr);
CostaUnlock(self->pStack);
/* SCWrite(self,"\b",eError); */
}
else
{
/* check for username and password */
pUser = strtok(pPtr," \t");
pPassword = strtok(NULL," \t\r\n");
iRet = IsValidUser(pUser,pPassword);
if(iRet >= 0)
{
SCWrite(self,"Login OK",eError);
self->iLogin = 1;
SCSetRights(self,iRet);
free(pPtr);
return 1;
}
else
{
SCWrite(self,"ERROR: Bad login",eError);
}
}
free(pPtr);
}
}
if(self->iEnd)
{
if(self->inUse != 0)
{
return 1;
}
else
{
return 0;
}
}
return 1;
}
/*---------------------------------------------------------------------------*/
void SCSignalFunction(void *pData, int iSignal, void *pSigData)
{
SConnection *self = NULL;
int *iInt;
char *pPtr;
self = (SConnection *)pData;
if(!VerifyConnection(self))
{
return;
}
if(iSignal == SICSINT)
{
iInt = (int *)pSigData;
SCSetInterrupt(self,*iInt);
if(*iInt == eEndServer)
{
self->iEnd = 1;
}
}
else if(iSignal == SICSBROADCAST)
{
pPtr = (char *)pSigData;
if(pPtr)
{
SCWrite(self,pPtr,eWarning);
}
}
else if(iSignal == TOKENRELEASE)
{
self->iGrab = 0;
}
else if(iSignal == TOKENGRAB)
{
self->iGrab = 1;
}
}
/*-----------------------------------------------------------------------*/
void SCparChange(SConnection *self)
{
if(!VerifyConnection(self))
{
return;
}
self->parameterChange = 1;
}