/*-------------------------------------------------------------------------- THE SICS SERVER Mark Koennecke, October 1996 Revised for use with tasker: Mark Koennecke, September 1997 Added code to redirect stdout/sterr to file, Mark Koennecke, May 2000 Define handler in InitServer to ignore SIGPIPE. Paul Hathaway, May 2004 Copyright: see copyright.h ----------------------------------------------------------------------------*/ #define NEEDDINTINIT #include "fortify.h" #include #include #include #include #include #include #include #include "sics.h" #include "network.h" #include "ifile.h" #include "status.h" #include "statusfile.h" #include "devexec.h" #include "passwd.h" #include "lld.h" #include "macro.h" #include "perfmon.h" #include "nread.h" #include "ofac.h" #include "telnet.h" #include "site.h" #include "tcldrivable.h" #include "nserver.h" #include "sicshipadaba.h" int ServerSetupInterrupt(int iPort, pNetRead pNet, pTaskMan pTasker); /* configures a port for listening for interrupts */ extern void StopExit(void); /* in SICSmain.c */ extern int openDevexecLog(); /* in devexec.c */ extern void NetWatchInit(void); /* in nwatch.c */ /* ========================= Less dreadful file statics =================== */ #define DEFAULTINIFILE "servo.tcl" #define DEFAULTSTATUSFILE "sicsstat.tcl" static int iFortifyScope; #include "obdes.h" #include "interface.h" #include "sicsvar.h" #include "emon.h" /*----------------------------------------------------------------------*/ pEnvMon GetEnvMon(SicsInterp *pSics) { CommandList *pCom; assert(pSics); pCom = FindCommand(pSics,"emon"); assert(pCom); assert(pCom->pData); return (pEnvMon)pCom->pData; } /*-------------------------------------------------------------------------*/ int InitServer(char *file, pServer *pServ) { char *pText = NULL; int iPort, iRet; FILE *fp; pSicsVariable pVar; char pBueffel[512]; SConnection *pCon = NULL; pServer self = NULL; char *pPtr; int iCommandTimeOut, iPasswordTimeOut, i; pNetRead pReader = NULL; pPerfMon pMon = NULL; CommandList *pCom; pid_t myPid; /* allocate a new server structure */ self = (pServer)malloc(sizeof(SicsServer)); if(!self) { puts("DEADLY ERROR: Cannot allocate server data structure!"); return 0; } memset(self,0,sizeof(SicsServer)); *pServ = self; /* define any signal handlers */ signal(SIGPIPE,SIG_IGN); /* configure fortify */ iFortifyScope = Fortify_EnterScope(); Fortify_CheckAllMemory(); /* interpreter */ self->pSics = InitInterp(); assert(self->pSics); /* initialise tasker */ assert(TaskerInit(&self->pTasker)); pSICSOptions = IFAddOption(pSICSOptions, "ConnectionCount","0"); pSICSOptions = IFAddOption(pSICSOptions, "ConMask","0"); /* initialize the network watcher */ NetWatchInit(); /* initialise the server from script */ if(file == NULL) { iRet = InitObjectCommands(self,DEFAULTINIFILE); } else { iRet = InitObjectCommands(self,file); } if(!iRet) { if(file) { printf("Error on initialization file --> %s <-- \n",file); } else { printf("Error on initialization file --> %s <-- \n",DEFAULTINIFILE); } return 0; } self->dummyCon = SCCreateDummyConnection(self->pSics); /* check for option RedirectFile and redirect stout/sterr to it if present. */ pPtr = NULL; pPtr = IFindOption(pSICSOptions,"RedirectFile"); if(pPtr != NULL) { myPid = getpid(); sprintf(pBueffel,"%s%5.5d.log",pPtr,(int)myPid); fp = freopen(pBueffel,"w",stdout); if(!fp) { printf("Failed to redirect stdout/stderr to %s\n",pBueffel); } fp = freopen(pBueffel,"w",stderr); if(!fp) { printf("Failed to redirect stdout/stderr to %s\n",pBueffel); } } /* initialise net reader */ pPtr = NULL; pPtr = IFindOption(pSICSOptions,"ReadTimeOut"); if(pPtr != NULL) { i = atoi(pPtr); iCommandTimeOut = i; } else { iCommandTimeOut = 100; /* this is in microseconds and anyway o.k. */ } pPtr = NULL; pPtr = IFindOption(pSICSOptions,"ReadUserPasswdTimeout"); if(pPtr != NULL) { i = atoi(pPtr); iPasswordTimeOut = i; } else { iPasswordTimeOut = 1; /* never used, but checked ! */ } assert((pReader = CreateNetReader(self,iPasswordTimeOut,iCommandTimeOut)) != NULL); TaskRegister(self->pTasker, NetReaderTask, NetReaderSignal, NULL, /* call DeleteNetReader later than TaskerDelete */ pReader,1); self->pReader = pReader; /* the socket */ pText = IFindOption(pSICSOptions,"ServerPort"); if(!pText) { printf("Cannot find ServerPort number in options file %s\n", "This value is required!"); DeleteInterp(self->pSics); IFDeleteOptions(pSICSOptions); return 0; } iRet = sscanf(pText,"%d",&iPort); if( (iRet != 1) || (iPort < 1024) ) { printf("Invalid port number specified in Server initialisation file\n"); DeleteInterp(self->pSics); IFDeleteOptions(pSICSOptions); return 0; } self->pServerPort = NETOpenPort(iPort); if(!self->pServerPort) { printf("Cannot open Server Socket\n"); DeleteInterp(self->pSics); IFDeleteOptions(pSICSOptions); return 0; } NetReadRegister(pReader, self->pServerPort, naccept, NULL); /* the device executor */ openDevexecLog(); DevexecLog("START","SICS"); /* initialize Interrupt Port */ pText = IFindOption(pSICSOptions,"InterruptPort"); if(!pText) { printf("Cannot find InterruptPort number in options file %s\n", "This value is required!"); DeleteInterp(self->pSics); IFDeleteOptions(pSICSOptions); return 0; } iRet = sscanf(pText,"%d",&iPort); if( (iRet != 1) || (iPort < 1024) ) { printf("Invalid port number specified in Server initialisation file\n"); DeleteInterp(self->pSics); IFDeleteOptions(pSICSOptions); return 0; } iRet = ServerSetupInterrupt(iPort,pReader,self->pTasker); if(!iRet) { SCWrite(pCon,"WARNING: UDP interrupt port not initialized",eWarning); } /* install a secret fully priviledged entry point for ME */ AddUser("Achterbahn","Kiel",usInternal); /* install environment monitor */ self->pMonitor = GetEnvMon(self->pSics); TaskRegister(self->pTasker, EnvMonTask, EnvMonSignal, NULL, self->pMonitor,1); /* install performance monitor */ pMon = CreatePerfMon(20); AddCommand(self->pSics,"Performance",PerfMonWrapper,DeletePerfMon,pMon); TaskRegister(self->pTasker, PerfMonTask, PerfMonSignal, NULL, pMon,1); /* install telnet port */ InstallTelnet(); /* If the restore file has not been loaded, do so now */ if(!hasRestored()) { strcpy(pBueffel,"restore"); SCInvoke(self->dummyCon,self->pSics,pBueffel); } /* exit handlers need to be installed here */ atexit(StopExit); Fortify_CheckAllMemory(); return 1; } /*---------------------------------------------------------------------------*/ void StopServer(pServer self) { SConnection *pCurrent, *pTemp; char pBueffel[512]; char *pText = NULL; SConnection *pCon = NULL; pSite site = NULL; /* clear all pending bullshit */ ClearExecutor(self->pExecutor); DevexecLog("STOP","SICS"); /* shut telnet down */ KillTelnet(); /* shut tasker down */ TaskerDelete(&self->pTasker); self->pTasker = NULL; /* save status */ if(!self->simMode) { strcpy(pBueffel,"Backup "); pText = IFindOption(pSICSOptions,"statusfile"); if(pText) { strcat(pBueffel,pText); } else { strcat(pBueffel,DEFAULTSTATUSFILE); } if(self->dummyCon) { InterpExecute(self->pSics,self->dummyCon,pBueffel); SCDeleteConnection(self->dummyCon); } else { printf("ERROR: Cannot allocate dummy connection, status NOT saved"); } } /* close redirection file if present */ pText = NULL; pText = IFindOption(pSICSOptions,"RedirectFile"); if(pText) { fclose(stderr); } /* clean out */ if(self->pSics) { DeleteInterp(self->pSics); self->pSics = NULL; } /* remove options after interpreter as some object kill functions may use options */ if(pSICSOptions) IFDeleteOptions(pSICSOptions); /* delete net reader */ DeleteNetReader(self->pReader); self->pReader = NULL; /* close the server port */ if(self->pServerPort) { NETClosePort(self->pServerPort); free(self->pServerPort); } /* remove the in memory password database */ KillPasswd(); /* close Interrupt system */ ServerStopInterrupt(); /* Remove Status Callback */ KillStatus(NULL); /* kill the site data structure */ site = getSite(); if(site != NULL) { site->KillSite(site); } /* kill overloaded interfaces data */ killTclDrivable(); KillFreeConnections(); killSICSHipadaba(); /* close the List system */ LLDsystemClose(); /* make fortify print his findings */ Fortify_DumpAllMemory(iFortifyScope); Fortify_LeaveScope(); free(self); } /*------------------------------------------------------------------------*/ void RunServer(pServer self) { TaskSchedule(self->pTasker); } /*------------------------------------------------------------------------*/ typedef struct { time_t tFinish; int iEnd; } WaitStruct, *pWaitStruct; /*-------------------------------------------------------------------------*/ static int WaitTask(void *pData) { time_t tNow; pWaitStruct self = NULL; self = (pWaitStruct)pData; if(self->iEnd) { return 0; } tNow = time(NULL); if(tNow >= self->tFinish) { return 0; /* done */ } else { return 1; } } /*-----------------------------------------------------------------------*/ static void WaitSignal(void *pUser, int iSignal, void *pEventData) { pWaitStruct self = NULL; int *iInt; self = (pWaitStruct)pUser; assert(self); iInt = (int *)pEventData; if(iSignal == SICSINT) { iInt = (int *)pEventData; if(*iInt > eContinue) { self->iEnd = 1; } } } /*-------------------------------------------------------------------------- UserWait: the user command for waiting, expects one arg: time to wait in seconds ---------------------------------------------------------------------------*/ int UserWait(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) { int i; char pBueffel[80]; float fVal; Status eOld; time_t tNow; WaitStruct sWait; pTaskMan pTask; long lID; assert(pCon); assert(pSics); assert(pData); pTask = GetTasker(); if(argc < 2) { sprintf(pBueffel,"Insufficient number of args to %s",argv[0]); SCWrite(pCon,pBueffel,eError); return 0; } /* try convert to a number */ i = sscanf(argv[1],"%f",&fVal); if(i < 1) { sprintf(pBueffel,"Expected numeric argument to %s, got %s", argv[0], argv[1]); SCWrite(pCon,pBueffel,eInError); return 0; } if(pServ->simMode) { return 1; } eOld = GetStatus(); SetStatus(eUserWait); tNow = time(NULL); sWait.tFinish = tNow + (time_t)fVal; sWait.iEnd = 0; lID = TaskRegister(pTask,WaitTask,WaitSignal,NULL,&sWait,1); TaskWait(pTask,lID); SetStatus(eOld); if(SCGetInterrupt(pCon) != eContinue) { return 0; } else { return 1; } } /*------------------------------------------------------------------------*/ int SicsWaitOld(long lTime) { WaitStruct sWait; pTaskMan pTasker = NULL; time_t tNow; long lID; if(pServ->simMode) { return 1; } pTasker = GetTasker(); tNow = time(NULL); sWait.tFinish = tNow + lTime; sWait.iEnd = 0; lID = TaskRegister(pTasker,WaitTask,WaitSignal,NULL,&sWait,1); TaskWait(pTasker,lID); return 1; } /*------------------------------------------------------------------------ The new SicsWait is still on probation. It prevents commands to be executed on the same task on which the Sicswait is acting. M.K. December 2005 -------------------------------------------------------------------------*/ int SicsWait(long lTime) { pTaskMan pTasker = NULL; time_t endTime; if(pServ->simMode) { return 1; } pTasker = GetTasker(); endTime = time(NULL) + lTime; while(time(NULL) < endTime) { TaskYield(pTasker); } return 1; } /*-------------------------------------------------------------------------*/ void ServerWriteGlobal(char *pMessage,int iOut) { pTaskMan pTasker = NULL; pTasker = GetTasker(); TaskSignal(pTasker,SICSBROADCAST,pMessage); } /*-------------------------------------------------------------------------*/ int ServerIsStarting(pServer self) { return self->pReader == NULL; }