/*-------------------------------------------------------------------------- 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" #include "commandlog.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" #define INIT(F) { void F(void); F(); } 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(); (void)Fortify_CheckAllMemory(); /* interpreter */ self->pSics = InitInterp(); self->dummyCon = SCCreateDummyConnection(self->pSics); assert(self->dummyCon != NULL); 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 */ SetWriteHistory(0); 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(); snprintf(pBueffel,sizeof(pBueffel)-1, "%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); */ NetReadInstallANETPort(pReader, naccept, iPort); /* 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 a second one for higher granularity measurement */ pMon = CreatePerfMon(2); TaskRegister(self->pTasker, PerfMonTask, PerfMonSignal, DeletePerfMon, 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); } SetWriteHistory(1); INIT(StatusFileInit); /* exit handlers need to be installed here */ atexit(StopExit); (void)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) { strlcat(pBueffel, pText,511); } 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 */ (void)Fortify_DumpAllMemory(iFortifyScope); (void)Fortify_LeaveScope(); free(self); } /*------------------------------------------------------------------------*/ void RunServer(pServer self) { TaskSchedule(self->pTasker); } /*------------------------------------------------------------------------*/ typedef struct { double dFinish; int iEnd; } WaitStruct, *pWaitStruct; /*-------------------------------------------------------------------------*/ static int WaitTask(void *pData) { pWaitStruct self = NULL; self = (pWaitStruct) pData; if (self->iEnd) { return 0; } if (DoubleTime() >= self->dFinish) { 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; WaitStruct sWait; pTaskMan pTask; long lID; assert(pCon); assert(pSics); assert(pData); pTask = GetTasker(); if (argc < 2) { snprintf(pBueffel,sizeof(pBueffel)-1, "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) { snprintf(pBueffel,sizeof(pBueffel)-1, "Expected numeric argument to %s, got %s", argv[0], argv[1]); SCWrite(pCon, pBueffel, eError); return 0; } if (pServ->simMode) { return 1; } eOld = GetStatus(); SetStatus(eUserWait); sWait.dFinish = DoubleTime() + (double)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 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; }