- Reworked the connection object and the IO system
- Reworked the support for TRICS - Added a second generation motor
This commit is contained in:
392
nread.c
392
nread.c
@@ -10,7 +10,7 @@
|
||||
Telnet Functionality added: Mark Koennecke, January 1998
|
||||
|
||||
Revamped login to non telnet connection.
|
||||
Mark Koennecke, October 20000
|
||||
Mark Koennecke, October 2000
|
||||
|
||||
-----------------------------------------------------------------------------*/
|
||||
#include <stdlib.h>
|
||||
@@ -67,6 +67,7 @@ extern int VerifyChannel(mkChannel *self); /* defined in network.c */
|
||||
int iReadTimeout;
|
||||
int iEnd;
|
||||
long lMagic;
|
||||
pDynString conList;
|
||||
} NetReader;
|
||||
/*---------------------------------------------------------------------------
|
||||
The structure used for an item in the Net Reader list of connections
|
||||
@@ -97,7 +98,8 @@ extern int VerifyChannel(mkChannel *self); /* defined in network.c */
|
||||
memset(pNew,0,sizeof(NetReader));
|
||||
|
||||
pNew->iList = LLDcreate(sizeof(NetItem));
|
||||
if(pNew->iList < 0)
|
||||
pNew->conList = CreateDynString(1024,1024);
|
||||
if(pNew->iList < 0 || pNew->conList == NULL)
|
||||
{
|
||||
free(pNew);
|
||||
return NULL;
|
||||
@@ -121,6 +123,10 @@ extern int VerifyChannel(mkChannel *self); /* defined in network.c */
|
||||
}
|
||||
|
||||
LLDdelete(self->iList);
|
||||
if(self->conList != NULL)
|
||||
{
|
||||
DeleteDynString(self->conList);
|
||||
}
|
||||
free(self);
|
||||
}
|
||||
/*--------------------------------------------------------------------------*/
|
||||
@@ -208,10 +214,12 @@ extern int VerifyChannel(mkChannel *self); /* defined in network.c */
|
||||
if(pNew)
|
||||
{
|
||||
/* create connection object */
|
||||
/* TODO
|
||||
pRes = SCreateConnection(self->pMain->pSics,pNew,3);
|
||||
*/
|
||||
if(!pRes)
|
||||
{
|
||||
SICSLogWrite("Failure to allocate new Connection",eInternal);
|
||||
SICSLogWrite("Failure to allocate new Connection",eInternal);
|
||||
NETClosePort(pNew);
|
||||
free(pNew);
|
||||
return 0;
|
||||
@@ -370,7 +378,9 @@ extern int VerifyChannel(mkChannel *self); /* defined in network.c */
|
||||
if(pNew)
|
||||
{
|
||||
/* create connection object */
|
||||
/* TODO
|
||||
pRes = SCreateConnection(self->pMain->pSics,pNew,usSpy);
|
||||
*/
|
||||
if(!pRes)
|
||||
{
|
||||
SICSLogWrite("Failure to allocate new Connection",eInternal);
|
||||
@@ -706,9 +716,6 @@ extern int VerifyChannel(mkChannel *self); /* defined in network.c */
|
||||
int conCount = 0;
|
||||
char num[50];
|
||||
IPair *options = NULL;
|
||||
char buffer[1024];
|
||||
int bufferLen;
|
||||
static int bufferFull=0;
|
||||
|
||||
self = (pNetRead)pData;
|
||||
assert(self);
|
||||
@@ -723,12 +730,13 @@ extern int VerifyChannel(mkChannel *self); /* defined in network.c */
|
||||
return 0;
|
||||
}
|
||||
|
||||
ANETprocess();
|
||||
|
||||
/* build the select mask */
|
||||
FD_ZERO(&lMask);
|
||||
iRet = LLDnodePtr2First(self->iList);
|
||||
iCount = 0;
|
||||
buffer[0] = '\0';
|
||||
bufferLen = 0;
|
||||
DynStringClear(self->conList);
|
||||
while(iRet != 0)
|
||||
{
|
||||
LLDnodeDataTo(self->iList,&NItem);
|
||||
@@ -736,14 +744,10 @@ extern int VerifyChannel(mkChannel *self); /* defined in network.c */
|
||||
{
|
||||
break;
|
||||
}
|
||||
snprintf(num,sizeof num, "%d, type %d:", NItem.pSock->sockid, NItem.eType);
|
||||
if (bufferLen + strlen(num) < sizeof buffer) {
|
||||
strcpy(buffer + bufferLen, num);
|
||||
bufferLen += strlen(num);
|
||||
} else {
|
||||
if (bufferFull == 0) {
|
||||
bufferFull = 1;
|
||||
}
|
||||
|
||||
sprintf(num,"%d, type %d:", NItem.pSock->sockid, NItem.eType);
|
||||
if(conCount < 100){
|
||||
DynStringConcat(self->conList,num);
|
||||
}
|
||||
FD_SET(NItem.pSock->sockid,&lMask);
|
||||
if(NItem.pSock->sockid > iCount)
|
||||
@@ -751,17 +755,20 @@ extern int VerifyChannel(mkChannel *self); /* defined in network.c */
|
||||
iCount = NItem.pSock->sockid;
|
||||
}
|
||||
conCount++;
|
||||
if(conCount > 100){
|
||||
WriteToCommandLog("WAYTOMANYCONNECTIONS> ", GetCharArray(self->conList));
|
||||
}
|
||||
iRet = LLDnodePtr2Next(self->iList);
|
||||
}
|
||||
|
||||
if(conCount > 100){
|
||||
WriteToCommandLog("WAYTOMANYCONNECTIONS> ", GetCharArray(self->conList));
|
||||
}
|
||||
|
||||
snprintf(num,sizeof num,"%d", conCount);
|
||||
IFSetOption(pSICSOptions,"ConnectionCount",num);
|
||||
IFSetOption(pSICSOptions,"ConMask",buffer);
|
||||
IFSetOption(pSICSOptions,"ConMask",GetCharArray(self->conList));
|
||||
|
||||
if (bufferFull == 1) {
|
||||
bufferFull = 2;
|
||||
WriteToCommandLog("BUFFERFULL>",buffer);
|
||||
}
|
||||
|
||||
/* the select itself */
|
||||
tmo.tv_usec = self->iReadTimeout;
|
||||
@@ -1072,5 +1079,348 @@ extern int VerifyChannel(mkChannel *self); /* defined in network.c */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*===================================================================================
|
||||
* new code to support the ANET network stuff
|
||||
* =================================================================================*/
|
||||
typedef struct {
|
||||
pDynString command;
|
||||
int state;
|
||||
SConnection *pCon;
|
||||
}CommandCBData, *pCommandCBData;
|
||||
/*----------------------------------------------------------------------------------*/
|
||||
static void killCommandCBData(void *data){
|
||||
pCommandCBData self = (pCommandCBData)data;
|
||||
if(self == NULL){
|
||||
return;
|
||||
}
|
||||
if(self->command != NULL){
|
||||
DeleteDynString(self->command);
|
||||
}
|
||||
free(self);
|
||||
}
|
||||
/*----------------------------------------------------------------------------------*/
|
||||
static int testAndInvokeInterrupt(pCommandCBData self, int handle){
|
||||
char *pPtr;
|
||||
char buffer[512];
|
||||
int iInt;
|
||||
|
||||
pPtr = GetCharArray(self->command);
|
||||
if(strstr(pPtr,"INT1712") != NULL){
|
||||
sscanf(pPtr, "%s %d",buffer, &iInt);
|
||||
if(SCMatchRights(self->pCon,usUser)) {
|
||||
TaskSignal(pServ->pTasker, SICSINT, &iInt);
|
||||
snprintf(buffer,512, "INTERRUPT %d issued on sock %d",
|
||||
iInt,handle);
|
||||
WriteToCommandLog("SYS>", buffer);
|
||||
if(iInt == eEndServer){
|
||||
TaskStop(pServ->pTasker);
|
||||
}
|
||||
} else {
|
||||
SCWrite(self->pCon,
|
||||
"ERROR: insufficient privilege to invoke Interrupt",
|
||||
eError);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*----------------------------------------------------------------------------------*/
|
||||
static int CommandDataCB(int handle, void *userData){
|
||||
pCommandCBData self = (pCommandCBData)userData;
|
||||
int i, length, status;
|
||||
char *pPtr = NULL;
|
||||
|
||||
assert(self != NULL);
|
||||
pPtr = ANETreadPtr(handle,&length);
|
||||
if(pPtr == NULL){
|
||||
return 1;
|
||||
}
|
||||
for(i = 0; i < length; i++){
|
||||
switch(self->state){
|
||||
case COLLECT:
|
||||
if(pPtr[i] == '\r' || pPtr[i] == '\n'){
|
||||
self->state = SKIPTERM;
|
||||
if(!testAndInvokeInterrupt(self,handle)){
|
||||
status = CostaTop(self->pCon->pStack, GetCharArray(self->command));
|
||||
if(!status){
|
||||
SCWrite(self->pCon,"ERROR: Busy", eError);
|
||||
}
|
||||
}
|
||||
DynStringClear(self->command);
|
||||
} else {
|
||||
if(pPtr[i] != '\0'){
|
||||
DynStringConcatChar(self->command, pPtr[i]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SKIPTERM:
|
||||
if(pPtr[i] != '\r' && pPtr[i] != '\n' && pPtr[i] != '\0'){
|
||||
DynStringConcatChar(self->command, pPtr[i]);
|
||||
self->state = COLLECT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
ANETreadConsume(handle, length);
|
||||
return 1;
|
||||
}
|
||||
/*----------------------------------------------------------------------------------*/
|
||||
static int CommandAcceptCB(int handle, void *userData){
|
||||
SConnection *pCon = NULL;
|
||||
pCommandCBData usData = NULL;
|
||||
|
||||
pCon = SCreateConnection(pServ->pSics, handle, 3);
|
||||
usData = malloc(sizeof(CommandCBData));
|
||||
if(pCon == NULL || usData == NULL){
|
||||
SICSLogWrite("Failure to allocate new Connection",eInternal);
|
||||
return 0;
|
||||
}
|
||||
usData->command = CreateDynString(256,256);
|
||||
if(usData->command == NULL){
|
||||
SICSLogWrite("Failure to allocate new Connection",eInternal);
|
||||
return 0;
|
||||
}
|
||||
usData->pCon = pCon;
|
||||
usData->state = COLLECT;
|
||||
TaskRegister(pServ->pTasker,
|
||||
SCTaskFunction,
|
||||
SCSignalFunction,
|
||||
SCDeleteConnection,
|
||||
pCon,
|
||||
1);
|
||||
ANETsetReadCallback(handle, CommandDataCB,
|
||||
usData, killCommandCBData);
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}
|
||||
/*-----------------------------------------------------------------------*/
|
||||
static int ANETTelnetReply(int sockHandle, char code, char cChar)
|
||||
{
|
||||
char pReply[3];
|
||||
|
||||
pReply[0] = IAC;
|
||||
pReply[1] = code;
|
||||
pReply[2] = cChar;
|
||||
|
||||
ANETwrite(sockHandle,pReply,3);
|
||||
return 1;
|
||||
}
|
||||
/*-----------------------------------------------------------------------*/
|
||||
static int ANETTelnetProcess(int handle, void *usData){
|
||||
pCommandCBData self = NULL;
|
||||
int length, status, i;
|
||||
int cChar;
|
||||
char *pPtr = NULL;
|
||||
char pError[256];
|
||||
|
||||
self = (pCommandCBData)usData;
|
||||
assert(self != NULL);
|
||||
|
||||
pPtr = ANETreadPtr(handle,&length);
|
||||
|
||||
/* do telnet analysis of the data buffer */
|
||||
for(i = 0; i < length; i++){
|
||||
cChar = (int)pPtr[i];
|
||||
#ifdef TELNETDEBUG
|
||||
if( (cChar > 48) && (cChar < 128) ){
|
||||
printf("char: %c\n",cChar);
|
||||
} else {
|
||||
printf("Control: %d\n",cChar);
|
||||
}
|
||||
#endif
|
||||
/* Telnet status switching */
|
||||
switch(self->state){
|
||||
case tData:
|
||||
switch(cChar){
|
||||
case IAC:
|
||||
self->state = tIAC;
|
||||
break;
|
||||
case '\r':
|
||||
case '\n':
|
||||
if(!testAndInvokeInterrupt(self,handle)){
|
||||
status = CostaTop(self->pCon->pStack, GetCharArray(self->command));
|
||||
if(!status){
|
||||
SCWrite(self->pCon,"ERROR: Busy", eError);
|
||||
}
|
||||
}
|
||||
self->state = tCR;
|
||||
DynStringClear(self->command);
|
||||
break;
|
||||
case (char)8: /* backspace */
|
||||
DynStringBackspace(self->command);
|
||||
break;
|
||||
case (char)0:/* ignore 0 character sent as end of text */
|
||||
break;
|
||||
default:
|
||||
DynStringConcatChar(self->command,(char)cChar);
|
||||
break;
|
||||
|
||||
} /* end of tData case */
|
||||
break;
|
||||
case tCR:
|
||||
if(cChar == '\r' || cChar == '\n' || cChar == '\0'){
|
||||
continue;
|
||||
} else {
|
||||
self->state = tData;
|
||||
DynStringConcatChar(self->command,(char)cChar);
|
||||
}
|
||||
break;
|
||||
case tIAC:
|
||||
switch(cChar)
|
||||
{
|
||||
case IAC:
|
||||
self->state = tData;
|
||||
break;
|
||||
case WILL:
|
||||
self->state = tWill;
|
||||
break;
|
||||
case WONT:
|
||||
self->state = tWont;
|
||||
break;
|
||||
case DONT:
|
||||
self->state = tDont;
|
||||
break;
|
||||
case DO:
|
||||
self->state = tDo;
|
||||
break;
|
||||
case EOR:
|
||||
self->state = tData;
|
||||
break;
|
||||
case SB:
|
||||
self->state = tSB;
|
||||
break;
|
||||
case EC:
|
||||
DynStringBackspace(self->command);
|
||||
self->state = tData;
|
||||
break;
|
||||
case EL:
|
||||
DynStringClear(self->command);
|
||||
self->state = tData;
|
||||
break;
|
||||
case IP:
|
||||
SCSetInterrupt(self->pCon,eAbortBatch);
|
||||
self->state = tData;
|
||||
break;
|
||||
default:
|
||||
self->state = tData;
|
||||
break;
|
||||
} /* end of tIAC */
|
||||
break;
|
||||
case tWill: /* we do not do options! */
|
||||
ANETTelnetReply(handle,DONT,cChar);
|
||||
self->state = tData;
|
||||
break;
|
||||
case tWont: /* we do not do options! A Wont is sent by the client
|
||||
if it cannot do a option we requested it to have. As
|
||||
we do not try to force options, this should not happen
|
||||
*/
|
||||
self->state = tData;
|
||||
break;
|
||||
case tDo: /* we do not do options! */
|
||||
ANETTelnetReply(handle,WONT,cChar);
|
||||
self->state = tData;
|
||||
break;
|
||||
case tDont: /* we do not do options! A Dont is sent by the client
|
||||
if it cannot do a option we requested it to have. As
|
||||
we do not try to force options, this should not happen
|
||||
*/
|
||||
self->state = tData;
|
||||
break;
|
||||
case tSB: /* as we do not have options, we cannot have suboption
|
||||
negotaitions. Something is seriously wrong when
|
||||
we are here. It is a protocoll error. However, we
|
||||
ignore it silently. tSB marks the start of the
|
||||
subnegotiation. The current character must be the
|
||||
option code we are dealing with.
|
||||
*/
|
||||
self->state = tSE;
|
||||
break;
|
||||
case tSE:
|
||||
/* now we are in the suboption parameter. Normally data
|
||||
should be copied to a suboption string buffer here
|
||||
until SE.
|
||||
*/
|
||||
switch(cChar)
|
||||
{
|
||||
case IAC:
|
||||
break;
|
||||
case SE:
|
||||
self->state = tData;
|
||||
/* suboption interpretation would go here */
|
||||
break;
|
||||
default:
|
||||
/* copy data to suboption buffer */
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* There is something wrong here! */
|
||||
sprintf(pError,"ERROR: bad telnet code %d", cChar);
|
||||
SICSLogWrite(pError,eInternal);
|
||||
self->state = tData;
|
||||
break;
|
||||
|
||||
} /* end master swicth */
|
||||
} /* end for loop */
|
||||
ANETreadConsume(handle,length);
|
||||
return 1;
|
||||
}
|
||||
/*----------------------------------------------------------------------------------*/
|
||||
static int TelnetAcceptCB(int handle, void *userData){
|
||||
SConnection *pCon = NULL;
|
||||
pCommandCBData usData = NULL;
|
||||
pTelTask pTel = NULL;
|
||||
|
||||
pCon = SCreateConnection(pServ->pSics, handle, 3);
|
||||
usData = malloc(sizeof(CommandCBData));
|
||||
if(pCon == NULL || usData == NULL){
|
||||
SICSLogWrite("Failure to allocate new Connection",eInternal);
|
||||
return 0;
|
||||
}
|
||||
usData->command = CreateDynString(256,256);
|
||||
if(usData->command == NULL){
|
||||
SICSLogWrite("Failure to allocate new Connection",eInternal);
|
||||
return 0;
|
||||
}
|
||||
usData->pCon = pCon;
|
||||
usData->state = tData;
|
||||
/* Create a task object for the telnet connection */
|
||||
pTel = CreateTelnet(pCon);
|
||||
if(!pTel){
|
||||
SICSLogWrite("Failure to allocate new Telnet Task Object",
|
||||
eInternal);
|
||||
SCDeleteConnection(pCon);
|
||||
return 0;
|
||||
}
|
||||
/* register connection and task */
|
||||
pCon->iTelnet = 1;
|
||||
TaskRegister(pServ->pTasker,
|
||||
TelnetTask,
|
||||
TelnetSignal,
|
||||
DeleteTelnet,
|
||||
pTel,
|
||||
1);
|
||||
ANETsetReadCallback(handle, ANETTelnetProcess,
|
||||
usData, killCommandCBData);
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}
|
||||
/*------------------------------------------------------------------------------------*/
|
||||
static void NREADlog(int level, char *txt, void *userData){
|
||||
puts(txt);
|
||||
}
|
||||
/*------------------------------------------------------------------------------------*/
|
||||
int NetReadInstallANETPort(pNetRead self, eNRType eType, int iPort){
|
||||
ANETsetLog(NREADlog,NULL);
|
||||
switch(eType){
|
||||
case naccept:
|
||||
return ANETopenServerPort(iPort,CommandAcceptCB,NULL);
|
||||
break;
|
||||
case taccept:
|
||||
return ANETopenServerPort(iPort,TelnetAcceptCB,NULL);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user