various improvements

- use dig for resolving host names
- ascon.c: fix terminator parsing
- property callback: change property before callback
- logger.c:default for logger period must be the old value instead of 1
- add frappy type history writing
- increase max. logreader line length
- HIPNONE returns "null" with json protocol
- encode strings properly in formatNameValue
- fix memory leak in json2tcl
- scriptcontext: do not show debug messages when script starts with underscore or when the "send" property is empty
- scriptcontext: remove args for action timestamp
- scriptcontext: "que" function will replace an already queued action, e.g. for 'halt
- introduced updatestatus script
This commit is contained in:
2021-09-16 12:26:18 +02:00
parent 8de1fd4183
commit 61341b52f4
24 changed files with 2352 additions and 304 deletions

95
ascon.c
View File

@ -1,8 +1,5 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
@ -13,69 +10,11 @@
#include "splitter.h"
#include "ascon.i"
#include "uselect.h"
#include "socketaddr.h"
static double lastClose = 0; /* time of last close operation */
static AsconProtocol *protocols = NULL;
static int MakeSocketAdr(
struct sockaddr *sockaddrPtr, /* socket address */
char *hostname, /* name or ip of host. NULL implies INADDR_ANY */
int port, /* port number */
char dotted_ip[16]) { /* resolved ip adr */
/*
Workaround for the following case:
switching off and on a LakeShore 336 does acquire a new address,
but the value in the cache (for gethostbyname) is not updated.
node: dig seems to be recommended over nslookup
*/
struct hostent *hostent; /* Host database entry */
struct sockaddr_in *sadr = (struct sockaddr_in *)sockaddrPtr;
FILE *fil;
char line[256];
int l;
(void) memset(sadr, 0, sizeof(*sadr));
if (dotted_ip) { /* default value: failure */
dotted_ip[0] = 0;
}
sadr->sin_family = AF_INET;
sadr->sin_port = htons((unsigned short)port);
if (hostname == NULL) {
/* do not need to copy, as INADDR_ANY is all zero bytes */
return 1;
}
if (inet_pton(AF_INET, hostname, &sadr->sin_addr) == 1) {
/* resolved as dotted numbers notation */
return 1;
}
hostent = gethostbyname(hostname);
if (hostent == 0) {
/* we assume that when gethostname gets no entry, dig will also fail.
That way, dig will not be called repeatedly for no reason */
return 0;
}
/* copy the address: in case dig fails, we use the cached value */
memcpy(&sadr->sin_addr, hostent->h_addr_list[0], 4);
/* we use hostent->h_name instead of hostname here, as this has already
the proper domain added */
snprintf(line, sizeof line, "timeout 1 dig +short %s", hostent->h_name);
fil = popen(line, "r");
if (fil != NULL) {
if (fgets(line, sizeof(line), fil) != NULL) {
l = strlen(line);
if (line[l-1] <= ' ') line[l-1] = 0; /* strip off newline */
/* silently ignore return value, if it fails, we take the cached value */
inet_pton(AF_INET, line, &sadr->sin_addr);
}
fclose(fil);
}
if (dotted_ip) {
inet_ntop(AF_INET, &sadr->sin_addr, dotted_ip, 16);
}
return 1;
}
void AsconError(Ascon *a, char *msg, int errorno)
{
static char *stateText[]={
@ -171,7 +110,7 @@ static void AsconConnect(Ascon * a)
return;
}
*colon = '\0';
ret = MakeSocketAdr(&adr, a->hostport, port, a->ip);
ret = MakeSocketAddr(&adr, a->hostport, port, a->ip);
*colon = ':';
if (ret == 0) {
AsconError(a, "bad host specification", 0);
@ -548,6 +487,22 @@ int AsconStdHandler(Ascon * a)
return AsconBaseHandler(a);
}
static void checkTerminator(char *term) {
int c, l;
if (term == NULL) return;
l = strlen(term);
if (l > 1 && term[0] == '"' && term[l-1] == '"') {
memmove(term, term+1, l-2);
term[l-2] = 0;
}
if (strncmp(term,"0x",2) == 0) {
sscanf(term,"%x",&c);
term[0] = (char)c;
term[1] = '\0';
}
}
/**
* Treat hex strings as terminators right. Note that this
* is limited to single character terminators.
@ -558,18 +513,10 @@ int AsconStdHandler(Ascon * a)
*/
void AsconCheckTerminators(Ascon *a)
{
int c, i, l;
int i, l;
if (a->sendTerminator != NULL && strncmp(a->sendTerminator,"0x",2) == 0) {
sscanf(a->sendTerminator,"%x",&c);
a->sendTerminator[0] = (char)c;
a->sendTerminator[1] = '\0';
}
if (a->replyTerminator != NULL && strncmp(a->replyTerminator,"0x",2) == 0) {
sscanf(a->replyTerminator,"%x",&c);
a->replyTerminator[0] = (char)c;
a->replyTerminator[1] = '\0';
}
checkTerminator(a->sendTerminator);
checkTerminator(a->replyTerminator);
a->compositeTerminator = 0;
if (a->replyTerminator != NULL && a->replyTerminator[0] == '\'') {
l = strlen(a->replyTerminator);

View File

@ -1157,6 +1157,10 @@ void SetHdbProperty(pHdb node, char *key, char *value)
hdbPropertyChange propMes;
if (node != NULL && key != NULL && node->properties != NULL) {
propMes.type = propertyChange;
propMes.key = key;
propMes.value = value;
InvokeCallbackChain(node,(pHdbMessage)&propMes);
if (value == NULL) {
StringDictDelete(node->properties, key);
} else if (StringDictExists(node->properties, key)) {
@ -1164,10 +1168,6 @@ void SetHdbProperty(pHdb node, char *key, char *value)
} else {
StringDictAddPair(node->properties, key, value);
}
propMes.type = propertyChange;
propMes.key = key;
propMes.value = value;
InvokeCallbackChain(node,(pHdbMessage)&propMes);
}
}

View File

@ -49,6 +49,12 @@ Logger *LoggerFind(const char *name)
return NULL;
}
/*--------------------------------------------------------------------------*/
Logger *LoggerList(void)
{
return list;
}
/*--------------------------------------------------------------------------*/
#define LASTLOGTXT "#last logging entry at:\n"
@ -158,8 +164,13 @@ int LoggerWrite0(Logger * log, time_t now, int period, char *value)
strftime(path + l, sizeof path - l, "%m-%d.log", &tm);
strftime(stim, sizeof stim, "#%Y-%m-%d %H:%M:%S", &tm);
if (period <= 0)
period = 1;
if (period <= 0) {
if (log->period > 0) {
period = log->period;
} else {
period = 1;
}
}
writeInfo = (tm.tm_isdst != lasttm.tm_isdst ||
tm.tm_yday != lasttm.tm_yday ||
(period != log->period && log->numeric));
@ -373,7 +384,7 @@ void LoggerKill(Logger * log)
}
/*--------------------------------------------------------------------------*/
static int LoggerMakeDir(char *path)
int LoggerMakeDir(char *path)
{
static char buffer[4096];
struct stat st;
@ -473,6 +484,10 @@ void LoggerFreeAll(void)
free(p->name);
if (p->old)
free(p->old);
if (p->secop_old)
free(p->secop_old);
if (p->secop_id)
free(p->secop_id);
free(p);
p = next;
}

View File

@ -16,12 +16,16 @@ typedef struct Logger {
int numeric;
int period;
int exact;
void *histWriter;
char *secop_old;
char *secop_id;
/* private: */
char *old;
int oldsize;
time_t last, lastWrite, omitTime;
float omitValue;
struct Logger *next;
int category; /* 0: unimportant, 1: important */
} Logger;
@ -39,5 +43,6 @@ void LoggerChange(Logger * log, int period, char *newname);
int LoggerVarPath(char *dir, char *path, int pathLen, char *name,
struct tm *t);
void LoggerFreeAll(void);
int LoggerMakeDir(char *path);
Logger *LoggerList(void);
#endif

View File

@ -10,7 +10,7 @@
#define LOGGER_NAN -999999.
#define ONE_YEAR (366*24*3600)
#define LLEN 1024
#define LLEN 4096
/* max. number of dirs in path */
#define MAX_DIRS 16

View File

@ -1,8 +1,161 @@
#include "logger.h"
#include "logsetup.h"
#include "sics.h"
#include "sicshipadaba.h"
static char *loggerID = "loggerID";
static char *histDir = NULL;
/* static char basepath[1024] = "/"; */
typedef struct _HistWriter {
char *name;
int old_hour;
FILE *fd;
time_t timestamp;
} HistWriter;
HistWriter mainWriter={""};
int FlushTask(void *data) {
HistWriter *wr = data;
if (wr->fd) fflush(wr->fd);
return 1;
}
/*--------------------------------------------------------------------------*/
int HistPath(char *dir, char *path, int pathLen, struct tm *t)
{
int l;
l = strlen(dir);
if (l + 17 >= pathLen) {
path[0] = '\0';
return 0;
}
strcpy(path, dir);
strftime(path + l, pathLen - l, "/%Y/%Y-%m-%d/", t);
l += 17;
path[l] = '\0';
return l;
}
/*--------------------------------------------------------------------------*/
static void HistWriteType(Logger *logger)
{
HistWriter *wr = logger->histWriter;
if (logger->numeric) {
fprintf(wr->fd, "#NUM %s %s\n", logger->secop_id, logger->name);
} else {
fprintf(wr->fd, "#STR %s %s\n", logger->secop_id, logger->name);
}
}
/*--------------------------------------------------------------------------*/
static void HistWrite(Logger *logger, pHdb node, time_t t, char *value)
{
HistWriter *wr = logger->histWriter;
char path[1024];
time_t now;
int l;
struct tm tm, tm0;
FILE *fd;
Logger *lg;
char *secop_id;
time_t current_hour;
int hour_of_day;
int reopen = 0;
secop_id = GetHdbProp(node, "secop_id");
if (!secop_id || !secop_id[0]) {
if (logger->secop_old) {
free(logger->secop_old);
logger->secop_old = NULL;
}
return;
}
if (!logger->secop_id) logger->secop_id = strdup("");
if (strcmp(secop_id, logger->secop_id) != 0) {
free(logger->secop_id);
logger->secop_id = strdup(secop_id);
}
time(&now);
tm = *localtime(&now);
current_hour = now / 3600;
if (current_hour != wr->old_hour) {
if (wr->fd) {
fprintf(wr->fd, "# %ld\n#END\n", (wr->timestamp / 3600 + 1) * 3600);
fclose(wr->fd);
wr->fd = NULL;
}
reopen = 1;
}
if (!wr->fd) {
if (histDir == NULL || reopen) {
histDir = IFindOption(pSICSOptions, "HistoryDir");
if (histDir == NULL) goto failed;
HistPath(histDir, path, sizeof path, &tm);
if (LoggerMakeDir(path) == 0) goto failed;
} else if (!*histDir) {
/* history writing not configured, or failed for current hour */
return;
}
/* last midnight: */
tm.tm_hour = 0;
tm.tm_min = 0;
tm.tm_sec = 0;
tm.tm_isdst = -1;
hour_of_day = (now - mktime(&tm)) / 3600;
l = HistPath(histDir, path, sizeof path, &tm);
strftime(path + l, sizeof path - l, "%Y-%m-%d", &tm);
l += 10;
if (l + 12 >= sizeof path) goto failed;
snprintf(path + l, sizeof path - l, "_%02d_hist.txt", hour_of_day);
fd = fopen(path, "r");
if (!fd) {
wr->fd = fopen(path, "w");
if (!wr->fd) goto failed; /* can not create file */
} else {
fclose(fd);
wr->fd = fopen(path, "a");
if (!wr->fd) goto failed; /* no write access to file */
}
fprintf(wr->fd, "#FRAPPY_HISTORY\n");
if (!wr->old_hour) {
TaskRegisterP(pServ->pTasker, "flush", FlushTask, 0, 0, wr, 0, 0.1, 0.1);
}
wr->old_hour = current_hour;
fprintf(wr->fd, "# %ld\n", t);
wr->timestamp = t;
for (lg = LoggerList(); lg != NULL; lg = lg->next) {
if (lg->secop_old) {
HistWriteType(lg);
fprintf(wr->fd, "%s %s\n", lg->secop_id, lg->secop_old);
}
}
if (logger->secop_old) free(logger->secop_old);
logger->secop_old = NULL;
}
if (logger->secop_old == NULL) {
if (value[0] == '\0') {
return;
}
HistWriteType(logger);
logger->secop_old = strdup("");
}
if (strcmp(logger->secop_old, value) != 0) {
if (t != wr->timestamp) {
fprintf(wr->fd, "# %ld\n", t);
wr->timestamp = t;
}
fprintf(wr->fd, "%s %s\n", secop_id, value);
free(logger->secop_old);
logger->secop_old = strdup(value);
}
return;
failed:
histDir = "";
}
static hdbCallbackReturn LoggerUpdateCallback(pHdb node,
void *userData,
@ -14,7 +167,9 @@ static hdbCallbackReturn LoggerUpdateCallback(pHdb node,
hdbValue value;
pHdbDataMessage mm = NULL;
pHdbDataSearch dsm = NULL;
pHdbMessage killmsg = NULL;
time_t now;
char *strvalue;
if ((dsm = GetHdbDataSearchMessage(message)) != NULL) {
if (dsm->testPtr == loggerID) {
@ -24,6 +179,18 @@ static hdbCallbackReturn LoggerUpdateCallback(pHdb node,
return hdbContinue;
}
if ((killmsg = GetHdbKillNodeMessage(message)) != NULL) {
if (logger->histWriter) {
time(&now);
HistWrite(logger, node, now, "");
if (logger->secop_old) {
free(logger->secop_old);
logger->secop_old = NULL;
}
}
return hdbContinue;
}
if ((mm = GetHdbUpdateMessage(message)) == NULL) {
return hdbContinue;
}
@ -31,66 +198,43 @@ static hdbCallbackReturn LoggerUpdateCallback(pHdb node,
value = *(mm->v);
time(&now);
if (GetHdbProp(node, "geterror") == NULL) {
str = formatValue(value, node);
strvalue = GetCharArray(str);
} else {
str = NULL;
strvalue = "";
}
/* testwise >= */
if (now >= LoggerLastTime(logger)) { /* never write more than once per second */
if (GetHdbProp(node, "geterror") == NULL) {
str = formatValue(value, node);
LoggerWrite(logger, time(NULL), LoggerPeriod(logger), GetCharArray(str));
DeleteDynString(str);
} else {
LoggerWrite(logger, time(NULL), LoggerPeriod(logger), "");
}
LoggerWrite(logger, now, LoggerPeriod(logger), strvalue);
}
if (logger->histWriter) {
HistWrite(logger, node, now, strvalue);
}
if (str) {
DeleteDynString(str);
}
return hdbContinue;
}
static int LogSetup(SConnection * pCon, SicsInterp * pSics, void *pData,
int argc, char *argv[])
{
pHdb node;
pHdbCallback cb;
static char basepath[1024] = "/";
int LogMakeInternal(pHdb node, char *path, int period) {
char buf[1024];
char *p, *name;
static char *loggerDir = NULL;
int numeric, period;
char secop_id[1024];
char secop_par[1024];
char *module;
int pos, l;
pHdb nd;
int numeric;
Logger *logger;
char *p, *name;
pHdbCallback cb;
if (argc < 2) {
SCPrintf(pCon, eError,
"ERROR: should be: logsetup <node> [<period> [<filename>]]");
/* or logsetup <node> clear */
return 0;
}
if (strcasecmp(argv[1], "basepath") == 0) {
if (argc > 2) {
snprintf(basepath, sizeof basepath, "%s", argv[2]);
}
SCPrintf(pCon, eValue, "%s", basepath);
return 1;
}
if (loggerDir == NULL) {
loggerDir = IFindOption(pSICSOptions, "LoggerDir");
if (loggerDir == NULL)
loggerDir = "./";
LoggerSetDir(loggerDir);
}
if (strcasecmp(argv[1], "directory") == 0) {
if (argc > 2) {
loggerDir = strdup(argv[2]);
}
SCPrintf(pCon, eValue, "%s", loggerDir);
return 1;
}
node = FindHdbNode(basepath, argv[1], pCon);
if (node == NULL) {
SCPrintf(pCon, eError, "ERROR: %s not found", argv[1]);
return 0;
}
if (argc > 3) {
snprintf(buf, sizeof buf, "%s", argv[3]);
if (strncmp(path, "/sics/", 6) == 0) {
snprintf(buf, sizeof buf, "%s", path+5);
} else {
snprintf(buf, sizeof buf, "%s", argv[1]);
snprintf(buf, sizeof buf, "%s", path);
}
for (p = buf; *p != '\0'; p++) {
if (*p == '/')
@ -101,29 +245,22 @@ static int LogSetup(SConnection * pCon, SicsInterp * pSics, void *pData,
} else {
name = buf;
}
if (node->value.dataType == HIPFLOAT) {
if (node->value.dataType == HIPFLOAT || node->value.dataType == HIPINT) {
numeric = 1;
} else {
numeric = 0;
}
logger = FindHdbCallbackData(node, loggerID);
period = 0;
if (argc > 2) {
if (logger != NULL && strcasecmp(argv[2], "clear") == 0) {
LoggerWrite(logger, time(NULL), LoggerPeriod(logger), "");
return 1;
}
period = atoi(argv[2]);
}
if (logger != 0) { /* logger exists already */
LoggerChange(logger, period, name);
} else {
logger = LoggerMake(name, period, !numeric);
/* If that failed, we cannot continue - it crashes in the callback */
if (logger == NULL) {
SCPrintf(pCon, eError, "ERROR: logger %s not created", argv[1]);
return 0;
}
logger->histWriter = &mainWriter;
LoggerSetNumeric(logger, numeric);
SetHdbProperty(node, "logger_name", name);
cb = MakeHipadabaCallback(LoggerUpdateCallback, logger,
@ -131,7 +268,70 @@ static int LogSetup(SConnection * pCon, SicsInterp * pSics, void *pData,
assert(cb);
AppendHipadabaCallback(node, cb);
}
return 1;
}
static int LogSetup(SConnection * pCon, SicsInterp * pSics, void *pData,
int argc, char *argv[])
{
pHdb node;
static char *loggerDir = NULL;
int period;
Logger *logger;
char *p;
pDynString result;
time_t now;
if (argc < 2 || argc > 3) {
SCPrintf(pCon, eError,
"ERROR: should be: logsetup <node> [<period>]");
/* or logsetup <node> clear */
return 0;
}
/* seems not used
if (strcasecmp(argv[1], "basepath") == 0) {
if (argc > 2) {
snprintf(basepath, sizeof basepath, "%s", argv[2]);
}
SCPrintf(pCon, eValue, "%s", basepath);
return 1;
}
*/
if (loggerDir == NULL) {
loggerDir = IFindOption(pSICSOptions, "LoggerDir");
if (loggerDir == NULL)
loggerDir = "./";
LoggerSetDir(loggerDir);
}
if (strcasecmp(argv[1], "directory") == 0) {
/* not used ? M.Z. 10.2020 */
if (argc > 2) {
loggerDir = strdup(argv[2]);
}
SCPrintf(pCon, eValue, "%s", loggerDir);
return 1;
}
node = FindHdbIntern(argv[1]);
if (node == NULL) {
SCPrintf(pCon, eError, "ERROR: %s not found", argv[1]);
return 0;
}
period = 0; /* default period */
if (argc > 2 && argv[2][0]) {
if (strcasecmp(argv[2], "clear") == 0) {
logger = FindHdbCallbackData(node, loggerID);
time(&now);
if (logger) { /* silently ignore clear on a missing logger */
LoggerWrite(logger, now, LoggerPeriod(logger), "");
HistWrite(logger, node, now, "");
}
return 1;
}
period = atoi(argv[2]);
}
if (!LogMakeInternal(node, argv[1], period)) {
SCPrintf(pCon, eError, "ERROR: logger %s not created", argv[1]);
}
return 1;
}

14
logsetup.h Normal file
View File

@ -0,0 +1,14 @@
/*---------------------------------------------------------------------------
logsetup.h
Markus Zolliker, Oct 2020
----------------------------------------------------------------------------
*/
#ifndef LOGSETUP_H
#define LOGSETUP_H
#include "hipadaba.h"
int LogMakeInternal(pHdb node, char *path, int period);
#endif

View File

@ -8,53 +8,61 @@
#EPICSOBJ=epicsmotor.o
EPICSOBJ=
COBJ = Sclient.o network.o ifile.o intcli.o $(FORTIFYOBJ)
SOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.o \
sicvar.o nserver.o SICSmain.o motorlist.o\
COREOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.o \
sicvar.o nserver.o SICSmain.o motorlist.o\
sicsexit.o costa.o task.o $(FORTIFYOBJ) testprot.o\
macro.o ofac.o obpar.o obdes.o drive.o status.o intserv.o \
macro.o obpar.o obdes.o drive.o status.o intserv.o \
devexec.o mumo.o mumoconf.o selector.o selvar.o fupa.o lld.o \
lld_blob.o strrepl.o lin2ang.o fomerge.o loglisten.o \
lld_blob.o strrepl.o lin2ang.o loglisten.o \
script.o o2t.o alias.o stringdict.o sdynar.o \
histmem.o histdriv.o histsim.o interface.o callback.o \
interface.o callback.o socketaddr.o \
event.o emon.o evcontroller.o evdriver.o simev.o perfmon.o \
danu.o nxdict.o varlog.o stptok.o nread.o trigd.o cell.o\
scan.o fitcenter.o telnet.o token.o wwildcard.o hklmot.o\
tclev.o hkl.o integrate.o optimise.o dynstring.o nxutil.o \
danu.o varlog.o stptok.o nread.o trigd.o \
scan.o fitcenter.o telnet.o token.o wwildcard.o \
tclev.o integrate.o optimise.o dynstring.o \
uubuffer.o udpquieck.o fourtable.o hexString.o\
rmtrail.o help.o nxupdate.o confvirtualmot.o vector.o\
simchop.o choco.o chadapter.o trim.o scaldate.o tasub.o\
xytable.o exebuf.o exeman.o ubfour.o ubcalc.o\
circular.o maximize.o sicscron.o scanvar.o tasublib.o\
rmtrail.o help.o confvirtualmot.o \
simchop.o choco.o chadapter.o trim.o scaldate.o \
xytable.o exebuf.o exeman.o \
circular.o maximize.o sicscron.o scanvar.o \
d_sign.o d_mod.o tcldrivable.o stdscan.o diffscan.o \
synchronize.o definealias.o oscillate.o tasdrive.o \
hmcontrol.o userscan.o rs232controller.o lomax.o tasscanub.o \
fourlib.o motreg.o motreglist.o anticollider.o nxdataset.o \
s_rnge.o sig_die.o gpibcontroller.o $(NIOBJ) mcreader.o mccontrol.o\
hmdata.o nxscript.o tclintimpl.o sicsdata.o mcstascounter.o \
mcstashm.o initializer.o remob.o tclmotdriv.o protocol.o \
sicslist.o cone.o hipadaba.o sicshipadaba.o statistics.o \
synchronize.o definealias.o oscillate.o \
userscan.o rs232controller.o \
motreg.o motreglist.o anticollider.o \
s_rnge.o sig_die.o gpibcontroller.o $(NIOBJ) \
tclintimpl.o sicsdata.o \
initializer.o remob.o tclmotdriv.o protocol.o \
sicslist.o hipadaba.o sicshipadaba.o statistics.o \
ascon.o scriptcontext.o logger.o logreader.o logsetup.o \
savehdb.o statusfile.o sicshdbfactory.o proxy.o devser.o \
moregress.o multicounter.o regresscter.o histregress.o \
sicshdbadapter.o polldriv.o sicspoll.o statemon.o hmslave.o \
nwatch.o asyncqueue.o asyncprotocol.o sicsobj.o frame.o syncedprot.o\
nxcopy.o nxinterhelper.o nxinter_wrap.o arrayutil.o \
sctdriveadapter.o sctdriveobj.o reflist.o singlex.o fourmess.o \
sgclib.o sgfind.o sgio.o sgsi.o sghkl.o singlediff.o singlebi.o \
singlenb.o simindex.o simidx.o uselect.o singletas.o motorsec.o \
moregress.o multicounter.o regresscter.o \
sicshdbadapter.o polldriv.o sicspoll.o statemon.o \
nwatch.o asyncqueue.o asyncprotocol.o sicsobj.o syncedprot.o\
arrayutil.o \
sctdriveadapter.o sctdriveobj.o reflist.o uselect.o motorsec.o \
rwpuffer.o asynnet.o background.o countersec.o hdbtable.o velosec.o \
histmemsec.o sansbc.o sicsutil.o strlutil.o genbinprot.o trace.o\
singlebinb.o taskobj.o sctcomtask.o tasmono.o multicountersec.o\
lscprot.o secopprot.o\
sicsutil.o strlutil.o genbinprot.o trace.o\
taskobj.o sctcomtask.o multicountersec.o\
lscprot.o secopprot.o secopprot3.o\
messagepipe.o sicsget.o remoteobject.o pmacprot.o charbychar.o binprot.o \
cnvrt.o tclClock.o tclDate.o tclUnixTime.o stack_trace.o logv2.o outcode.o
cnvrt.o tclClock.o tclDate.o tclUnixTime.o stack_trace.o logv2.o outcode.o
MOTOROBJ = motor.o simdriv.o
COUNTEROBJ = countdriv.o simcter.o counter.o
VELOOBJ = velo.o velosim.o
OBJ = $(SOBJ) $(MOTOROBJ) $(COUNTEROBJ) $(VELOOBJ) $(DIFIL) $(EXTRA) $(EPICSOBJ)
SICSOBJ = ofac.o fomerge.o \
histmem.o histdriv.o histsim.o histregress.o hmslave.o fourmess.o histmemsec.o \
hmcontrol.o fourlib.o lomax.o hmdata.o frame.o singlebinb.o sansbc.o \
cell.o vector.o hklmot.o hkl.o ubfour.o ubcalc.o cone.o \
singlex.o sgclib.o sgfind.o sgio.o sgsi.o sghkl.o singlediff.o singlebi.o \
singlenb.o simindex.o simidx.o singletas.o \
tasdrive.o tasscanub.o tasub.o tasublib.o tasmono.o \
nxupdate.o nxdict.o nxutil.o nxdataset.o nxscript.o nxcopy.o nxinterhelper.o nxinter_wrap.o \
mcreader.o mccontrol.o mcstascounter.o mcstashm.o \
$(COREOBJ) $(MOTOROBJ) $(COUNTEROBJ) $(VELOOBJ) $(DIFIL) $(EXTRA) $(EPICSOBJ)
SEAOBJ = sea_ofac.o sea_extra.o $(COREOBJ) $(EXTRA) $(MOTOROBJ) $(COUNTEROBJ) $(VELOOBJ)
.SUFFIXES:
.SUFFIXES: .tcl .htm .c .o .tc
@ -62,16 +70,24 @@ OBJ = $(SOBJ) $(MOTOROBJ) $(COUNTEROBJ) $(VELOOBJ) $(DIFIL) $(EXTRA) $(EPICSOBJ)
.tc.c:
tjxp $*.tc $*.c
all: seaserver
#all: sicserver
seaserver: libseapsi SeaServer
sicserver: libpsi libhlib libmat SICServer
#--- This .SECONDARY. target is necessary to preserve generated .c files for debugging
.SECONDARY.: sicspoll.c polldriv.c
all: libmat libhlib libpsi SICServer
# use this target when some of the libraries SUBLIBS might be incomplete
full: purge all
SICServer: $(OBJ) $(SUBLIBS)
$(CC) $(DBG) -o SICServer $(OBJ) $(LIBS)
SICServer: libmat libhlib libpsi $(SICSOBJ) $(SUBLIBS)
$(CC) $(DBG) -o SICServer $(SICSOBJ) $(LIBS)
SeaServer: libseapsi $(SEAOBJ) $(SEASUBLIBS)
$(CC) $(DBG) -o SeaServer $(SEAOBJ) $(SEALIBS)
matrix/libmatrix.a: libmat
@ -88,6 +104,9 @@ $(SICSROOT)/sicspsi/libpsi.a: libpsi
libpsi:
cd $(SICSROOT)/sicspsi; make $(MFLAGS) libpsi.a
libseapsi:
cd $(SICSROOT)/sicspsi; make $(MFLAGS) libseapsi.a
purge:
rm -f SICServer $(SUBLIBS)

View File

@ -34,6 +34,11 @@ LIBS = -L$(EXTRAROOT)/lib -L$(EXTRAROOT)/lib $(SUBLIBS) $(NILIB) $(EPICSLIBS)
-ltcl -lNeXus /usr/lib64/libhdf5.so \
$(EXTRAROOT)/lib/libjson-c.a \
-ldl -lz -lmxml $(EXTRAROOT)/lib/libghttp.a -lm -lc -lpthread -lsqlite3 -lbson-1.0 -lmongoc-1.0
SEASUBLIBS = $(SICSROOT)/sicspsi/libseapsi.a
SEALIBS = -L$(EXTRAROOT)/lib -L$(EXTRAROOT)/lib $(SEASUBLIBS) \
-ltcl \
$(EXTRAROOT)/lib/libjson-c.a \
-ldl -lz -lm -lc -lpthread
include make_gen

View File

@ -53,6 +53,7 @@
#include <fcntl.h>
#include "sics.h"
#include "uselect.h"
#include "socketaddr.h"
#define PORT 1
#define SOCKET 2
@ -78,43 +79,6 @@ static void NetError(const char pText[])
Log(severity,"io","%s", pText);
}
/* ---------------------------- Local ------------------------------------
CreateSocketAdress stolen from Tcl. Thanks to John Ousterhout
*/
static int CreateSocketAdress(struct sockaddr_in *sockaddrPtr, /* Socket address */
char *host, /* Host. NULL implies INADDR_ANY */
int port)
{ /* Port number */
struct hostent *hostent; /* Host database entry */
struct in_addr addr; /* For 64/32 bit madness */
(void) memset((char *) sockaddrPtr, '\0', sizeof(struct sockaddr_in));
sockaddrPtr->sin_family = AF_INET;
sockaddrPtr->sin_port = htons((unsigned short) (port & 0xFFFF));
if (host == NULL) {
addr.s_addr = INADDR_ANY;
} else {
hostent = gethostbyname(host);
if (hostent != NULL) {
memcpy((char *) &addr,
(char *) hostent->h_addr_list[0], (size_t) hostent->h_length);
} else {
addr.s_addr = inet_addr(host);
if (addr.s_addr == (unsigned int) -1) {
return 0; /* error */
}
}
}
/*
* There is a rumor that this assignment may require care on
* some 64 bit machines.
*/
sockaddrPtr->sin_addr.s_addr = addr.s_addr;
return 1;
}
/*-------------------------------------------------------------------------*/
mkChannel *NETOpenPort(int iPort)

1
ofac.c
View File

@ -53,6 +53,7 @@ static void InitGeneral(void)
INIT(AddCharByCharProtocoll);
INIT(AddLscProtocol);
INIT(AddSecopProtocol);
INIT(AddSecop3Protocol);
INIT(MakeTrace);
INIT(InitTaskOBJ);
INIT(RemoteObjectInit);

View File

@ -469,10 +469,11 @@ struct json_object *mkJSON_Object(SConnection * pCon, char *pBuffer,
char pError[256];
pError[0] = '\0';
/*
if (strlen(pBuffer) == 0) {
return 0;
}
*/
if (!SCVerifyConnection(pCon)) {
return 0;
@ -518,9 +519,14 @@ struct json_object *mkJSON_Object(SConnection * pCon, char *pBuffer,
}
if (iOut == eHdbValue || iOut == eHdbEvent) {
tmp_json = json_tokener_parse(pBuffer);
if (tmp_json == NULL) {
linenum = __LINE__;
goto reporterr;
if (strcmp(pBuffer, "null") != 0) {
if (tmp_json == NULL) {
tmp_json = json_object_new_string(pBuffer);
}
if (tmp_json == NULL) {
linenum = __LINE__;
goto reporterr;
}
}
} else {
/* Strip \r and \n */
@ -561,9 +567,11 @@ int SCWriteJSON_String(SConnection * pCon, char *pBuffer, int iOut)
char pBueffel[MAXMSG], errBuff[MAXMSG];
int iRet, errLen = MAXMSG;
/*
if (strlen(pBuffer) == 0)
return 1;
*/
/* log it for any case */
iRet = SCGetSockHandle(pCon);

View File

@ -43,6 +43,7 @@
#include <assert.h>
#include <ctype.h>
#include <math.h>
#include <time.h>
#include "fortify.h"
#include "sics.h"
#include "fupa.h"
@ -583,7 +584,7 @@ Tcl_Obj *json2tcl(struct json_object *jobj) {
char buf[100];
int i, len;
Tcl_Obj **list;
Tcl_Obj *dict, *kobj, *vobj;
Tcl_Obj *result, *kobj, *vobj;
Tcl_Obj *val;
const char *key;
const char *str;
@ -605,18 +606,20 @@ Tcl_Obj *json2tcl(struct json_object *jobj) {
list[i] = json2tcl(json_object_array_get_idx(jobj, i));
if (!list[i]) return NULL;
}
return Tcl_NewListObj(len, list);
result = Tcl_NewListObj(len, list);
free(list);
return result;
case json_type_object:
dict = Tcl_NewDictObj();
if (!dict) return NULL;
result = Tcl_NewDictObj();
if (!result) return NULL;
json_object_object_foreach(jobj, key, val) {
kobj = Tcl_NewStringObj(key, strlen(key));
vobj = json2tcl(val);
if (kobj && vobj) {
Tcl_DictObjPut(NULL, dict, kobj, vobj);
Tcl_DictObjPut(NULL, result, kobj, vobj);
}
}
return dict;
return result;
}
return Tcl_NewStringObj("None", 4);
}

View File

@ -344,14 +344,16 @@ int SctCallInContext(SConnection * con, char *script, Hdb * node,
char path[MAX_HDB_PATH];
PushContext(node, controller);
if (controller->debugConn) {
GetHdbPath(node, path, sizeof path);
SCPf(SCPureSockWrite, controller->debugConn, eLog,
"%6.3f script: (on %s) %s", secondsOfMinute(), path, script);
}
if (controller->fd != NULL) {
GetHdbPath(node, path, sizeof path);
fprintf(controller->fd,"%6.3f script: (on %s) %s\n", secondsOfMinute(), path, script);
if (script[strlen(script)-1] != '_') { /* suppress these debug messages */
if (controller->debugConn) {
GetHdbPath(node, path, sizeof path);
SCPf(SCPureSockWrite, controller->debugConn, eLog,
"%6.3f script: (on %s) %s", secondsOfMinute(), path, script);
}
if (controller->fd != NULL) {
GetHdbPath(node, path, sizeof path);
fprintf(controller->fd,"%6.3f script: (on %s) %s\n", secondsOfMinute(), path, script);
}
}
MacroPush(con);
@ -366,12 +368,18 @@ int SctCallInContext(SConnection * con, char *script, Hdb * node,
result++;
}
}
if (controller->debugConn) {
SCPf(SCPureSockWrite, controller->debugConn, eLog,
"%6.3f error: %s", secondsOfMinute(), result);
}
if(controller->fd != NULL){
if (script[strlen(script)-1] != '_') { /* suppress these error messages */
if (controller->debugConn) {
SCPf(SCPureSockWrite, controller->debugConn, eLog,
"%6.3f error: %s", secondsOfMinute(), result);
} else {
/* just return to tcl */
SCPf(SCNotWrite, controller->conn, eLog,
"%6.3f error: %s", secondsOfMinute(), result);
}
if(controller->fd != NULL){
fprintf(controller->fd, "%6.3f error: %s\n", secondsOfMinute(), result);
}
}
iRet = 0;
}
@ -390,6 +398,11 @@ static int SctMatch(void *data1, void *data2)
return a->node == b->node && strcasecmp(a->name, b->name) == 0;
}
static int NoMatch(void *data1, void *data2)
{
return 0;
}
/*
* This routine is running the script chain. It is called repeatedly
* with response data from the device serializer (devser). This function
@ -622,8 +635,16 @@ static char *SctActionHandler(void *actionData, char *lastReply,
data->name, path, emsg);
SetHdbProperty(node, eprop, NULL);
}
snprintf(timeKey, sizeof timeKey, "%s_time", data->name);
blank = strchr(data->name, ' ');
if (blank != NULL) {
l = blank - data->name;
} else {
l = strlen(data->name);
}
/* omit arguments, in case action is a script */
snprintf(timeKey, sizeof timeKey, "%.*s_time", (int)l, data->name);
snprintf(timeVal, sizeof timeVal, "%.3f", DoubleTime());
SetHdbProperty(node, timeKey, timeVal);
send = NULL;
free(script);
@ -644,17 +665,19 @@ static char *SctActionHandler(void *actionData, char *lastReply,
send = GetProp(node, controller->node, "send");
if (send == NULL)
send = "";
if (controller->debugConn) {
SCPf(SCPureSockWrite, controller->debugConn, eLog,
"%6.3f send : %s", secondsOfMinute(), send);
}
if (controller->fd != NULL) {
fprintf(controller->fd, "%6.3f send : %s\n", secondsOfMinute(), send);
}
if(data != NULL && data->controller != NULL){
traceIO(data->controller->node->name, "send:%s", send);
} else {
traceIO("sctunknown", "send:%s", send);
if (*send != '\0') {
if (controller->debugConn) {
SCPf(SCPureSockWrite, controller->debugConn, eLog,
"%6.3f send : %s", secondsOfMinute(), send);
}
if (controller->fd != NULL) {
fprintf(controller->fd, "%6.3f send : %s\n", secondsOfMinute(), send);
}
if(data != NULL && data->controller != NULL){
traceIO(data->controller->node->name, "send:%s", send);
} else {
traceIO("sctunknown", "send:%s", send);
}
}
return send;
}
@ -852,6 +875,7 @@ static hdbCallbackReturn SctActionCallback(Hdb * node, void *userData,
SCPrintf(con, eError, "ERROR: %s", error); /* nicer for the user */
SetHdbProperty(node, "target", NULL);
SetHdbProperty(node, "requested", NULL);
DeleteDynString(text);
return hdbAbort;
}
}
@ -1194,7 +1218,7 @@ static int SctWriteCmd(pSICSOBJ ccmd, SConnection * con,
}
void SctQueueNode(SctController * controller, Hdb * node,
DevPrio prio, char *action, SConnection * con)
DevPrio prio, char *action, int replace, SConnection * con)
{
SctData *data;
hdbCallback *cb;
@ -1215,8 +1239,9 @@ void SctQueueNode(SctController * controller, Hdb * node,
data->syncid = SyncedIncr(0);
data->busy = 1;
if (DevQueue(data->controller->devser, data, prio,
SctWriteHandler, SctMatch, SctKillData, SctDataInfo)) {
if (DevQueue(data->controller->devser, data, prio, SctWriteHandler,
replace ? SctMatch : NoMatch,
SctKillData, SctDataInfo)) {
if (con != NULL) {
data->conCtx = SCCopyConnection(con);
}
@ -1257,7 +1282,8 @@ static int SctQueueCmd(pSICSOBJ ccmd, SConnection * con,
}
action = ParText(cmdNode, "action", nPar, "write");
SctQueueNode(controller, node, prio, action, con);
SctQueueNode(controller, node, prio, action,
strcmp(cmdNode->name, "que") != 0, con);
return 1;
}
@ -1970,13 +1996,18 @@ static int SctMakeController(SConnection * con, SicsInterp * sics,
"write", usMugger, MakeSICSFunc(SctWriteCmd));
AddSICSHdbPar(cmd, "node", usMugger, MakeHdbText(""));
cmd = AddSICSHdbPar(controller->node,
"queue", usMugger, MakeSICSFunc(SctQueueCmd));
AddSICSHdbPar(cmd, "node", usMugger, MakeHdbText(""));
AddSICSHdbPar(cmd, "prio", usMugger, MakeHdbText("write"));
AddSICSHdbPar(cmd, "action", usMugger, MakeHdbText("write"));
cmd = AddSICSHdbPar(controller->node,
"que", usMugger, MakeSICSFunc(SctQueueCmd));
AddSICSHdbPar(cmd, "node", usMugger, MakeHdbText(""));
AddSICSHdbPar(cmd, "prio", usMugger, MakeHdbText("write"));
AddSICSHdbPar(cmd, "action", usMugger, MakeHdbText("write"));
cmd = AddSICSHdbPar(controller->node,
"updatescript", usMugger, MakeSICSFunc(SctUpdatescriptCmd));
AddSICSHdbPar(cmd, "node", usMugger, MakeHdbText(""));

View File

@ -14,10 +14,11 @@ typedef struct SctController SctController;
* \param node the node
* \param prio the priority
* \param action the initial state
* \param replace 0 queue does not replace, 1: entries with the same node and action are replaced
* \param con an optional connection to be used by the action scripts
*/
void SctQueueNode(SctController * controller, Hdb * node,
DevPrio prio, char *action, SConnection * con);
DevPrio prio, char *action, int replace, SConnection * con);
/** \brief call a script and configure the sct command to be used
* in connection with the given node and controller

View File

@ -56,7 +56,7 @@ static int SCTDRIVHalt(void *data)
self = (pSctDrive) data;
if (GetHdbProperty(self->node, "halt", dummy, sizeof dummy)) {
SctQueueNode(self->c, self->node, HaltPRIO, "halt", NULL);
SctQueueNode(self->c, self->node, HaltPRIO, "halt", 1, NULL);
} else if (GetHdbProperty(self->node, "status", dummy, sizeof dummy)) {
SetHdbProperty(self->node, "status", "idle");
}

View File

@ -79,7 +79,7 @@ static int SCTDRIVHalt(void *data)
self = (pSICSOBJ) data;
pPriv = (pDrivObjPriv) self->pPrivate;
if (GetHdbProperty(self->objectNode, "halt", dummy, sizeof dummy)) {
SctQueueNode(pPriv->c, self->objectNode, HaltPRIO, "halt",
SctQueueNode(pPriv->c, self->objectNode, HaltPRIO, "halt", 1,
pPriv->pCon);
} else
if (GetHdbProperty(self->objectNode, "status", dummy, sizeof dummy))
@ -177,7 +177,8 @@ static int SCTDRIVCheckStatus(void *data, SConnection * pCon)
Tcl_Interp *pTcl = NULL;
char *result;
SConnection *con;
int ret;
self = (pSICSOBJ) data;
pPriv = (pDrivObjPriv) self->pPrivate;
@ -186,7 +187,8 @@ static int SCTDRIVCheckStatus(void *data, SConnection * pCon)
*/
if (GetHdbProperty(self->objectNode, "writestatus", script, 1024)) {
if (strcmp(script, "start") == 0) {
return HWBusy;
ret = HWBusy;
goto Return;
}
}
@ -198,7 +200,9 @@ static int SCTDRIVCheckStatus(void *data, SConnection * pCon)
SCWrite(pCon,
"ERROR: configuration problem: no checkstatus script!",
eError);
return HWFault;
ret = HWFault;
result = "error";
goto Return;
}
result = script;
} else {
@ -206,7 +210,9 @@ static int SCTDRIVCheckStatus(void *data, SConnection * pCon)
pPriv->c, &result);
if (status == 0) {
SCPrintf(pCon, eError, " script %s returned %s", script, result);
return HWFault;
ret = HWFault;
result = "error";
goto Return;
}
if (SctDebugConn(pPriv->c)) {
SCPf(SCPureSockWrite, SctDebugConn(pPriv->c), eError,
@ -214,20 +220,28 @@ static int SCTDRIVCheckStatus(void *data, SConnection * pCon)
}
}
if (strstr(result, "run") != NULL) {
return HWBusy;
ret = HWBusy;
} else if (strstr(result, "posfault") != NULL) {
return HWPosFault;
ret = HWPosFault;
} else if (strstr(result, "error") != NULL) {
return HWFault;
ret = HWFault;
} else if (strstr(result, "idle") != NULL) {
return HWIdle;
ret = HWIdle;
} else {
SCPrintf(pCon, eError,
"ERROR: invalid status code %s returned from checkstatus script",
result);
return HWFault;
ret = HWFault;
}
return HWFault;
Return:
if (GetHdbProperty(self->objectNode, "updatestatus", script, 1024)) {
status = SctCallInContext(pCon, script, self->objectNode,
pPriv->c, &result);
if (status == 0) {
SCPrintf(pCon, eError, " %s returned %s", script, result);
}
}
return ret;
}
/*----------------------------------------------------------------

145
sea_extra.c Normal file
View File

@ -0,0 +1,145 @@
/*
* Extracts from other SICS code and dummy definitions for SEA
*
* Markus Zolliker Jun 2020
*/
#include <math.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <site.h>
#include <sicsvar.h>
#include <danu.h>
pCounterDriver NewMcStasCounter(char *name) {
return NULL;
}
float GetHistPreset(pHistMem self) {return 0;};
int SetHistPreset(pHistMem self, float fVal) {return 0;};
CounterMode GetHistCountMode(pHistMem self) {return 0;};
int SetHistCountMode(pHistMem self, CounterMode eNew) {return 0;};
long GetHistMonitor(pHistMem self, int i, SConnection *pCon) {return 0;};
const float *GetHistTimeBin(pHistMem self, int *iLength) {return 0;};
int GetHistLength(pHistMem self) {return 0;};
int GetHistDim(pHistMem self, int iDim[MAXDIM], int *nDim) {return 0;};
float GetHistCountTime(pHistMem self,SConnection *pCon) {return 0;};
int GetHistogram(pHistMem self, SConnection *pCon,
int i,int iStart, int iEnd, HistInt *lData, int iDataLen) {return 0;};
HistInt *GetHistogramPointer(pHistMem self,SConnection *pCon) {return 0;};
int GetHistogramDirect(pHistMem self, SConnection *pCon,
int i, int iStart, int iEnd,
HistInt *lData, int iDataLen) {return 0;};
void HistDirty(pHistMem self) {};
HistInt *subSample(pHMdata self, char *command, char *error, int errLen) {return 0;};
int Nxinter_SafeInit(Tcl_Interp * pTcl) {return 0;};
int NXcopy_Init(Tcl_Interp * pTcl) {return 0;};
int isNXScriptWriting(void) {return 0;};
/* alternative implementation in order to avoid nexus stuff */
void SNXFormatTime(char *result, int size) {
time_t timeStamp;
time(&timeStamp);
strftime(result, size, "%Y-%m-%d %H:%M:%S", localtime(&timeStamp));
}
/* from nxscript.c: */
/*------------------------------------------------------------------------*/
char *makeFilename(SicsInterp * pSics, SConnection * pCon)
{
pSicsVariable pPath = NULL, pPref = NULL, pEnd = NULL;
char *pRes = NULL;
int iLen, iNum, iYear, thousand;
char pNumText[10], pBueffel[256];
CommandList *pCom = NULL;
DIR *dir = NULL;
/* Try, get all the Variables */
pPath = FindVariable(pSics, "sicsdatapath");
pPref = FindVariable(pSics, "sicsdataprefix");
pCom = FindCommand(pSics, "sicsdatanumber");
pEnd = FindVariable(pSics, "sicsdatapostfix");
if ((!pPath) || (!pPref) || (!pCom) || (!pEnd)) {
SCWrite(pCon,
"ERROR: cannot read variables for automatic data file name creation",
eError);
SCWrite(pCon,
"ERROR: This is a VERY, VERY, VERY serious installation problem",
eError);
SCWrite(pCon, "ERROR: your data will be dumped into emergency.hdf",
eError);
return NULL;
}
/* find length */
iLen = strlen(pPath->text) + 4; /* extra 4 for dir number */
iLen += strlen(pPref->text);
iLen += 10; /* for number + year */
iLen += strlen(pEnd->text);
iLen += 10; /* safety margin */
/* allocate memory */
pRes = (char *) malloc(iLen * sizeof(char));
if (!pRes) {
SCWrite(pCon, "ERROR: no memory in makeFilename", eError);
return NULL;
}
memset(pRes, 0, iLen);
/* increment the data file number */
iNum = IncrementDataNumber(pCom->pData, &iYear);
if (iNum < 0) {
SCWrite(pCon, "ERROR: cannot increment data number!", eError);
SCWrite(pCon, "ERROR: your data will be dumped to emergency.hdf",
eError);
free(pRes);
return NULL;
}
strcpy(pRes, pPath->text);
thousand = (int) floor(iNum / 1000.);
snprintf(pNumText, 9, "%3.3d", thousand);
strcat(pRes, pNumText);
/*
check for existence of directory and create if neccessary
*/
dir = opendir(pRes);
if (dir == NULL) {
mkdir(pRes, S_IRWXU | S_IRGRP | S_IXGRP);
snprintf(pBueffel, 255, "Creating dir: %s", pRes);
SCWrite(pCon, pBueffel, eLog);
} else {
closedir(dir);
}
/*
build the rest of the filename
*/
strcat(pRes, "/");
strcat(pRes, pPref->text);
snprintf(pNumText,sizeof(pNumText)-1, "%4.4d", iYear);
strcat(pRes, pNumText);
strcat(pRes, "n");
snprintf(pNumText,sizeof(pNumText)-1, "%6.6d", iNum);
strcat(pRes, pNumText);
strcat(pRes, pEnd->text);
return pRes;
}
/*---------------------------------------------------------------------*/
void changeExtension(char *filename, char *newExtension)
{
char *pPtr = NULL;
pPtr = strrchr(filename, (int) '.');
assert(pPtr != NULL);
pPtr++;
assert(strlen(pPtr) >= strlen(newExtension));
strcpy(pPtr, newExtension);
}

1068
sea_macro.c Normal file

File diff suppressed because it is too large Load Diff

243
sea_ofac.c Normal file
View File

@ -0,0 +1,243 @@
/**
* Startup commands and definitions
*
* copyright: see file COPYRIGHT
*
* Mark Koennecke 1996 - ?
* heavy modifications to separate PSI specific commands into a
* separate library. Mark Koennecke, June 2003
*
* moved some functions to sicsutil.c
* Markus Zolliker Jan 2010
*
* reduced version for SEA only, June 2020
*/
#include "ofac.h"
#include "exeman.h"
#include "statusfile.h"
#include "site.h"
#include "sicshipadaba.h"
#include "sicsglobal.h"
static unsigned int killStartupCommands = 1;
int isDuringInitialization;
extern void DevExecInit(void); /* devexec.c */
/*--------------------------------------------------------------------------*/
static void InitGeneral(void)
{
#define INIT(F) { void F(void); F(); }
/* insert here initialization routines ... */
INIT(StatisticsInit);
INIT(InitializerInit);
INIT(SaveHdbInit); /* must be after InitializerInit */
INIT(DefineAliasInit);
INIT(SctInit);
INIT(SctDriveAdapterInit);
INIT(SctDriveObjInit);
INIT(SctDriveAdapterInit);
INIT(SICSGetInit);
INIT(LogReaderInit);
INIT(LogSetupInit);
INIT(InstallBackground);
INIT(MakeProtocol);
INIT(UdpInit);
INIT(HelpInit);
INIT(AddTestProt);
INIT(AddGenBinProtocoll);
INIT(AddSyncedProt);
INIT(AddBinProtocol);
INIT(AddPMACProtocoll);
INIT(AddCharByCharProtocoll);
INIT(AddLscProtocol);
INIT(AddSecopProtocol);
INIT(AddSecop3Protocol);
INIT(MakeTrace);
INIT(InitTaskOBJ);
INIT(RemoteObjectInit);
INIT(Logv2Init);
INIT(LogListenInit);
INIT(SiteInit); /* site specific initializations */
}
static void InitIniCommands(SicsInterp * pInter)
{
/* declare and add permanent command */
#define PCMD(NAME, FUN) { \
int FUN(SConnection * pCon, SicsInterp * pSics, void *pData, \
int argc, char *argv[]); \
AddCommandWithFlag(pInter, NAME, FUN, NULL, NULL, 0); \
}
/* declare and add startup command */
#define SCMD(NAME, FUN) { \
int FUN(SConnection * pCon, SicsInterp * pSics, void *pData, \
int argc, char *argv[]); \
AddCommandWithFlag(pInter, NAME, FUN, NULL, NULL, 1); \
}
/* permanent commands in alphabetic order */
PCMD("alias", MakeAlias);
PCMD("broadcast", Broadcast);
PCMD("ClientPut", ClientPut);
PCMD("ClientLog", ClientLog);
PCMD("config", ConfigCon);
PCMD("db", SICSDebug);
PCMD("Dir", ListObjects);
PCMD("dolater", MakeCron);
PCMD("DrivableInvoke", TclDrivableInvoke);
PCMD("DynSicsObj", InstallSICSOBJ);
PCMD("EVFactory", EVControlFactory);
PCMD("FileEval", MacroFileEval);
PCMD("findalias", LocateAliasAction);
PCMD("fulltransact", TransactAction);
PCMD("GetInt", GetSICSInterrupt);
PCMD("GumPut", GumPut);
PCMD("InternEval", InternalFileEval);
PCMD("kill_command", SICSKill);
PCMD("list", SicsList);
PCMD("MakeAsyncProtocol", AsyncProtocolFactory);
PCMD("MakeAsyncQueue", AsyncQueueFactory);
PCMD("MakeMulti", MakeMulti);
PCMD("MakeOptimise", MakeOptimiser);
PCMD("MakeSecMotor", SecMotorFactory);
PCMD("Publish", TclPublish);
PCMD("Remob", RemobCreate);
PCMD("ResetServer", ResetStatus);
PCMD("scriptcallback", CallbackScript);
PCMD("SetInt", SetSICSInterrupt);
PCMD("SetStatus", SetSICSStatus);
PCMD("SICSBounds", SICSBounds);
PCMD("sicscron", MakeCron);
PCMD("sicsdatafactory", SICSDataFactory);
PCMD("sicsdescriptor", SICSDescriptor);
PCMD("SICSLog", LogOutput);
PCMD("sicsprompt", SicsPrompt);
PCMD("SICSStatus", SICSStatus);
/* PCMD("sicstime", SICSTime); */
PCMD("doubletime", SICSDoubleTime);
PCMD("SICSType", SICSType);
PCMD("Sics_Exitus", SicsExit);
PCMD("silent", SICSSilent);
PCMD("json2tcl", SICSjson2tcl);
PCMD("status", UserStatus);
PCMD("TclReplaceDrivable", TclReplaceDrivable);
PCMD("transact", TransactAction);
PCMD("wait", UserWait);
PCMD("yield", UserYield);
PCMD("checksum", CheckSum);
PCMD("loguserinfo", LogUserInfoWrapper);
/* startup commands in alphabetic order */
SCMD("allowexec", AllowExec);
SCMD("AntiCollisionInstall", AntiColliderFactory);
SCMD("ChopperAdapter", CHAdapterFactory);
SCMD("MakeBatchManager", MakeExeManager);
SCMD("MakeChopper", ChocoFactory);
SCMD("MakeConfigurableMotor", MakeConfigurableVirtualMotor);
SCMD("MakeCounter", MakeCounter);
SCMD("MakeDataNumber", DNFactory);
SCMD("MakeDiffScan", MakeDiffScan);
SCMD("MakeDrive", MakeDrive);
SCMD("MakeEnergy", MakeEnergyVar);
SCMD("MakeGPIB", MakeGPIB);
SCMD("MakeHdbTable", HdbTableFactory);
SCMD("MakeLin2Ang", MakeLin2Ang);
SCMD("MakeMaximize", MaximizeFactory);
SCMD("MakeMono", MonoInit);
SCMD("MakeMultiCounter", MakeMultiCounter);
SCMD("MakeMultiSec", MakeMultiSec);
SCMD("MakeO2T", CreateO2T);
SCMD("MakeOscillator", MakeOscillator);
SCMD("MakePeakCenter", FitFactory);
SCMD("MakeProxy", ProxyFactory);
SCMD("MakeRefList", MakeReflectionList);
SCMD("MakeRS232Controller", RS232Factory);
SCMD("MakeScanCommand", ScanFactory);
SCMD("MakeSecCounter", MakeSecCter);
SCMD("MakeSicsObj", InstallSICSOBJ);
SCMD("MakeSicsPoll", InstallSICSPoll);
SCMD("MakeStateMon", StateMonFactory);
SCMD("MakeSync", MakeSync);
SCMD("MakeTclInt", MakeTclInt);
SCMD("MakeWaveLength", MakeWaveLengthVar);
SCMD("MakeXYTable", XYFactory);
SCMD("Motor", MotorCreate);
SCMD("ServerOption", IFServerOption);
SCMD("SicsAlias", SicsAlias);
SCMD("SicsUser", PWSicsUser);
SCMD("TokenInit", TokenInit);
SCMD("VarMake", VarFactory);
SCMD("VelocitySelector", VelSelFactory);
}
/*--------------------------------------------------------------------------*/
int InitObjectCommands(pServer pServ, char *file)
{
SConnection *pCon = NULL;
char pBueffel[1024];
int iRet;
SicsInterp *pSics;
pExeList pExe;
pEnvMon pEnv = NULL;
pSite site = NULL;
pSics = pServ->pSics;
assert(pSics);
InitGeneral();
/* general initialization */
/* create a connection */
pCon = SCCreateDummyConnection(pSics);
if (!pCon) {
return 0;
}
MakeExeManager(pCon, pSics, NULL, 1, NULL);
pExe = CreateExeList(pServ->pTasker);
pServ->pExecutor = pExe;
pEnv = CreateEnvMon();
DevExecInit();
assert(pExe);
assert(pEnv);
InitIniCommands(pSics);
/*
install site specific commands
*/
site = getSite();
if (site != NULL) {
site->AddSiteCommands(pServ->pSics);
}
InstallBckRestore(pCon, pSics);
InstallSICSHipadaba(pCon, pSics,NULL,0,NULL);
/* evaluate the file */
snprintf(pBueffel,sizeof(pBueffel)-1, "fileeval %s", file);
iRet = InterpExecute(pSics, pCon, pBueffel);
/* done */
SCDeleteConnection(pCon);
if (site != NULL && site->RemoveSiteCommands != NULL) {
site->RemoveSiteCommands(pSics);
}
if(killStartupCommands){
RemoveStartupCommands();
}
isDuringInitialization = 0;
return 1;
}
/*---------------------------------------------------------------------------------*/
void KeepStartupCommands()
{
killStartupCommands = 0;
}

196
secopprot3.c Normal file
View File

@ -0,0 +1,196 @@
#include <errno.h>
#include <tcl.h>
#include <json-c/json.h>
#include "uselect.h"
#include "ascon.h"
#include "ascon.i"
#include "script.h"
/*
* protocol for SECoP
*
* Markus Zolliker Feb 2019
*/
/* the first item in this linked list contains a partial or empty buffer.
all the following are the messages in the queue */
typedef struct secop_msg {
struct secop_msg *next;
char *message;
} SecopMsg;
typedef struct secop_buf {
SecopMsg *queue;
pDynString buffer;
} SecopBuf;
/*----------------------------------------------------------------------------*/
void SecopKillPrivate(void *private) {
SecopBuf *msgbuf = private;
SecopMsg *msg, *next;
for (msg = msgbuf->queue; msg != NULL; msg = next) {
next = msg->next;
if (msg->message) {
free(msg->message);
}
free(msg);
}
DeleteDynString(msgbuf->buffer);
free(msgbuf);
}
/*----------------------------------------------------------------------------*/
int Secop3ReadChars(int fd, char *bytes, int maxbytes)
{
fd_set rmask;
struct timeval tmo = { 0, 0 };
int ret;
FD_ZERO(&rmask);
FD_SET(fd, &rmask);
ret = uselect(fd + 1, &rmask, NULL, NULL, &tmo);
if (ret <= 0)
return ret;
ret = recv(fd, bytes, maxbytes, 0);
/* PrintChar(*chr); fflush(stdout); */
if (ret > 0)
return ret;
if (ret == 0) {
errno = ECONNRESET;
return ASCON_DISCONNECTED;
}
return ASCON_RECV_ERROR;
}
/*----------------------------------------------------------------------------*/
int Secop3ProtHandler(Ascon *a) {
int ret;
char *result;
char *space;
char *json;
char *specifier;
Tcl_Obj *tcllist[3], *tclobj;
int l, l1, l2;
struct json_object *jobj;
char buffer[1024];
char *bytes;
char *str;
SecopBuf *msgbuf;
SecopMsg *msg, **msgp;
if (a->state <= AsconConnectDone) {
/* handle connect states */
return AsconStdHandler(a);
}
/* treat incoming messages always */
msgbuf = a->private;
if (msgbuf == NULL) {
msgbuf = calloc(1, sizeof *msgbuf);
a->private = msgbuf;
a->killPrivate = SecopKillPrivate;
msgbuf->buffer = CreateDynString(60, 65536);
}
ret = Secop3ReadChars(a->fd, buffer, sizeof buffer - 1);
while (ret > 0) {
assert(ret < sizeof buffer);
buffer[ret] = '\0';
bytes = buffer;
str = strchr(bytes, '\n');
while (str) {
l = str - bytes;
DynStringConcatBytes(msgbuf->buffer, bytes, l);
/* append at end of queue */
for (msgp = &msgbuf->queue; *msgp != NULL; msgp = &(*msgp)->next);
msg = calloc(1, sizeof *msg);
*msgp = msg;
msg->message = strdup(GetCharArray(msgbuf->buffer));
DynStringClear(msgbuf->buffer);
bytes += l + 1;
str = strchr(bytes, '\n');
}
DynStringConcat(msgbuf->buffer, bytes);
ret = Secop3ReadChars(a->fd, buffer, sizeof buffer - 1);
}
if (ret < 0) {
AsconError(a, "SECOP.1", errno);
}
switch (a->state) {
case AsconWriting:
/* do not skip garbage */
l = GetDynStringLength(a->wrBuffer) - a->wrPos;
ret = AsconWriteChars(a->fd, GetCharArray(a->wrBuffer) + a->wrPos, l);
if (ret < 0) {
AsconError(a, "SECOP.2", errno); /* sets state to AsconFailed */
} else {
a->wrPos += ret;
if (a->wrPos >= GetDynStringLength(a->wrBuffer)) {
a->state = AsconWriteDone;
}
}
return 1;
case AsconWriteStart:
if (GetDynStringLength(a->wrBuffer) == 0) {
/* do not send empty message */
a->state = AsconWriteDone;
return 1;
}
if (a->sendTerminator) {
DynStringConcat(a->wrBuffer, a->sendTerminator);
}
a->wrPos = 0;
a->state = AsconWriting;
break;
case AsconReadStart:
a->state = AsconReadDone;
msgbuf = a->private;
if (msgbuf->queue == NULL) {
DynStringClear(a->rdBuffer);
return 1;
}
msg = msgbuf->queue;
msgbuf->queue = msg->next;
space = strchr(msg->message, ' ');
jobj = NULL;
specifier = "";
if (space) {
l1 = space - msg->message;
specifier = space + 1;
json = strchr(specifier, ' ');
if (json) {
l2 = json - specifier;
json++;
jobj = json_tokener_parse(json);
} else {
l2 = strlen(specifier);
}
} else {
l1 = strlen(msg->message);
l2 = 0;
}
tcllist[0] = Tcl_NewStringObj(msg->message, l1);
tcllist[1] = Tcl_NewStringObj(specifier, l2);
if (jobj) {
tcllist[2] = json2tcl(jobj);
tclobj = Tcl_NewListObj(3, tcllist);
} else {
tclobj = Tcl_NewListObj(2, tcllist);
}
DynStringCopy(a->rdBuffer, Tcl_GetString(tclobj));
a->responseValid = 1;
json_object_put(jobj); /* free jobj */
free(msg->message);
free(msg);
break;
}
return 1;
}
/*----------------------------------------------------------------------------*/
void AddSecop3Protocol() {
static AsconProtocol secopprot;
secopprot.name = "SECoP3";
secopprot.handler = Secop3ProtHandler;
secopprot.init = AsconStdInit;
AsconInsertProtocol(&secopprot);
}

View File

@ -41,6 +41,7 @@
#include "arrayutil.h"
#include "HistMem.h"
#include "asynnet.h"
#include <json-c/json.h>
#define MAX_HDB_PATH 1024
@ -455,6 +456,7 @@ int formatNameValue(Protocol protocol, char *name, char *value,
pDynString result, int hdtype)
{
char *char_arr, *ptr;
char token[8], ch;
switch (protocol) {
case normal_protocol:
@ -465,6 +467,7 @@ int formatNameValue(Protocol protocol, char *name, char *value,
case json_protocol:
switch (hdtype) {
case HIPNONE:
DynStringCopy(result, "null");
break;
case HIPINT:
case HIPFLOAT:
@ -478,7 +481,27 @@ int formatNameValue(Protocol protocol, char *name, char *value,
DynStringCopy(result, "{\"");
DynStringConcat(result, name);
DynStringConcat(result, "\": \"");
DynStringConcat(result, value);
ptr = NULL;
for (ch=*value; ch!=0; ch=*++value) {
switch (ch) {
case '"': strcpy(token, "\\\"");
case '\\': strcpy(token, "\\\\");
default:
if (ch > 127 || ch < 32) {
snprintf(token, sizeof token, "\\u%4.4x", (unsigned char)ch);
} else {
if (!ptr) ptr = value;
continue;
}
}
if (ptr) {
DynStringConcatBytes(result, ptr, value - ptr);
}
DynStringConcat(result, token);
}
if (ptr) {
DynStringConcatBytes(result, ptr, value - ptr);
}
DynStringConcat(result, "\"}");
break;
case HIPINTAR:
@ -593,8 +616,11 @@ static hdbCallbackReturn SICSNotifyCallback(pHdb node, void *userData,
pHdbIDMessage idm = NULL;
pHdbPtrMessage cmm = NULL;
pHdbDataMessage mm = NULL;
hdbPropertyChange *propm = NULL;
hdbValue *hvalue;
SConnection *tstCon;
char updatePath[1024];
char *geterror;
cbInfo = (HdbCBInfo *) userData;
@ -650,9 +676,20 @@ static hdbCallbackReturn SICSNotifyCallback(pHdb node, void *userData,
}
/*
* Deal with update messages
* Deal with update and geterror property messages
*/
if ((mm = GetHdbUpdateMessage(message)) == NULL) {
if ((propm = GetPropertyChangeMessage(message)) != NULL) {
if (strcmp(propm->key, "geterror") != 0) {
/* this is a property change of an other property */
return hdbContinue;
}
geterror = propm->value;
hvalue = &node->value;
} else if ((mm = GetHdbUpdateMessage(message)) != NULL) {
geterror = GetHdbProp(node, "geterror");
hvalue = mm->v;
} else {
return hdbContinue;
}
@ -663,19 +700,26 @@ static hdbCallbackReturn SICSNotifyCallback(pHdb node, void *userData,
else
outCode = eEvent;
if (geterror && *geterror) {
/* send geterror */
strlcat(updatePath, ".geterror", sizeof updatePath);
formatNameValue(protocol, updatePath, geterror, result, HIPTEXT);
SCPureSockWrite(cbInfo->pCon, Dyn2Cstring(result), outCode);
return hdbContinue;
} /* else normal notify */
/**
* if transfer = zip always transfer data in zipped form
*/
if (GetHdbProperty(node, "transfer", value, 80) == 1) {
if (strstr(value, "zip") != NULL || strstr(value,"bin") != NULL) {
status = sendZippedNodeData(node, *(mm->v), cbInfo->pCon);
status = sendZippedNodeData(node, *hvalue, cbInfo->pCon);
DeleteDynString(result);
return hdbContinue;
}
}
if (mm->v->arrayLength < 100) {
printedData = formatValue(*(mm->v), node);
if (hvalue->arrayLength <= 400) {
printedData = formatValue(*hvalue, node);
if (printedData == NULL || result == NULL) {
SCWrite(cbInfo->pCon, "ERROR: out of memory formatting data",
eEvent);
@ -686,7 +730,7 @@ static hdbCallbackReturn SICSNotifyCallback(pHdb node, void *userData,
return hdbContinue;
}
formatNameValue(protocol, updatePath, GetCharArray(printedData), result,
mm->v->dataType);
hvalue->dataType);
#ifdef SITE_ANSTO
SCWrite(cbInfo->pCon, GetCharArray(result), outCode);
#else
@ -792,8 +836,10 @@ static hdbCallbackReturn TreeChangeCallback(pHdb node, void *userData,
outCode = eHdbEvent;
else
outCode = eEvent;
/* formatNameValue(protocol, "treechange", path, result,
node->value.dataType); */
formatNameValue(protocol, "treechange", path, result,
node->value.dataType);
HIPTEXT);
SCWrite(cbInfo->pCon, GetCharArray(result), outCode);
DeleteDynString(result);
free(path);
@ -814,7 +860,9 @@ pHdbCallback MakeTreeChangeCallback(SConnection * pCon, int id)
if (cbInfo->pCon == NULL) {
return NULL;
}
SCsetMacro(cbInfo->pCon, 0);
cbInfo->ID = id;
cbInfo->internalID = -1;
return MakeHipadabaCallback(TreeChangeCallback, cbInfo, cbKill);
}
@ -3024,11 +3072,12 @@ static pDynString formatPlainList(pHdb node)
}
/*---------------------------------------------------------------------------*/
static pDynString formatJSONList(pHdb node)
static pDynString formatJSONList(pHdb node, int withValues)
{
pHdb current;
pDynString result = NULL;
pDynString data = NULL;
char *str;
if (node->child == NULL)
return NULL;
@ -3037,22 +3086,44 @@ static pDynString formatJSONList(pHdb node)
return NULL;
}
if (node->child->value.dataType == HIPNONE)
DynStringCopy(result, "[");
else
if (withValues)
DynStringCopy(result, "{");
else
DynStringCopy(result, "[");
current = node->child;
while (current != NULL) {
DynStringConcat(result, "\"");
DynStringConcatChar(result, '"');
DynStringConcat(result, current->name);
DynStringConcat(result, "\"");
if (current->value.dataType != HIPNONE) {
data = formatValue(current->value, current);
if (data != NULL) {
DynStringConcat(result, ": ");
DynStringConcat(result, GetCharArray(data));
DeleteDynString(data);
DynStringConcatChar(result, '"');
if (withValues) {
DynStringConcat(result, ": ");
if (current->value.dataType == HIPTEXT) {
DynStringConcatChar(result, '"');
data = formatValue(current->value, current);
if (data != NULL) {
/* lazy approach: remove \ and " */
for (str = GetCharArray(data); *str != 0; str++) {
if (*str == '\\' || *str == '"') {
*str = '_';
}
}
DynStringConcat(result, GetCharArray(data));
DeleteDynString(data);
}
DynStringConcatChar(result, '"');
} else {
if (current->value.dataType != HIPINT && current->value.dataType != HIPFLOAT) {
data = NULL;
} else {
data = formatValue(current->value, current);
}
if (data != NULL) {
DynStringConcat(result, GetCharArray(data));
DeleteDynString(data);
} else {
DynStringConcat(result, "null");
}
}
}
if (current->next != NULL)
@ -3060,10 +3131,10 @@ static pDynString formatJSONList(pHdb node)
current = current->next;
}
if (node->child->value.dataType == HIPNONE)
DynStringConcat(result, "]");
else
if (withValues)
DynStringConcat(result, "}");
else
DynStringConcat(result, "]");
return result;
}
@ -3197,31 +3268,34 @@ static int ListHdbNode(SConnection * pCon, SicsInterp * pSics, void *pData,
return 0;
}
/* do not modify arguments!
if (pathArg == 2) {
strtolower(argv[1]);
}
if (strcmp(argv[1], "-val") == 0) {
listData = formatListWithVal(node);
} else if (strcmp(argv[1], "-cli") == 0) {
*/
outCode = eValue;
if (strcasecmp(argv[1], "-val") == 0) {
if (isJSON(pCon, 0)) {
listData = formatJSONList(node, 1);
outCode = eHdbEvent;
} else {
listData = formatListWithVal(node);
}
} else if (strcasecmp(argv[1], "-cli") == 0) {
listData = formatClientList(node);
} else {
if ((protocol = isJSON(pCon, 0)) == 1) {
listData = formatJSONList(node);
listData = formatJSONList(node, 0);
outCode = eHdbEvent;
} else {
listData = formatPlainList(node);
outCode = eValue;
}
}
if (listData == NULL) {
SCWrite(pCon, "ERROR: failed to format list", eError);
return 0;
}
if ((strcmp(argv[1], "-val") == 0) || (strcmp(argv[1], "-cli") == 0)) {
SCWrite(pCon, GetCharArray(listData), eValue);
} else {
SCWrite(pCon, GetCharArray(listData), outCode);
}
SCWrite(pCon, GetCharArray(listData), outCode);
DeleteDynString(listData);
return 1;
}

72
socketaddr.c Normal file
View File

@ -0,0 +1,72 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
int MakeSocketAddr(
struct sockaddr *sockaddrPtr, /* socket address */
char *hostname, /* name or ip of host. NULL implies INADDR_ANY */
int port, /* port number */
char dotted_ip[16]) { /* resolved ip addr */
/*
Workaround for cases, where the local cache is not updated (yet)
often, gethostbyname gets a cached value, but dig will get a fresh one
note after an internet research: dig is recommended over nslookup
*/
struct hostent *hostent; /* Host database entry */
struct sockaddr_in *sadr = (struct sockaddr_in *)sockaddrPtr;
FILE *fil;
char line[256];
int l;
(void) memset(sadr, 0, sizeof(*sadr));
if (dotted_ip) { /* default value: failure */
dotted_ip[0] = 0;
}
sadr->sin_family = AF_INET;
sadr->sin_port = htons((unsigned short)port);
if (hostname == NULL) {
/* do not need to copy, as INADDR_ANY is all zero bytes */
return 1;
}
if (inet_pton(AF_INET, hostname, &sadr->sin_addr) == 1) {
/* resolved as dotted numbers notation */
return 1;
}
hostent = gethostbyname(hostname);
if (hostent == 0) {
/* we assume that when gethostname gets no entry, dig will also fail.
That way, dig will not be called repeatedly for no reason */
return 0;
}
/* copy the address: in case dig fails, we use the cached value */
memcpy(&sadr->sin_addr, hostent->h_addr_list[0], 4);
/* we use hostent->h_name instead of hostname here, as this has already
the proper domain added */
snprintf(line, sizeof line, "timeout 1 dig +short %s", hostent->h_name);
fil = popen(line, "r");
if (fil != NULL) {
if (fgets(line, sizeof(line), fil) != NULL) {
l = strlen(line);
if (line[l-1] <= ' ') line[l-1] = 0; /* strip off newline */
/* silently ignore return value, if it fails, we take the cached value */
inet_pton(AF_INET, line, &sadr->sin_addr);
}
fclose(fil);
}
if (dotted_ip) {
inet_ntop(AF_INET, &sadr->sin_addr, dotted_ip, 16);
}
return 1;
}
int CreateSocketAdress(struct sockaddr_in *sockaddrPtr, /* Socket address */
char *host, /* Host. NULL implies INADDR_ANY */
int port)
{
return MakeSocketAddr((struct sockaddr *)sockaddrPtr, host, port, NULL);
}

23
socketaddr.h Normal file
View File

@ -0,0 +1,23 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
int MakeSocketAddr(
struct sockaddr *sockaddrPtr, /* socket address */
char *hostname, /* name or ip of host. NULL implies INADDR_ANY */
int port, /* port number */
char dotted_ip[16]); /* resolved ip addr */
/*
Workaround for cases, where the local cache is not updated (yet)
often, gethostbyname gets a cached value, but dig will get a fresh one
note after an internet research: dig is recommended over nslookup
*/
/* compatibility for network.c */
int CreateSocketAdress(struct sockaddr_in *sockaddrPtr, /* Socket address */
char *host, /* Host. NULL implies INADDR_ANY */
int port);