New example server that monitors all the IOC on a network

This commit is contained in:
Jim Kowalkowski
1997-05-13 14:19:40 +00:00
parent f810436bb1
commit f654800370
10 changed files with 1536 additions and 0 deletions

View File

@@ -0,0 +1,12 @@
# $Log$
# Revision 1.2 1997/03/05 21:16:21 jbk
# Fixes cvs log id at top
#
TOP=../../../..
include $(TOP)/config/CONFIG_BASE
include $(TOP)/config/RULES_ARCHS

View File

@@ -0,0 +1,25 @@
# $Log$
# Revision 1.2 1997/03/05 21:16:21 jbk
# Fixes cvs log id at top
#
CAS = ../../..
TOP = $(CAS)/../..
include $(TOP)/config/CONFIG_BASE
CXXCMPLR = STRICT
PROD_LIBS := cas ca gdd Com
SRCS += mon.cc monAdl.cc monNode.cc monServer.cc
PROD := iocMonitor
include $(TOP)/config/RULES.Host
clean::
@$(RM) iocMonitor
@$(RM) -rf Templates.DB
@$(RM) core

View File

@@ -0,0 +1,337 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <net/if.h>
#include "caProto.h"
// use lower 11 bits of address as index
#define ADDR_MASK 0x000007ff
#define ADDR_CHECK 10
#define ADDR_WARNING 20
#define ADDR_DEATH 40
#define REPEATER_PORT 5065
typedef enum { nodeAlive=0, nodeUnknown, nodeDead } nodeState;
// ----------------------------- host node ------------------------------
class netNode
{
public:
netNode(unsigned long a,const char* pre);
~netNode(void);
void report(void);
void ping(void);
nodeState state(void);
nodeState state(time_t);
unsigned long addr;
time_t last_ping;
const char* name;
struct netNode* next;
};
netNode::netNode(unsigned long a,const char* pre)
{
struct in_addr& in = (struct in_addr&)a;
struct hostent* entry;
char *n,*x;
addr=a;
time(&last_ping);
if((entry=gethostbyaddr((char*)&a,sizeof(a),AF_INET))==NULL)
n=inet_ntoa(in);
else
n=entry->h_name;
x=new char[strlen(n)+1+strlen(pre)];
strcpy(x,pre);
strcat(x,n);
name=x;
next=NULL;
}
netNode::~netNode(void)
{
char* n = (char*)name;
delete [] n;
}
void netNode::ping(void)
{
time(&last_ping);
}
nodeState netNode::state(void)
{
time_t t;
time(&t);
return state(t);
}
nodeState netNode::state(time_t t)
{
nodeState s;
time_t x;
x=t-last_ping;
if(x<ADDR_WARNING)
s=nodeAlive;
else if(x<ADDR_DEATH)
s=nodeUnknown;
else
s=nodeDead;
return s;
}
void netNode::report(void)
{
switch(state())
{
case nodeDead: printf(" IOC %s Dead\n",name); break;
case nodeAlive: printf(" IOC %s Alive\n",name); break;
case nodeUnknown: printf(" IOC %s Unknown\n",name); break;
}
}
// -------------------------- database ---------------------------
class addrDb
{
public:
addrDb(const char* p);
~addrDb(void);
void report(void);
netNode* findNode(unsigned long addr);
netNode* addNode(unsigned long addr);
private:
const char* prefix;
netNode** db;
};
addrDb::addrDb(const char* p)
{
int i;
const char* x = p?p:"_";
char* y;
y=new char[strlen(x)+1];
strcpy(y,x);
prefix=y;
db=new netNode*[ADDR_MASK];
for(i=0;i<ADDR_MASK;i++) db[i]=NULL;
}
addrDb::~addrDb(void)
{
int i;
netNode *c,*p;
for(i=0;i<ADDR_MASK;i++)
{
for(c=db[i];c;)
{
p=c->next;
delete c;
c=p;
}
}
delete [] db;
}
void addrDb::report(void)
{
int i;
netNode* n;
for(i=0;i<ADDR_MASK;i++)
{
for(n=db[i];n;n=n->next)
n->report();
}
}
netNode* addrDb::findNode(unsigned long addr)
{
netNode* t;
for(t=db[addr&ADDR_MASK];t && t->addr!=addr;t=t->next);
return t;
}
netNode* addrDb::addNode(unsigned long addr)
{
unsigned long i;
netNode* t;
if((t=findNode(addr))==NULL)
{
i=addr&ADDR_MASK;
t=new netNode(addr,prefix);
t->next=db[i];
db[i]=t;
}
else
t->ping();
return t;
}
// ------------------------------------------------------------------------
addrDb* db;
int main(int argc, char* argv[] )
{
caHdr msg;
struct sockaddr_in tsin;
struct sockaddr ssin;
struct timeval tout;
struct hostent* entry;
fd_set fds;
char* name;
netNode* node;
int soc,retry,done,rlen,len;
unsigned short cmd;
unsigned long* iaddr;
time_t curr,last;
if(argc<2)
{
fprintf(stderr,"Must enter a prefix for PVs on command line\n");
return -1;
}
db=new addrDb(argv[1]);
tsin.sin_port=htons(0);
tsin.sin_family=AF_INET;
tsin.sin_addr.s_addr=htonl(INADDR_ANY);
if((soc=socket(AF_INET,SOCK_DGRAM,17))<0)
{
perror("open socket failed");
return -1;
}
if((bind(soc,(struct sockaddr*)&tsin,sizeof(tsin)))<0)
{
perror("local bind failed to soc failed");
close(soc);
return -1;
}
memset((char*)&msg,0,sizeof(msg));
msg.m_cmmd = htons(REPEATER_REGISTER);
msg.m_available = tsin.sin_addr.s_addr;
tsin.sin_port=htons(REPEATER_PORT);
for(done=0,retry=0;done==0 && retry<3;retry++)
{
if(sendto(soc,(char*)&msg,sizeof(msg),0,
(struct sockaddr*)&tsin,sizeof(tsin))<0)
{
perror("sendto failed");
close(soc);
return -1;
}
FD_ZERO(&fds);
FD_SET(soc,&fds);
tout.tv_sec=0;
tout.tv_usec=500000;
switch(select(FD_SETSIZE,&fds,NULL,NULL,&tout))
{
case -1: /* bad */
perror("first select failed");
return -1;
case 0: /* timeout */
break;
default: /* data ready */
done=1;
}
}
if(done==1)
{
rlen=0;
if((len=recvfrom(soc,(char*)&msg,sizeof(msg),0,&ssin,&rlen))<0)
{
perror("first recvfrom failed");
return -1;
}
cmd=ntohs(msg.m_cmmd);
if(cmd==REPEATER_CONFIRM)
printf("Connected to repeater\n");
else
{
printf("Cannot connect to repeater (%d)\n",(int)cmd);
return -1;
}
}
else
{
printf("Cannot connect to repeater\n");
return -1;
}
/* ---------------- ready ---------------- */
last=0;
while(1)
{
FD_ZERO(&fds);
FD_SET(soc,&fds);
tout.tv_sec=ADDR_CHECK;
tout.tv_usec=0;
switch(select(FD_SETSIZE,&fds,NULL,NULL,&tout))
{
case -1: /* bad */
perror("main select failed");
case 0: /* timeout */
// db->report();
break;
default: /* data ready */
{
if((len=recvfrom(soc,(char*)&msg,sizeof(msg),0,&ssin,&rlen))<0)
{
perror("first recvfrom failed");
return -1;
}
iaddr=(unsigned long*)&msg.m_available;
node=db->addNode(*iaddr);
// cmd=ntohs(msg.m_cmmd);
// if(cmd==CA_PROTO_RSRV_IS_UP)
// {
// printf("Alive\n");
// }
// else
// printf("Unidentified Command from 0x%8.8x\n",*iaddr);
break;
}
}
time(&curr);
if((curr-last)>=ADDR_CHECK)
{
db->report();
last=curr;
}
}
return 0;
}

View File

@@ -0,0 +1,89 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "monNode.h"
#include "monServer.h"
#define WIDTH 180
#define HEIGHT 10
#define MAX_WIDTH 1000
#define MAX_HEIGHT 700
#define TOTAL_X (MAX_WIDTH/WIDTH)
#define TOTAL_Y (MAX_HEIGHT/HEIGHT)
int monAdl(monNode** head, char* fname,const char* prefix)
{
FILE *fdout;
int dh;
int i,j,k;
monNode* node;
if((fdout=fopen(fname,"w"))==NULL)
{
fprintf(stderr,"Cannot open the ADL file %s\n",fname);
return -1;
}
dh=monNode::total/TOTAL_X;
if((dh*TOTAL_X)!=monNode::total) ++dh;
fprintf(fdout,"\nfile { name=\"ioc_status.adl\" version=020209 }\n");
fprintf(fdout,"display {\n");
fprintf(fdout," object { x=0 y=0 width=%d height=%d }\n",
MAX_WIDTH,dh*HEIGHT+40);
fprintf(fdout," clr=37 bclr=14 cmap=\"\"\n}\n");
fprintf(fdout,"\"color map\" { ncolors=65 colors {\n");
fprintf(fdout,"ffffff, ececec, dadada, c8c8c8, bbbbbb, aeaeae, 9e9e9e,\n");
fprintf(fdout,"919191, 858585, 787878, 696969, 5a5a5a, 464646, 2d2d2d,\n");
fprintf(fdout,"000000, 00d800, 1ebb00, 339900, 2d7f00, 216c00, fd0000,\n");
fprintf(fdout,"de1309, be190b, a01207, 820400, 5893ff, 597ee1, 4b6ec7,\n");
fprintf(fdout,"3a5eab, 27548d, fbf34a, f9da3c, eeb62b, e19015, cd6100,\n");
fprintf(fdout,"ffb0ff, d67fe2, ae4ebc, 8b1a96, 610a75, a4aaff, 8793e2,\n");
fprintf(fdout,"6a73c1, 4d52a4, 343386, c7bb6d, b79d5c, a47e3c, 7d5627,\n");
fprintf(fdout,"58340f, 99ffff, 73dfff, 4ea5f9, 2a63e4, 0a00b8, ebf1b5,\n");
fprintf(fdout,"d4db9d, bbc187, a6a462, 8b8239, 73ff6b, 52da3b, 3cb420,\n");
fprintf(fdout,"289315, 1a7309,\n");
fprintf(fdout,"} }\n");
// ----------------------- heading ----------------------------------
i=(MAX_WIDTH/2)-(300/2);
fprintf(fdout," text { object { x=%d y=2 width=300 height=25 }\n",i);
fprintf(fdout," \"basic attribute\" { clr=37 }\n");
fprintf(fdout," textix=\"%d IOC STATUS MONITOR\"\n",monNode::total);
fprintf(fdout," align=\"horiz. centered\"\n}\n");
// ---------------------- generate new file button -------------------
fprintf(fdout,"\"message button\" { object\n");
fprintf(fdout," { x=%d y=2 width=180 height=22 }\n",MAX_WIDTH-180);
fprintf(fdout," control { chan=\"%smakeScreen\" clr=31 bclr=47 }\n",prefix);
fprintf(fdout," label=\"Make New Screen\" press_msg=\"1\"\n}\n");
fprintf(fdout,"\"text update\" { object { x=1 y=2 width=180 height=22 }\n");
fprintf(fdout," monitor { chan=\"%siocCount\" clr=31 bclr=14 }\n",prefix);
fprintf(fdout,"}\n");
// -------------- make all the buttons
i=0;j=0;
for(k=0;k<ADDR_TOTAL;k++)
{
for(node=head[k];node;node=node->next)
{
fprintf(fdout,"\"text update\" {\n");
fprintf(fdout," object { x=%d y=%d width=%d height=%d }\n",
i*WIDTH,j*HEIGHT+30,WIDTH,HEIGHT);
if(++i>=TOTAL_X) { i=0; ++j; }
fprintf(fdout," monitor { chan=\"%s\" clr=0 bclr=14 }\n",
node->name);
fprintf(fdout," clrmod=\"alarm\"\n}\n");
}
}
fclose(fdout);
return 0;
}

View File

@@ -0,0 +1,277 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include "gddAppTable.h"
#include "monServer.h"
#include "monNode.h"
// --------------------------- monPv ----------------------------
monPv::monPv(const casCtx& c,monServer& s,monNode* n,const char* name):
casPV(c,name),node(n),mrg(s)
{
monDebug1(5,"monPV: Creating PV for %s\n",name);
data=NULL;
markNotInterested();
node->setPv(this);
}
monPv::~monPv(void)
{
node->clearPv();
if(data) data->unreference();
monDebug1(5,"monPV: Deleting PV for %s\n",node->name);
}
unsigned monPv::maxSimultAsyncOps(void) const { return 5000u; }
void monPv::interestDelete(void) { markNotInterested(); }
aitEnum monPv::bestExternalType(void) const { return aitEnumString; }
unsigned monPv::maxDimension(void) const { return 0; }
aitIndex monPv::maxBound(unsigned dim) const { return 0; }
void monPv::destroy(void) { casPV::destroy(); }
caStatus monPv::interestRegister(void)
{
markInterested();
return S_casApp_success;
}
caStatus monPv::read(const casCtx& ctx, gdd& dd)
{
monDebug1(5,"monPV: Read PV data=0x%8.8x\n",(int)data);
gddApplicationTypeTable& table=gddApplicationTypeTable::AppTable();
if(data) table.smartCopy(&dd,data);
return S_casApp_success;
}
caStatus monPv::write(const casCtx& /*ctx*/, gdd& /*dd*/)
{
// cannot write to these PVs
return S_casApp_success;
}
void monPv::eventData(void)
{
struct tm* t;
char val[40];
char str[10];
aitTimeStamp stamp(node->state_ping,0);
// prepare a new gdd used for posting and reads
if(data) data->unreference();
data=new gddScalar(mrg.appValue,aitEnumString);
t=localtime(&node->state_ping);
switch(node->state())
{
case monAlive:
strcpy(str,"Up");
data->setStatSevr(0,NO_ALARM);
break;
case monUnknown:
strcpy(str,"?");
data->setStatSevr(TIMEOUT_ALARM,MINOR_ALARM);
break;
case monDead:
strcpy(str,"Down");
data->setStatSevr(COMM_ALARM,MAJOR_ALARM);
break;
}
/*
sprintf(val,"(%s %s %2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d)",
&node->name[mrg.prefix_length],str,
t->tm_mon+1,t->tm_mday,t->tm_year,t->tm_hour,t->tm_min,t->tm_sec);
*/
sprintf(val,"(%2.2d/%2.2d %2.2d:%2.2d:%2.2d %s)",
t->tm_mon+1,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec,
&node->name[mrg.prefix_length]);
data->reference();
data->setTimeStamp(&stamp);
data->put(val);
monDebug1(5,"monPV: eventData data=0x%8.8x\n",(int)data);
if(debugLevel>6) data->dump();
if(isMonitored())
{
monDebug0(5,"monPV: PV monitored\n");
casEventMask select(
mrg.alarmEventMask|mrg.valueEventMask|mrg.logEventMask);
postEvent(select,*data);
}
}
// --------------------------- monNode ----------------------------
monNode::monNode(unsigned long a,const char* prefix)
{
struct in_addr& in = (struct in_addr&)a;
struct hostent* entry;
char *n,*x;
addr=a;
time(&last_ping);
state_ping=last_ping;
if((entry=gethostbyaddr((char*)&a,sizeof(a),AF_INET))==NULL)
n=inet_ntoa(in);
else
n=entry->h_name;
x=new char[strlen(n)+1+strlen(prefix)];
strcpy(x,prefix);
strcat(x,n);
name=x;
next=NULL;
pv=NULL;
last_state=monAlive;
++monNode::total;
monDebug1(5,"monNode: Created node %s\n",name);
}
monNode::~monNode(void)
{
monDebug1(5,"monNode: Deleted node %s\n",name);
char* n = (char*)name;
delete [] n;
}
int monNode::total=0;
void monNode::ping(void)
{
time(&last_ping);
}
monState monNode::state(void)
{
return last_state;
}
monState monNode::state(time_t t)
{
monState s;
time_t x;
x=t-last_ping;
if(x<ADDR_WARNING)
s=monAlive;
else if(x<ADDR_DEATH)
s=monUnknown;
else
s=monDead;
return s;
}
void monNode::check(time_t t)
{
monState s = state(t);
monDebug1(9,"monNode: Checking node %s\n",name);
if(s!=last_state)
{
last_state=s;
// only change boot time if going from/to dead
if(s==monDead || last_state==monDead) state_ping=t;
if(pv) pv->eventData();
}
}
void monNode::setPv(monPv* p)
{
int need;
monDebug1(9,"monNode: Setting PV for %s\n",name);
if(pv==NULL)
need=1;
else
need=0;
pv=p;
if(need) pv->eventData();
}
void monNode::clearPv(void) { pv=NULL; }
void monNode::report(FILE* fd)
{
struct in_addr* ia = (struct in_addr*)&addr;
switch(state())
{
case monDead:
fprintf(fd,"%s %s Dead\n",name,inet_ntoa(*ia));
break;
case monAlive:
fprintf(fd,"%s %s Alive\n",name,inet_ntoa(*ia));
break;
case monUnknown:
fprintf(fd,"%s %s Unknown\n",name,inet_ntoa(*ia));
break;
}
}
// -------------------- status PVs -----------------------
makeScreenPV::~makeScreenPV(void) { }
aitEnum makeScreenPV::bestExternalType(void) const { return aitEnumInt32; }
caStatus makeScreenPV::read(const casCtx& /*ctx*/, gdd& /*dd*/)
{
return S_casApp_success;
}
caStatus makeScreenPV::write(const casCtx& /*ctx*/, gdd& /*dd*/)
{
mrg.makeADL();
return S_casApp_success; // cannot write to these PVs
}
// -------------
iocCountPV::~iocCountPV(void) { mrg.count_pv=NULL; }
void iocCountPV::interestDelete(void) { monitored=0; }
aitEnum iocCountPV::bestExternalType(void) const { return aitEnumInt32; }
void iocCountPV::postValue(void)
{
gdd* value=new gddScalar(mrg.appValue,aitEnumInt32);
value->put(monNode::total);
if(monitored)
{
casEventMask select(
mrg.alarmEventMask|mrg.valueEventMask|mrg.logEventMask);
postEvent(select,*value);
}
}
caStatus iocCountPV::interestRegister(void)
{
monitored=1;
return S_casApp_success;
}
caStatus iocCountPV::read(const casCtx& ctx, gdd& dd)
{
// this is bad, should check for dd to be scalar, if it is not a scalar,
// then find the value gdd within the container
dd.put(monNode::total);
return S_casApp_success;
}
caStatus iocCountPV::write(const casCtx& /*ctx*/, gdd& /*dd*/)
{
return S_casApp_success; // cannot write to these PVs
}

View File

@@ -0,0 +1,109 @@
#ifndef MONNODE_H
#define MONNODE_H
#include <time.h>
#include "aitTypes.h"
#include "casdef.h"
typedef enum { monAlive=0, monUnknown, monDead } monState;
#define ADDR_CHECK 10
#define ADDR_WARNING 20
#define ADDR_DEATH 40
class monNode;
class monServer;
class gdd;
class monPv : public casPV
{
public:
monPv(const casCtx&,monServer&,monNode*,const char* pv_name);
virtual ~monPv(void);
// CA server interface functions
virtual caStatus interestRegister(void);
virtual void interestDelete(void);
virtual aitEnum bestExternalType(void) const;
virtual caStatus read(const casCtx &ctx, gdd &prototype);
virtual caStatus write(const casCtx &ctx, gdd &value);
virtual void destroy(void);
virtual unsigned maxSimultAsyncOps(void) const;
virtual unsigned maxDimension(void) const;
virtual aitIndex maxBound(unsigned dim) const;
void eventData(void);
void markInterested(void) { monitor=1; }
void markNotInterested(void) { monitor=0; }
int isMonitored(void) { return monitor; }
monServer& mrg;
monNode* node;
int monitor;
gdd* data;
};
class monNode
{
public:
monNode(unsigned long a, const char* prefix);
~monNode(void);
void report(FILE*);
void ping(void);
void check(time_t);
monState state(void);
monState state(time_t);
void setPv(monPv*);
void clearPv(void);
unsigned long addr;
time_t last_ping;
time_t state_ping;
const char* name;
monPv* pv;
monNode* next;
monState last_state;
static int total;
};
// ---------------------------- status PVs --------------------------
class makeScreenPV : public casPV
{
public:
makeScreenPV(const casCtx& c,const char* pv_name,monServer& s):
casPV(c,pv_name),mrg(s){}
virtual ~makeScreenPV(void);
// CA server interface functions
virtual aitEnum bestExternalType(void) const;
virtual caStatus read(const casCtx &ctx, gdd &prototype);
virtual caStatus write(const casCtx &ctx, gdd &value);
monServer& mrg;
};
class iocCountPV : public casPV
{
public:
iocCountPV(const casCtx& c,const char* pv_name,monServer& s):
casPV(c,pv_name),mrg(s),monitored(0) {}
virtual ~iocCountPV(void);
// CA server interface functions
virtual caStatus interestRegister(void);
virtual void interestDelete(void);
virtual aitEnum bestExternalType(void) const;
virtual caStatus read(const casCtx &ctx, gdd &prototype);
virtual caStatus write(const casCtx &ctx, gdd &value);
void postValue(void);
int monitored;
monServer& mrg;
};
#endif

View File

@@ -0,0 +1,352 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <ctype.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <net/if.h>
#include "caProto.h"
#include "gddAppTable.h"
#include "monServer.h"
#include "monNode.h"
int debugLevel=0;
int makeReport=0;
int keepGoing=1;
typedef void (*SIG_FUNC)(int);
static SIG_FUNC save_hup = NULL;
static SIG_FUNC save_int = NULL;
static SIG_FUNC save_term = NULL;
static SIG_FUNC save_usr1 = NULL;
static void sig_end(int)
{
signal(SIGHUP,sig_end);
signal(SIGTERM,sig_end);
signal(SIGINT,sig_end);
keepGoing=0;
}
static void sig_usr1(int) { makeReport=1; signal(SIGUSR1,sig_usr1); }
extern int monAdl(monNode**,char*,const char*);
// ------------------------- file descriptor servicing ----------------------
monFd::~monFd(void) { }
void monFd::callBack(void) { server.dataReady(); }
// -------------------------- server -----------------------------
monServer::monServer(unsigned namelen,unsigned pvcount,unsigned simio,
const char* p):caServer(namelen,pvcount,simio)
{
int i;
count_pv=NULL;
const char* x = p?p:"_";
prefix=new char[strlen(x)+1];
strcpy(prefix,x);
prefix_length=strlen(prefix);
soc_fd=NULL;
db=new monNode*[ADDR_TOTAL];
for(i=0;i<ADDR_TOTAL;i++) db[i]=NULL;
gddApplicationTypeTable& tt = gddApplicationTypeTable::AppTable();
appValue=tt.getApplicationType("value");
sprintf(ioc_count_name,"%siocCount",prefix);
sprintf(make_screen_name,"%smakeScreen",prefix);
}
monServer::~monServer(void)
{
int i;
monNode *c,*p;
for(i=0;i<ADDR_TOTAL;i++)
{
for(c=db[i];c;)
{
p=c->next;
delete c;
c=p;
}
}
delete [] db;
}
void monServer::report(FILE* fd)
{
int i;
monNode* n;
for(i=0;i<ADDR_TOTAL;i++)
{
for(n=db[i];n;n=n->next)
n->report(fd);
}
}
monNode* monServer::findNode(unsigned long addr)
{
monNode* t;
for(t=db[addr&ADDR_MASK];t && t->addr!=addr;t=t->next);
return t;
}
monNode* monServer::addNode(unsigned long addr)
{
unsigned long i;
monNode* t;
if((t=findNode(addr))==NULL)
{
i=addr&ADDR_MASK;
t=new monNode(addr,prefix);
t->next=db[i];
db[i]=t;
pv_list.add(t->name,*t);
if(count_pv) count_pv->postValue();
}
else
t->ping();
return t;
}
void monServer::checkEvent(void)
{
// go through all the nodes and send out monitors on PV if required
time_t t;
int i;
monNode* n;
time(&t);
for(i=0;i<ADDR_TOTAL;i++)
{
for(n=db[i];n;n=n->next)
n->check(t);
}
}
pvExistReturn monServer::pvExistTest(const casCtx& c,const char* pvname)
{
monNode* node;
if(strcmp(pvname,ioc_count_name)==0)
return pvExistReturn(S_casApp_success,ioc_count_name);
if(strcmp(pvname,make_screen_name)==0)
return pvExistReturn(S_casApp_success,make_screen_name);
if(pv_list.find(pvname,node)==0)
return pvExistReturn(S_casApp_success,node->name);
else
return pvExistReturn(S_casApp_pvNotFound);
}
casPV* monServer::createPV(const casCtx& c,const char* pvname)
{
monNode* node;
if(strcmp(pvname,ioc_count_name)==0)
return count_pv=new iocCountPV(c,pvname,*this);
if(strcmp(pvname,make_screen_name)==0)
return new makeScreenPV(c,pvname,*this);
if(pv_list.find(pvname,node)==0)
return new monPv(c,*this,node,pvname);
else
return NULL;
}
int monServer::repeaterConnect(void)
{
caHdr msg;
struct sockaddr_in tsin;
struct sockaddr ssin;
struct timeval tout;
fd_set fds;
int retry,done,rlen,len;
tsin.sin_port=htons(0);
tsin.sin_family=AF_INET;
tsin.sin_addr.s_addr=htonl(INADDR_ANY);
if((soc=socket(AF_INET,SOCK_DGRAM,17))<0)
{
perror("open socket failed");
return -1;
}
if((bind(soc,(struct sockaddr*)&tsin,sizeof(tsin)))<0)
{
perror("local bind failed to soc failed");
close(soc);
return -1;
}
memset((char*)&msg,0,sizeof(msg));
msg.m_cmmd = htons(REPEATER_REGISTER);
msg.m_available = tsin.sin_addr.s_addr;
tsin.sin_port=htons(REPEATER_PORT);
for(done=0,retry=0;done==0 && retry<3;retry++)
{
if(sendto(soc,(char*)&msg,sizeof(msg),0,
(struct sockaddr*)&tsin,sizeof(tsin))<0)
{
perror("sendto failed");
close(soc);
return -1;
}
FD_ZERO(&fds);
FD_SET(soc,&fds);
tout.tv_sec=0;
tout.tv_usec=500000;
switch(select(FD_SETSIZE,&fds,NULL,NULL,&tout))
{
case -1: /* bad */
perror("first select failed");
return -1;
case 0: /* timeout */
break;
default: /* data ready */
done=1;
}
}
if(done==1)
{
rlen=0;
if((len=recvfrom(soc,(char*)&msg,sizeof(msg),0,&ssin,&rlen))<0)
{
perror("first recvfrom failed");
return -1;
}
if(ntohs(msg.m_cmmd)==REPEATER_CONFIRM)
printf("Connected to repeater\n");
else
{
printf("Cannot connect to repeater (%d)\n",(int)ntohs(msg.m_cmmd));
return -1;
}
}
else
{
printf("Cannot connect to repeater\n");
return -1;
}
soc_fd=new monFd(soc,fdrRead,*this);
return 0;
}
void monServer::dataReady(void)
{
caHdr msg;
struct sockaddr ssin;
monNode* node;
int rlen,len;
unsigned long* iaddr;
rlen=0;
if((len=recvfrom(soc,(char*)&msg,sizeof(msg),0,&ssin,&rlen))<0)
{
perror("first recvfrom failed");
}
else if(ntohs(msg.m_cmmd)==CA_PROTO_RSRV_IS_UP)
{
iaddr=(unsigned long*)&msg.m_available;
node=addNode(*iaddr);
}
}
void monServer::mainLoop(void)
{
osiTime delay(ADDR_CHECK,0u);
time_t curr,prev;
if(repeaterConnect()<0) return;
prev=0;
while(keepGoing)
{
fileDescriptorManager.process(delay);
time(&curr);
if((curr-prev)>=ADDR_CHECK)
{
checkEvent();
prev=curr;
}
if(makeReport)
{
FILE* fd;
if((fd=fopen("PV_REPORT","w")))
{
report(fd);
fclose(fd);
}
makeADL();
makeReport=0;
}
}
}
void monServer::makeADL(void) { monAdl(db,"ioc_status.adl",prefix); }
// ------------------------------------------------------------------------
int main(int argc, char* argv[])
{
if(argc<2)
{
fprintf(stderr,"Must enter a prefix for PVs on command line\n");
return -1;
}
if(argc==3) sscanf(argv[2],"%d",&debugLevel);
// disassociate from parent
switch(fork())
{
case -1: // error
perror("Cannot create gateway processes");
return -1;
case 0: // child
#if defined linux || defined SOLARIS
setpgrp();
#else
setpgrp(0,0);
#endif
setsid();
break;
default: // parent
return 0;
break;
}
save_hup=signal(SIGHUP,sig_end);
save_term=signal(SIGTERM,sig_end);
save_int=signal(SIGINT,sig_end);
save_usr1=signal(SIGUSR1,sig_usr1);
monServer* ms = new monServer(32u,5u,2000u,argv[1]);
ms->mainLoop();
delete ms;
return 0;
}

View File

@@ -0,0 +1,86 @@
#ifndef MONSERVER_H
#define MONSERVER_H
#include "casdef.h"
#include "tsHash.h"
#include "fdManager.h"
#include "monNode.h"
class gdd;
class monServer;
// use lower 11 bits of address as index
#define ADDR_MASK 0x0000001f
#define ADDR_TOTAL (ADDR_MASK+1)
#define REPEATER_PORT 5065
// ---------------------- fd manager ------------------------
class monFd : public fdReg
{
public:
monFd(const int fdIn,const fdRegType typ,monServer& s):
fdReg(fdIn,typ),server(s) { }
virtual ~monFd(void);
private:
virtual void callBack(void);
monServer& server;
};
// ---------------------------- server -------------------------------
class monServer : public caServer
{
public:
monServer(unsigned max_name_len,unsigned pv_count_est,unsigned max_sim_io,
const char* pre);
virtual ~monServer(void);
// CAS virtual overloads
virtual pvExistReturn pvExistTest(const casCtx& c,const char* pvname);
virtual casPV* createPV(const casCtx& c,const char* pvname);
// CAS application management functions
int repeaterConnect(void);
void checkEvent(void);
void dataReady(void);
void mainLoop(void);
void report(FILE*);
void makeADL(void);
monNode* findNode(unsigned long addr);
monNode* addNode(unsigned long addr);
int appValue;
char* prefix;
int prefix_length;
iocCountPV* count_pv;
private:
tsHash<monNode> pv_list; // client pv list
monNode** db;
monFd* soc_fd;
int soc;
char ioc_count_name[40];
char make_screen_name[40];
};
extern int debugLevel;
/* debug macro creation */
#ifdef NODEBUG
#define monDebug(l,f,v) ;
#else
#define monDebug(l,f,v) { if(l<=debugLevel) \
{ fprintf(stderr,f,v); fflush(stderr); }}
#define monDebug0(l,f) { if(l<=debugLevel) \
{ fprintf(stderr,f); fflush(stderr); } }
#define monDebug1(l,f,v) { if(l<=debugLevel) \
{ fprintf(stderr,f,v); fflush(stderr); }}
#define monDebug2(l,f,v1,v2) { if(l<=debugLevel) \
{ fprintf(stderr,f,v1,v2); fflush(stderr); }}
#define monDebug3(l,f,v1,v2,v3) { if(l<=debugLevel) \
{ fprintf(stderr,f,v1,v2,v3); fflush(stderr); }}
#endif
#endif

View File

@@ -0,0 +1,106 @@
#ifndef tsDLHashList_H
#define tsDLHashList_H
extern "C" {
#include "gpHash.h"
}
template <class T>
class tsHash
{
private:
void* hash_table;
public:
gpHash(void)
{
hash_table=NULL;
gphInitPvt(&hash_table);
}
~gateHash(void) { gphFreeMem(hash_table); }
int add(const char* key, T& item);
{
GPHENTRY* entry;
int rc;
entry=gphAdd(hash_table,(char*)key,hash_table);
if(entry==(GPHENTRY*)NULL)
rc=-1;
else
{
entry->userPvt=(void*)&item;
rc=0;
}
return rc;
}
int remove(const char* key,T*& item);
{
int rc;
if(find(key,item)<0)
rc=-1;
else
{
gphDelete(hash_table,(char*)key,hash_table);
rc=0;
}
return rc;
}
int find(const char* key, T*& item);
{
GPHENTRY* entry;
int rc;
entry=gphFind(hash_table,(char*)key,hash_table);
if(entry==(GPHENTRY*)NULL)
rc=-1;
else
{
item=(T*)entry->userPvt;
rc=0;
}
return rc;
}
};
template <class T>
class tsDLHashList : public tsDLList<T>
{
private:
tsHash<T> h;
public:
int add(const char* key, T& item)
{
int rc;
rc=h.add(key,item);
add(item);
return rc;
}
int find(const char* key, T*& item);
{
int rc=0;
if(h.find(key,item)!=0)
rc=-1;
return rc;
}
int remove(const char* key,T*& item);
{
int rc=0;
if(h.find(key,item)==0)
{
h.remove(key,item);
remove(*item);
}
else
rc=-1;
return rc;
}
};
#endif

View File

@@ -0,0 +1,143 @@
#ifndef tsDLHashList_H
#define tsDLHashList_H
/*
* Author: Jim Kowalkowski
* Date: 7/96
*
* $Id$
*
* $Log$
* Revision 1.2 1996/08/14 21:10:35 jbk
* next wave of updates, menus stopped working, units working, value not
* working correctly sometimes, can't delete the channels
*
* Revision 1.1 1996/07/23 16:32:46 jbk
* new gateway that actually runs
*
*/
extern "C" {
#include "gpHash.h"
}
#include "tsDLList.h"
template <class T>
class tsHash
{
private:
void* hash_table;
friend class tsDLHashIter<T>;
public:
tsHash(void)
{
hash_table=0;
gphInitPvt(&hash_table,2048); // 2048 is a guess
}
~tsHash(void)
{
gphFreeMem(hash_table);
}
int add(const char* key, T& item)
{
GPHENTRY* entry;
int rc;
entry=gphAdd(hash_table,(char*)key,hash_table);
if(entry==0)
rc=-1;
else
{
entry->userPvt=(void*)&item;
rc=0;
}
return rc;
}
int remove(const char* key,T*& item)
{
int rc;
if(find(key,item)<0)
rc=-1;
else
{
gphDelete(hash_table,(char*)key,hash_table);
rc=0;
}
return rc;
}
int find(const char* key, T*& item)
{
GPHENTRY* entry;
int rc;
entry=gphFind(hash_table,(char*)key,hash_table);
if(entry==0)
rc=-1;
else
{
item=(T*)entry->userPvt;
rc=0;
}
return rc;
}
};
template <class T>
class tsDLHashList : public tsDLList<T>
{
private:
tsHash<T> h;
friend class tsDLHashIter<T>;
public:
tsDLHashList(void) { }
~tsDLHashList(void) { }
int add(const char* key, T& item)
{
int rc;
rc=h.add(key,item);
tsDLList<T>::add(item);
return rc;
}
int find(const char* key, T*& item)
{
int rc=0;
if(h.find(key,item)!=0)
rc=-1;
return rc;
}
int remove(const char* key,T*& item)
{
int rc=0;
if(h.find(key,item)==0)
{
h.remove(key,item);
tsDLList<T>::remove(*item);
}
else
rc=-1;
return rc;
}
};
template <class T>
class tsDLHashNode : public tsDLNode<T>
{
public:
T* getNext(void) { return tsDLNode<T>::getNext(); }
T* getPrev(void) { return tsDLNode<T>::getPrev(); }
};
#endif