1099 lines
28 KiB
C
1099 lines
28 KiB
C
/*-----------------------------------------------------------------------
|
|
remob.c
|
|
|
|
implements remote driveable objects living on an other sics server
|
|
|
|
M. Zolliker July 04
|
|
|
|
------------------------------------------------------------------------*/
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include <netdb.h>
|
|
#include "fortify.h"
|
|
#include "sics.h"
|
|
#include "devexec.h"
|
|
#include "remob.h"
|
|
#include "splitter.h"
|
|
#include "status.h"
|
|
#include "site.h"
|
|
/*-------------------------------------------------------------------------*/
|
|
#define INTERRUPTMODE 0
|
|
#define ACCESSCODE 1
|
|
|
|
/*------------------------------------------------------------------------ */
|
|
typedef struct Remob Remob;
|
|
|
|
typedef struct RemChannel {
|
|
mkChannel *chan;
|
|
int timeout;
|
|
int incomplete;
|
|
char line[1024];
|
|
} RemChannel;
|
|
|
|
typedef struct RemServer {
|
|
pObjectDescriptor desc;
|
|
char *name;
|
|
char *host;
|
|
int port;
|
|
RemChannel rc[2];
|
|
Remob *objList;
|
|
int matchMap;
|
|
int taskActive;
|
|
int interestActive;
|
|
int forwardMessages;
|
|
SConnection *conn;
|
|
} RemServer;
|
|
|
|
struct Remob {
|
|
pObjectDescriptor desc;
|
|
char *name;
|
|
pIDrivable pDrivInt;
|
|
pICallBack pCall;
|
|
RemServer *server;
|
|
int status;
|
|
Remob *next;
|
|
int markForDel;
|
|
};
|
|
|
|
typedef struct {
|
|
float fVal;
|
|
char *pName;
|
|
} RemobCallback;
|
|
|
|
typedef struct {
|
|
char *pName;
|
|
SConnection *pCon;
|
|
} RemobInfo;
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
static char *StartsWith(char *line, char *name)
|
|
{
|
|
/* if line does not start with name, return NULL
|
|
else return a pointer to the next non-white space character
|
|
*/
|
|
char *str;
|
|
int l;
|
|
|
|
l = strlen(name);
|
|
if (0 != strncmp(line, name, l))
|
|
return NULL;
|
|
str = line + l;
|
|
while (*str == ' ') {
|
|
str++;
|
|
}
|
|
return str;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
static int RemWrite(RemChannel * rc, char *line)
|
|
{
|
|
int iret;
|
|
|
|
if (rc->chan) {
|
|
/* printf("> %s\n", line); */
|
|
iret = NETWrite(rc->chan, line, strlen(line));
|
|
if (iret == 0)
|
|
iret = -1;
|
|
return iret;
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
static int RemRead(RemChannel * rc, long tmo)
|
|
{
|
|
int iRet;
|
|
|
|
if (rc->chan == NULL)
|
|
return 0; /* no data */
|
|
iRet = NETReadTillTerm(rc->chan, tmo, "\n", rc->line + rc->incomplete,
|
|
sizeof(rc->line) - rc->incomplete);
|
|
if (iRet == 0) {
|
|
rc->incomplete = strlen(rc->line); /* number of chars already received */
|
|
return 0; /* timeout */
|
|
} else {
|
|
rc->incomplete = 0;
|
|
}
|
|
return iRet;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
static int RemHandle(RemServer * remserver)
|
|
{
|
|
char *line, *par, *str;
|
|
Remob *remob;
|
|
RemChannel *rc;
|
|
|
|
rc = &remserver->rc[0]; /* drivstat messages appear only on the spy channel */
|
|
|
|
/* skip whitespace at the beginning */
|
|
line = rc->line;
|
|
if (line[0] == '\0')
|
|
return 0; /* return when line is empty */
|
|
while (*line < ' ' && *line != '\0') {
|
|
line++;
|
|
}
|
|
memmove(rc->line, line, strlen(line));
|
|
|
|
/* handle drivstat messages */
|
|
line = rc->line;
|
|
|
|
for (remob = remserver->objList; remob != NULL; remob = remob->next) {
|
|
par = StartsWith(line, remob->name);
|
|
if (par != NULL) {
|
|
if ((str = StartsWith(par, "finished"))) {
|
|
if (*str == '\0') {
|
|
remob->status = HWIdle;
|
|
} else {
|
|
remob->status = HWFault;
|
|
}
|
|
line[0] = '\0';
|
|
return 1;
|
|
}
|
|
if ((str = StartsWith(par, "started"))) {
|
|
remob->status = HWBusy;
|
|
line[0] = '\0';
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
static void RemCopy(RemChannel * rc, SConnection * pCon)
|
|
{
|
|
if (pCon != NULL && rc->line[0] != '\0') {
|
|
SCPrintf(pCon, eValue, " %s", rc->line);
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
static void RemDisconnect(RemServer * remserver)
|
|
{
|
|
int isUser;
|
|
RemChannel *rc;
|
|
|
|
for (isUser = 0; isUser <= 1; isUser++) {
|
|
rc = &remserver->rc[isUser];
|
|
if (rc->chan != NULL) {
|
|
NETClosePort(rc->chan);
|
|
free(rc->chan);
|
|
rc->chan = NULL;
|
|
/* printf("disconnected\n"); */
|
|
}
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
static int RemSetInterest(RemChannel * rc)
|
|
{
|
|
int iRet;
|
|
|
|
if (rc->chan != NULL) { /* already connected */
|
|
iRet = RemWrite(rc, "transact listexe interest\n");
|
|
if (iRet >= 0) {
|
|
iRet = RemRead(rc, 1000);
|
|
while (iRet > 0) { /* eat response */
|
|
if (StartsWith(rc->line, "TRANSACTIONFINISHED")) {
|
|
return 1;
|
|
}
|
|
iRet = RemRead(rc, 1000);
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
static void RemConnect(RemServer * remserver, int both)
|
|
{
|
|
/* open channel 0 or both channels, if not yet opened */
|
|
int iRet;
|
|
mkChannel *chan;
|
|
int i;
|
|
RemChannel *rc;
|
|
|
|
for (i = 0; i <= both; i++) {
|
|
rc = &remserver->rc[i];
|
|
if (!rc->chan) {
|
|
rc->timeout = 0;
|
|
chan = NETConnect(remserver->host, remserver->port);
|
|
if (!chan) {
|
|
return;
|
|
}
|
|
rc->chan = chan;
|
|
if (i != 0) { /* open the user channel */
|
|
iRet = RemWrite(rc, "remuser sesam\n");
|
|
} else { /* open spy channel */
|
|
iRet = RemWrite(rc, "Spy 007\n");
|
|
}
|
|
if (iRet < 0)
|
|
goto close;
|
|
iRet = RemRead(rc, 1000);
|
|
while (iRet > 0) { /* eat login response */
|
|
if (StartsWith(rc->line, "Login OK")) {
|
|
/* printf("connected\n"); */
|
|
if (remserver->interestActive && rc == &remserver->rc[0]) { /* open the user channel */
|
|
if (!RemSetInterest(rc))
|
|
goto close;
|
|
}
|
|
break;
|
|
}
|
|
iRet = RemRead(rc, 1000);
|
|
}
|
|
if (iRet <= 0)
|
|
goto close;
|
|
}
|
|
}
|
|
return;
|
|
close:
|
|
RemDisconnect(remserver);
|
|
return;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
static int RemServerTask(void *data)
|
|
{
|
|
RemServer *remserver = data;
|
|
int iRet;
|
|
SConnection *pCon;
|
|
int isUser;
|
|
RemChannel *rc;
|
|
|
|
if (!remserver->taskActive)
|
|
return 0; /* remove task */
|
|
|
|
for (isUser = 0; isUser <= 1; isUser++) {
|
|
rc = &remserver->rc[isUser];
|
|
if (RemRead(rc, 0) <= 0)
|
|
continue;
|
|
|
|
if (strstr(rc->line, " ") == rc->line) {
|
|
Log(ERROR,"sys","%s:%s","REMOB", "infinite echo loop detected");
|
|
continue;
|
|
}
|
|
if (isUser == 0) {
|
|
if (RemHandle(remserver)) { /* handle drivstat messages */
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (remserver->forwardMessages) {
|
|
/* forward all other messages */
|
|
if (SCisConnected(remserver->conn)) {
|
|
RemCopy(rc, remserver->conn);
|
|
}
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
static int RemTransact(RemServer * remserver, int nChan,
|
|
SConnection * pCon, char *cmd, ...)
|
|
{
|
|
/* the variable arguments are for filtering:
|
|
|
|
"<name", &val get float value named name
|
|
"!blabla" skip lines starting with blabla
|
|
">" write untreated lines to pCon
|
|
*/
|
|
char *buffer;
|
|
int bufferLen;
|
|
int iRet;
|
|
char *arg, *val, *endp;
|
|
float *f;
|
|
va_list ap;
|
|
int try;
|
|
int argMask;
|
|
RemChannel *rc = &remserver->rc[nChan];
|
|
pDynString errorResult;
|
|
|
|
try = 3;
|
|
if (rc->timeout) { /* eat old responses */
|
|
while (RemRead(rc, 0) > 0) {
|
|
RemHandle(remserver);
|
|
}
|
|
}
|
|
tryagain:
|
|
bufferLen = strlen(cmd) + 16;
|
|
buffer = malloc(bufferLen);
|
|
if (buffer == NULL) {
|
|
SCPrintf(pCon, eError, "ERROR: can not get another %d bytes",
|
|
bufferLen);
|
|
return 0;
|
|
}
|
|
snprintf(buffer, bufferLen, "transact %s\n", cmd);
|
|
RemConnect(remserver, nChan);
|
|
iRet = RemWrite(rc, buffer);
|
|
free(buffer);
|
|
if (iRet < 0)
|
|
goto close;
|
|
|
|
iRet = RemRead(rc, 2000);
|
|
if (iRet <= 0)
|
|
goto close;
|
|
while (!StartsWith(rc->line, "TRANSACTIONFINISHED")) {
|
|
if (StartsWith(rc->line, "ERROR:")) {
|
|
errorResult = CreateDynString(60, 64);
|
|
do {
|
|
RemHandle(remserver);
|
|
DynStringConcat(errorResult, rc->line);
|
|
DynStringConcat(errorResult, "\n");
|
|
iRet = RemRead(rc, 2000);
|
|
} while (!StartsWith(rc->line, "TRANSACTIONFINISHED"));
|
|
if (pCon != NULL) {
|
|
SCPrintf(pCon, eError, "ERROR: in %s:\n%s", remserver->name, GetCharArray(errorResult));
|
|
}
|
|
DeleteDynString(errorResult);
|
|
return -2;
|
|
}
|
|
RemHandle(remserver);
|
|
va_start(ap, cmd);
|
|
arg = va_arg(ap, char *);
|
|
argMask = 1;
|
|
remserver->matchMap = 0;
|
|
while (arg != NULL) {
|
|
if (*arg == '>') {
|
|
RemCopy(rc, pCon);
|
|
} else if (*arg == '<') {
|
|
f = va_arg(ap, float *);
|
|
val = StartsWith(rc->line, arg + 1);
|
|
if (val != NULL) {
|
|
val = StartsWith(val, "=");
|
|
if (val != NULL) {
|
|
*f = strtod(val, &endp);
|
|
break;
|
|
}
|
|
}
|
|
} else if (*arg == '!') {
|
|
if (StartsWith(rc->line, arg + 1)) {
|
|
remserver->matchMap |= argMask;
|
|
argMask = argMask * 2;
|
|
break;
|
|
}
|
|
} else {
|
|
printf("unknown argument in RemTransact: %s\n", arg);
|
|
assert(0);
|
|
}
|
|
arg = va_arg(ap, char *);
|
|
}
|
|
va_end(ap);
|
|
iRet = RemRead(rc, 2000);
|
|
if (iRet <= 0)
|
|
goto close;
|
|
}
|
|
return 1;
|
|
close:
|
|
if (iRet == 0) {
|
|
if (try == 1) {
|
|
SCPrintf(pCon, eError, "ERROR: timeout on %s", remserver->name);
|
|
rc->timeout = 1;
|
|
return iRet;
|
|
} else {
|
|
SCPrintf(pCon, eError, "WARNING: timeout on %s", remserver->name);
|
|
}
|
|
}
|
|
RemDisconnect(remserver);
|
|
try--;
|
|
if (try > 0)
|
|
goto tryagain;
|
|
SCPrintf(pCon, eError, "ERROR: no connection to %s", remserver->name);
|
|
return iRet;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
static void *RemobGetInterface(void *pData, int iID)
|
|
{
|
|
Remob *self = pData;
|
|
|
|
assert(self);
|
|
if (iID == DRIVEID) {
|
|
return self->pDrivInt;
|
|
} else if (iID == CALLBACKINTERFACE) {
|
|
return self->pCall;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
static int RemobHalt(void *self)
|
|
{
|
|
Remob *remob = self;
|
|
RemServer *remserver = remob->server;
|
|
RemChannel *rc = &remserver->rc[1]; /* Halt is only called with at least user priv. */
|
|
char buf[64];
|
|
|
|
assert(remob);
|
|
RemConnect(remserver, 1);
|
|
snprintf(buf, sizeof(buf), "stopexe %s\n", remob->name);
|
|
remob->status = HWFault;
|
|
return RemWrite(rc, buf);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static int RemobLimits(void *self, float fVal, char *error, int iErrLen)
|
|
{
|
|
float fHard;
|
|
Remob *remob = self;
|
|
|
|
assert(remob);
|
|
/* check is done on remote server */
|
|
return 1;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
static float RemobGetValue(void *pData, SConnection * pCon)
|
|
{
|
|
Remob *remob = pData;
|
|
RemServer *remserver = remob->server;
|
|
char buf[80];
|
|
float none, value;
|
|
int iRet;
|
|
|
|
assert(remob);
|
|
|
|
if (remserver->conn != NULL) {
|
|
SCDeleteConnection(remserver->conn);
|
|
}
|
|
remserver->conn = SCCopyConnection(pCon);
|
|
none = -1.234e32;
|
|
value = none;
|
|
snprintf(buf, sizeof(buf), "<%s", remob->name);
|
|
/* get value needs only spy priviledge */
|
|
iRet =
|
|
RemTransact(remserver, 0, pCon, remob->name, buf, &value, ">", NULL);
|
|
/*
|
|
if (iRet <= 0) {
|
|
return 0.0;
|
|
}
|
|
*/
|
|
if (value != none) {
|
|
return value;
|
|
}
|
|
snprintf(buf, sizeof(buf), "can not get %s", remob->name);
|
|
SCWrite(pCon, buf, eWarning);
|
|
return 0.0;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
static int RemobSaveStatus(void *pData, char *name, FILE * fil)
|
|
{
|
|
Remob *self = pData;
|
|
|
|
assert(self);
|
|
assert(fil);
|
|
|
|
/*
|
|
data is stored on remote server
|
|
*/
|
|
return 1;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
static int RemServerSaveStatus(void *pData, char *name, FILE * fil)
|
|
{
|
|
RemServer *remserver = pData;
|
|
Remob *remob;
|
|
|
|
assert(remserver);
|
|
assert(fil);
|
|
|
|
for (remob = remserver->objList; remob != NULL; remob = remob->next) {
|
|
if (remob->pDrivInt) {
|
|
fprintf(fil, "catch { remob drv %s %s }\n", remob->name,
|
|
remserver->name);
|
|
} else {
|
|
fprintf(fil, "catch { remob obj %s %s }\n", remob->name,
|
|
remserver->name);
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
static int RemobStatus(void *pData, SConnection * pCon)
|
|
{
|
|
Remob *remob = pData;
|
|
|
|
assert(remob);
|
|
|
|
if (remob->server->conn != NULL) {
|
|
SCDeleteConnection(remob->server->conn);
|
|
}
|
|
remob->server->conn = SCCopyConnection(pCon);
|
|
return remob->status;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
static long RemobRun(void *self, SConnection * pCon, float fNew)
|
|
{
|
|
Remob *remob = self;
|
|
float fHard;
|
|
int i, iRet, iCode;
|
|
char buf[512], sBuf[64];
|
|
char pError[132];
|
|
Remob *p;
|
|
RemServer *remserver;
|
|
long lTime;
|
|
float fDelta;
|
|
int rights;
|
|
RemChannel *rc;
|
|
int nChan;
|
|
|
|
assert(remob);
|
|
assert(pCon);
|
|
|
|
remserver = remob->server;
|
|
if (remserver->conn != NULL) {
|
|
SCDeleteConnection(remserver->conn);
|
|
}
|
|
remserver->conn = SCCopyConnection(pCon);
|
|
|
|
rights = SCGetRights(pCon);
|
|
nChan = rights <= usUser;
|
|
rc = &remserver->rc[nChan];
|
|
RemConnect(remserver, 0); /* connect spy for listexe interest */
|
|
|
|
remob->status = HWIdle;
|
|
snprintf(buf, sizeof(buf), "run %s %g", remob->name, fNew);
|
|
iRet =
|
|
RemTransact(remserver, nChan, pCon, buf, "!ERROR: somebody else",
|
|
"!ERROR: cannot", ">", NULL);
|
|
if (iRet <= 0)
|
|
return 0;
|
|
|
|
if (remserver->matchMap & 1) { /* already running, stop first */
|
|
remob->status = HWBusy;
|
|
snprintf(sBuf, sizeof(sBuf), "stopexe %s", remob->name);
|
|
iRet = RemTransact(remserver, nChan, pCon, sBuf, ">", NULL);
|
|
if (iRet <= 0)
|
|
return 0;
|
|
while (remob->status == HWBusy) {
|
|
iRet = RemRead(rc, 1000);
|
|
if (iRet <= 0)
|
|
break;
|
|
if (!RemHandle(remserver)) {
|
|
RemCopy(rc, pCon);
|
|
}
|
|
}
|
|
iRet = RemTransact(remserver, nChan, pCon, buf, ">", NULL);
|
|
if (iRet <= 0)
|
|
return 0;
|
|
}
|
|
/* wait for "started" message */
|
|
while (remob->status != HWBusy) {
|
|
iRet = RemRead(&remserver->rc[0], 1000);
|
|
if (iRet <= 0)
|
|
break;
|
|
if (!RemHandle(remserver)) {
|
|
RemCopy(&remserver->rc[0], pCon);
|
|
}
|
|
}
|
|
if (remob->status != HWBusy) {
|
|
return 0;
|
|
}
|
|
return OKOK;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
static void KillInfo(void *pData)
|
|
{
|
|
RemobInfo *self = pData;
|
|
|
|
assert(self);
|
|
if (self->pName) {
|
|
free(self->pName);
|
|
}
|
|
if (self->pCon) {
|
|
SCDeleteConnection(self->pCon);
|
|
}
|
|
free(self);
|
|
}
|
|
|
|
/*------------------- The CallBack function for interest ------------------*/
|
|
static int InterestCallback(int iEvent, void *pEvent, void *pUser)
|
|
{
|
|
RemobCallback *psCall = pEvent;
|
|
RemobInfo *pInfo = pUser;
|
|
char buf[80];
|
|
|
|
assert(psCall);
|
|
assert(pInfo);
|
|
|
|
snprintf(buf, sizeof(buf), "%s.position = %g ", pInfo->pName,
|
|
psCall->fVal);
|
|
SCWrite(pInfo->pCon, buf, eEvent);
|
|
return 1;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
int RemobAction(SConnection * pCon, SicsInterp * pSics, void *pData,
|
|
int argc, char *argv[])
|
|
{
|
|
Remob *remob = pData;
|
|
RemServer *remserver = remob->server;
|
|
char buf[512];
|
|
TokenList *pList = NULL;
|
|
TokenList *pCurrent;
|
|
TokenList *pName;
|
|
int iRet;
|
|
int i;
|
|
int pos;
|
|
float fValue;
|
|
long lID;
|
|
char *endp;
|
|
char *cmd;
|
|
/*
|
|
char acce[128], inte[128];
|
|
*/
|
|
int rights;
|
|
int nChan;
|
|
RemChannel *rc;
|
|
|
|
assert(pCon);
|
|
assert(pSics);
|
|
assert(remob);
|
|
|
|
rights = SCGetRights(pCon);
|
|
nChan = (rights <= usUser);
|
|
rc = &remserver->rc[nChan];
|
|
if (rights >= usUser) {
|
|
if (remserver->conn != NULL) {
|
|
SCDeleteConnection(remserver->conn);
|
|
}
|
|
remserver->conn = SCCopyConnection(pCon);
|
|
}
|
|
if (argc == 1) {
|
|
/* filter out time stamps !=== */
|
|
iRet = RemTransact(remserver, nChan, pCon, remob->name, "!===", ">", NULL);
|
|
if (iRet < 0) {
|
|
iRet = 0;
|
|
} else {
|
|
iRet = 1;
|
|
}
|
|
} else if (strcasecmp(argv[1], "interest") == 0) {
|
|
/* ignore interest commands, as they would not work properly */
|
|
iRet = 1;
|
|
} else if (strcasecmp(argv[1], "list") == 0) {
|
|
/*
|
|
snprintf(acce, sizeof(acce), "!%s.accesscode", remob->name);
|
|
snprintf(inte, sizeof(inte), "!%s.interruptmode", remob->name);
|
|
*/
|
|
|
|
cmd = Arg2Tcl0(argc - 1, argv + 1, buf, sizeof buf, remob->name);
|
|
if (cmd) {
|
|
/* filter out time stamps !=== */
|
|
RemTransact(remserver, nChan, pCon, cmd, "!===", ">", NULL);
|
|
if (cmd != buf)
|
|
free(cmd);
|
|
}
|
|
iRet = 1;
|
|
} else {
|
|
pos = snprintf(buf, sizeof(buf), "%s ", remob->name);
|
|
for (i = 1; i < argc; i++) {
|
|
pos += snprintf(buf + pos, sizeof(buf) - pos, "%s ", argv[i]);
|
|
}
|
|
iRet = RemTransact(remserver, nChan, pCon, buf, ">", NULL);
|
|
}
|
|
return iRet;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static void RemobKill(void *self)
|
|
{
|
|
Remob *remob = self;
|
|
Remob *p, **last;
|
|
|
|
assert(remob);
|
|
|
|
/* remove from object list */
|
|
if (remob->server) {
|
|
last = &remob->server->objList;
|
|
p = *last;
|
|
while (p != remob && p != NULL) {
|
|
last = &p->next;
|
|
p = p->next;
|
|
}
|
|
if (p != NULL) {
|
|
*last = p->next;
|
|
}
|
|
remob->next = NULL;
|
|
}
|
|
if (remob->name) {
|
|
free(remob->name);
|
|
}
|
|
if (remob->pDrivInt) {
|
|
free(remob->pDrivInt);
|
|
}
|
|
if (remob->pCall) {
|
|
DeleteCallBackInterface(remob->pCall);
|
|
}
|
|
|
|
/* kill Descriptor */
|
|
if (remob->desc) {
|
|
DeleteDescriptor(remob->desc);
|
|
}
|
|
free(remob);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
int RemServerAction(SConnection * pCon, SicsInterp * pSics, void *pData,
|
|
int argc, char *argv[])
|
|
{
|
|
RemServer *remserver = pData;
|
|
TokenList *pList = NULL;
|
|
TokenList *pCurrent;
|
|
TokenList *pName;
|
|
int iRet;
|
|
socklen_t i;
|
|
int pos;
|
|
float fValue;
|
|
long lID;
|
|
char *endp, *serverport, *thishostname;
|
|
struct sockaddr_in adr;
|
|
struct hostent *thishost;
|
|
Remob *p, *next;
|
|
int rights, nChan;
|
|
RemChannel *rc;
|
|
char *args;
|
|
|
|
assert(pCon);
|
|
assert(pSics);
|
|
assert(remserver);
|
|
|
|
rights = SCGetRights(pCon);
|
|
nChan = (rights <= usUser);
|
|
rc = &remserver->rc[nChan];
|
|
if (nChan) {
|
|
if (remserver->conn != NULL) {
|
|
SCDeleteConnection(remserver->conn);
|
|
}
|
|
remserver->conn = SCCopyConnection(pCon);
|
|
}
|
|
if (argc == 1) {
|
|
serverport = IFindOption(pSICSOptions, "ServerPort");
|
|
i = sizeof adr;
|
|
thishostname = NULL;
|
|
if (rc->chan) {
|
|
if (getsockname(rc->chan->sockid, (void *) &adr, &i) >= 0) {
|
|
thishost = gethostbyaddr((char *) &adr.sin_addr,
|
|
sizeof adr.sin_addr, AF_INET);
|
|
if (thishost) {
|
|
thishostname = thishost->h_name;
|
|
}
|
|
}
|
|
}
|
|
if (thishostname == NULL)
|
|
thishostname = "undef";
|
|
SCPrintf(pCon, eValue, "%s = %s:%d %s:%s",
|
|
argv[0], remserver->host, remserver->port, thishostname,
|
|
serverport);
|
|
} else if (argc > 2 && strcasecmp(argv[1], "nowait") == 0) {
|
|
RemConnect(remserver, nChan);
|
|
args = Arg2Tcl(argc - 2, argv + 2, NULL, 0);
|
|
RemWrite(rc, args);
|
|
RemWrite(rc, "\n");
|
|
free(args);
|
|
} else if (argc == 2 && strcasecmp(argv[1], "markForDel") == 0) {
|
|
p = remserver->objList;
|
|
while (p) {
|
|
p->markForDel = 1;
|
|
p = p->next;
|
|
}
|
|
} else if (argc == 2 && strcasecmp(argv[1], "delMarked") == 0) {
|
|
p = remserver->objList;
|
|
while (p) {
|
|
next = p->next;
|
|
if (p->markForDel) {
|
|
if (p->pDrivInt && pServ->pExecutor
|
|
&& isInRunMode(pServ->pExecutor)) {
|
|
SCWrite(pCon, "ERROR: cannot delete while running", eError);
|
|
return 0;
|
|
}
|
|
RemoveCommand(pSics, p->name);
|
|
}
|
|
p = next;
|
|
}
|
|
} else {
|
|
args = Arg2Tcl(argc - 1, argv + 1, NULL, 0);
|
|
iRet = RemTransact(remserver, nChan, pCon, args, ">", NULL);
|
|
free(args);
|
|
return iRet;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static void RemServerKill(void *self)
|
|
{
|
|
RemServer *remserver = self;
|
|
Remob *remob, *next;
|
|
|
|
assert(remserver);
|
|
|
|
if (remserver->taskActive) {
|
|
remserver->taskActive = 0;
|
|
/* let the tasker kill me */
|
|
return;
|
|
}
|
|
remob = remserver->objList;
|
|
while (remob) {
|
|
next = remob->next;
|
|
RemoveCommand(pServ->pSics, remob->name);
|
|
remob = next;
|
|
}
|
|
RemDisconnect(remserver);
|
|
DeleteDescriptor(remserver->desc);
|
|
if (remserver->name)
|
|
free(remserver->name);
|
|
if (remserver->host)
|
|
free(remserver->host);
|
|
if (remserver->conn != NULL) {
|
|
SCDeleteConnection(remserver->conn);
|
|
}
|
|
free(remserver);
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
static int RemobSetDriveable(Remob * remob, int driveable)
|
|
{
|
|
RemChannel *rc;
|
|
|
|
if (driveable) {
|
|
/* initialise Drivable interface */
|
|
remob->pDrivInt = CreateDrivableInterface();
|
|
if (!remob->pDrivInt)
|
|
return 0;
|
|
remob->pDrivInt->SetValue = RemobRun;
|
|
remob->pDrivInt->CheckLimits = RemobLimits;
|
|
remob->pDrivInt->CheckStatus = RemobStatus;
|
|
remob->pDrivInt->GetValue = RemobGetValue;
|
|
remob->pDrivInt->Halt = RemobHalt;
|
|
if (remob->server->interestActive == 0) {
|
|
rc = &remob->server->rc[0];
|
|
remob->server->interestActive = 1;
|
|
if (!RemSetInterest(rc)) {
|
|
RemDisconnect(remob->server); /* disconnect on error, RemSetInterest will be called again on connect */
|
|
}
|
|
}
|
|
} else if (remob->pDrivInt) {
|
|
free(remob->pDrivInt);
|
|
remob->pDrivInt = NULL;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
static Remob *RemobInit(char *name, RemServer * remserver)
|
|
{
|
|
Remob *remob, *p;
|
|
|
|
assert(name);
|
|
|
|
/* get memory */
|
|
remob = (Remob *) calloc(1, sizeof(Remob));
|
|
if (!remob) {
|
|
return NULL;
|
|
}
|
|
|
|
/* copy arguments */
|
|
remob->server = remserver;
|
|
remob->name = strdup(name);
|
|
|
|
/* initialise object descriptor */
|
|
remob->desc = CreateDescriptor("RemObject");
|
|
if (!remob->desc)
|
|
goto killit;
|
|
remob->desc->GetInterface = RemobGetInterface;
|
|
remob->desc->SaveStatus = RemobSaveStatus;
|
|
|
|
/* initialise callback interface */
|
|
remob->pCall = CreateCallBackInterface();
|
|
if (!remob->pCall)
|
|
goto killit;
|
|
|
|
/* check if not yet in object list */
|
|
for (p = remserver->objList; p != NULL; p = p->next) {
|
|
if (p == remob)
|
|
break;
|
|
}
|
|
if (p == NULL) {
|
|
remob->next = remserver->objList;
|
|
remserver->objList = remob;
|
|
}
|
|
|
|
remob->markForDel = 0;
|
|
/* done */
|
|
return remob;
|
|
killit:
|
|
RemobKill(remob);
|
|
return NULL;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
static RemServer *RemServerInit(char *name, char *host, int port)
|
|
{
|
|
RemServer *remserver = NULL;
|
|
RemChannel *rc;
|
|
int isUser;
|
|
|
|
assert(name);
|
|
|
|
remserver = calloc(1, sizeof(RemServer));
|
|
if (!remserver) {
|
|
return 0;
|
|
}
|
|
|
|
/* initialise object descriptor */
|
|
remserver->desc = CreateDescriptor("RemServer");
|
|
if (!remserver->desc) {
|
|
free(remserver);
|
|
return NULL;
|
|
}
|
|
remserver->desc->SaveStatus = RemServerSaveStatus;
|
|
remserver->name = strdup(name);
|
|
remserver->host = strdup(host);
|
|
remserver->port = port;
|
|
for (isUser = 0; isUser <= 1; isUser++) {
|
|
rc = &remserver->rc[isUser];
|
|
rc->incomplete = 0;
|
|
rc->chan = NULL;
|
|
rc->timeout = 0;
|
|
}
|
|
remserver->objList = NULL;
|
|
remserver->conn = NULL;
|
|
if (!remserver->name || !remserver->host || !remserver->port) {
|
|
/* no success, clean up */
|
|
RemServerKill(remserver);
|
|
return NULL;
|
|
}
|
|
remserver->taskActive = 1;
|
|
remserver->interestActive = 0;
|
|
remserver->forwardMessages = 1;
|
|
TaskRegisterN(pServ->pTasker,name, RemServerTask, NULL, RemServerKill,
|
|
remserver, TASK_PRIO_HIGH);
|
|
return remserver;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------
|
|
The Factory function for creating a remote driveable object.
|
|
|
|
Usage:
|
|
Remob server serverName host:port
|
|
Remob obj remobName serverName
|
|
Remob drv remobName serverName
|
|
Remob del remobName
|
|
Remob del serverName
|
|
*/
|
|
|
|
int RemobCreate(SConnection * pCon, SicsInterp * pSics, void *pData,
|
|
int argc, char *argv[])
|
|
{
|
|
RemServer *remserver = NULL;
|
|
Remob *remob = NULL;
|
|
char host[128];
|
|
char *p;
|
|
int iD, iRet;
|
|
char *obj;
|
|
int argf;
|
|
|
|
assert(pCon);
|
|
assert(pSics);
|
|
|
|
argtolower(argc, argv);
|
|
if (argc >= 4 && strcmp(argv[1], "server") == 0) {
|
|
p = strchr(argv[3], ':');
|
|
if (p) {
|
|
snprintf(host, sizeof host, "%.*s", (int)(p - argv[3]), argv[3]);
|
|
remserver = RemServerInit(argv[2], host, atoi(p + 1));
|
|
argf = 4;
|
|
} else {
|
|
remserver = RemServerInit(argv[2], argv[3], atoi(argv[4]));
|
|
argf = 5;
|
|
}
|
|
if (remserver && argc > argf && strcmp(argv[argf], "0") == 0) {
|
|
remserver->forwardMessages = 0;
|
|
}
|
|
if (!remserver) {
|
|
SCPrintf(pCon, eError,
|
|
"ERROR: Failure to create remote server connection %s",
|
|
argv[2]);
|
|
return 0;
|
|
}
|
|
/* create the interpreter command */
|
|
iRet =
|
|
AddCommand(pSics, argv[2], RemServerAction, RemServerKill,
|
|
remserver);
|
|
if (!iRet) {
|
|
SCPrintf(pCon, eError, "ERROR: duplicate command %s not created",
|
|
argv[2]);
|
|
RemServerKill(remserver);
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
} else if (argc == 4
|
|
&& (strcmp(argv[1], "obj") == 0
|
|
|| strcmp(argv[1], "drv") == 0)) {
|
|
remserver = FindCommandData(pServ->pSics, argv[3], "RemServer");
|
|
if (!remserver) {
|
|
SCPrintf(pCon, eError, "ERROR: remote server %s not found", argv[3]);
|
|
return 0;
|
|
}
|
|
remob = FindCommandData(pServ->pSics, argv[2], "RemObject");
|
|
if (remob) {
|
|
if (remob->server == remserver) {
|
|
RemobSetDriveable(remob, strcmp(argv[1], "drv") == 0);
|
|
remob->markForDel = 0;
|
|
return 1; /* object exists already, silent return */
|
|
}
|
|
}
|
|
remob = RemobInit(argv[2], remserver);
|
|
if (!remob) {
|
|
SCPrintf(pCon, eError, "ERROR: Failure to create remote object %s",
|
|
argv[1]);
|
|
return 0;
|
|
}
|
|
RemobSetDriveable(remob, strcmp(argv[1], "drv") == 0);
|
|
/* create the interpreter command */
|
|
iRet = AddCommand(pSics, argv[2], RemobAction, RemobKill, remob);
|
|
SCparChange(pCon);
|
|
if (!iRet) {
|
|
SCPrintf(pCon, eError, "ERROR: duplicate command %s not created",
|
|
argv[2]);
|
|
RemobKill(remob);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
} else if (argc == 3 && strcmp(argv[1], "del") == 0) {
|
|
remob = FindCommandData(pSics, argv[2], "RemObject");
|
|
if (remob) { /* its a remob */
|
|
if (remob->pDrivInt && pServ->pExecutor
|
|
&& isInRunMode(pServ->pExecutor)) {
|
|
SCPrintf(pCon, eError, "ERROR: cannot delete %s while running",
|
|
argv[2]);
|
|
return 0;
|
|
}
|
|
return RemoveCommand(pSics, argv[2]);
|
|
}
|
|
if (pServ->pExecutor && isInRunMode(pServ->pExecutor)) {
|
|
SCPrintf(pCon, eError, "ERROR: cannot delete %s while running",
|
|
argv[2]);
|
|
return 0;
|
|
}
|
|
remserver = FindCommandData(pSics, argv[2], "RemServer");
|
|
if (remserver) { /* its a remserver */
|
|
return RemoveCommand(pSics, argv[2]);
|
|
}
|
|
SCWrite(pCon, "ERROR: remob object not found", eError);
|
|
return 0;
|
|
}
|
|
SCPrintf(pCon, eError, "ERROR: illegal arguments for command remob");
|
|
return 0;
|
|
}
|