Files
sics/nserver.c

525 lines
13 KiB
C

/*--------------------------------------------------------------------------
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 <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
#include <time.h>
#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"
extern int openDevexecLog(); /* in devexec.c */
extern int NetWatchTask(void *pData); /* in nwatch.c */
/*------------------------------------------------------------------------*/
static void StopExit(void)
{
if (pServ) {
StopServer(pServ);
}
LogClose(NULL);
}
#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 */
TaskerInit(&self->pTasker);
assert(self->pTasker != NULL);
pSICSOptions = IFAddOption(pSICSOptions, "ConnectionCount", "0");
pSICSOptions = IFAddOption(pSICSOptions, "ConMask", "0");
/* initialize the network watcher */
TaskRegisterN(self->pTasker, "nwatch", NetWatchTask, NULL, NULL, NULL, TASK_PRIO_HIGH);
/* 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();
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);
TaskRegisterN(self->pTasker, "Network Reader",
NetReaderTask, NetReaderSignal, NULL, /* call DeleteNetReader later than TaskerDelete */
pReader, TASK_PRIO_HIGH);
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;
}
if (NetReadInstallANETPort(pReader, naccept, iPort) < 0) {
printf("can not open server port %d - probably this SeaServer is already running\n", iPort);
exit(0);
}
/* 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);
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;
}
/* install a secret fully priviledged entry point for ME */
AddUser("Achterbahn", "Kiel", usInternal);
/* install a secret entry point for remote objects */
AddUser("RemoteMaster","3ed4c656a15f0aa45e02fd5ec429225bb93b762e7eb06cc81a0b4f6c35c76184",usInternal);
/* install environment monitor */
self->pMonitor = GetEnvMon(self->pSics);
TaskRegisterN(self->pTasker,"EV Monitor",
EnvMonTask, EnvMonSignal, NULL, self->pMonitor, TASK_PRIO_HIGH);
/* install performance monitor */
pMon = CreatePerfMon(20);
AddCommand(self->pSics, "Performance", PerfMonWrapper, DeletePerfMon,
pMon);
TaskRegisterN(self->pTasker,"perfmon", PerfMonTask, PerfMonSignal, NULL, pMon, TASK_PRIO_HIGH);
/* Install a second one for higher granularity measurement */
pMon = CreatePerfMon(2);
TaskRegisterN(self->pTasker,"perfmon2",
PerfMonTask, PerfMonSignal, DeletePerfMon, pMon, TASK_PRIO_HIGH);
/* 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);
}
INIT(StatusFileInit);
/* install status task */
InitStatus();
/* 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();
/* Remove Status Callback */
KillStatus(NULL);
/*
kill the site data structure
*/
site = getSite();
if (site != NULL) {
site->KillSite(site);
}
/*
kill overloaded interfaces data
*/
killTclDrivable();
killSICSHipadaba();
/* close the List system */
LLDsystemClose();
/* make fortify print his findings */
(void)Fortify_DumpAllMemory(iFortifyScope);
(void)Fortify_LeaveScope();
free(self);
LogClose(NULL);
}
/*------------------------------------------------------------------------*/
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;
}
sWait.dFinish = DoubleTime() + (double)fVal;
sWait.iEnd = 0;
lID = TaskRegisterN(pTask,"wait", WaitTask, WaitSignal, NULL, &sWait, TASK_PRIO_HIGH);
TaskWait(pTask, lID); if (SCGetInterrupt(pCon) != eContinue) {
return 0;
} else {
return 1;
}
}
/*--------------------------------------------------------------------------*/
int UserYield(SConnection * pCon, SicsInterp * pSics, void *pData,
int argc, char *argv[])
{
TaskYield(pServ->pTasker);
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;
}
pServer pServ = NULL;
/*--------------------------------------------------------------------------*/
SicsInterp *GetInterpreter(void)
{
return pServ->pSics;
}
/*--------------------------------------------------------------------------*/
pExeList GetExecutor(void)
{
return pServ->pExecutor;
}
/*-------------------------------------------------------------------------*/
pTaskMan GetTasker(void)
{
return pServ->pTasker;
}