diff --git a/src/cas/example/iocmonitor/Makefile b/src/cas/example/iocmonitor/Makefile new file mode 100644 index 000000000..e62475d85 --- /dev/null +++ b/src/cas/example/iocmonitor/Makefile @@ -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 + diff --git a/src/cas/example/iocmonitor/Makefile.Host b/src/cas/example/iocmonitor/Makefile.Host new file mode 100644 index 000000000..4434fd934 --- /dev/null +++ b/src/cas/example/iocmonitor/Makefile.Host @@ -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 + diff --git a/src/cas/example/iocmonitor/mon.cc b/src/cas/example/iocmonitor/mon.cc new file mode 100644 index 000000000..ae0608046 --- /dev/null +++ b/src/cas/example/iocmonitor/mon.cc @@ -0,0 +1,337 @@ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#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(xnext; + delete c; + c=p; + } + } + delete [] db; +} + +void addrDb::report(void) +{ + int i; + netNode* n; + for(i=0;inext) + 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; +} diff --git a/src/cas/example/iocmonitor/monAdl.cc b/src/cas/example/iocmonitor/monAdl.cc new file mode 100644 index 000000000..91fea5fe0 --- /dev/null +++ b/src/cas/example/iocmonitor/monAdl.cc @@ -0,0 +1,89 @@ + +#include +#include +#include + +#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;knext) + { + 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; +} + diff --git a/src/cas/example/iocmonitor/monNode.cc b/src/cas/example/iocmonitor/monNode.cc new file mode 100644 index 000000000..517b3beee --- /dev/null +++ b/src/cas/example/iocmonitor/monNode.cc @@ -0,0 +1,277 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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(xeventData(); + } +} + +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 +} + diff --git a/src/cas/example/iocmonitor/monNode.h b/src/cas/example/iocmonitor/monNode.h new file mode 100644 index 000000000..ff0d79167 --- /dev/null +++ b/src/cas/example/iocmonitor/monNode.h @@ -0,0 +1,109 @@ +#ifndef MONNODE_H +#define MONNODE_H + +#include + +#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 diff --git a/src/cas/example/iocmonitor/monServer.cc b/src/cas/example/iocmonitor/monServer.cc new file mode 100644 index 000000000..d6e51034f --- /dev/null +++ b/src/cas/example/iocmonitor/monServer.cc @@ -0,0 +1,352 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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;inext; + delete c; + c=p; + } + } + delete [] db; +} + +void monServer::report(FILE* fd) +{ + int i; + monNode* n; + for(i=0;inext) + 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;inext) + 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; +} + diff --git a/src/cas/example/iocmonitor/monServer.h b/src/cas/example/iocmonitor/monServer.h new file mode 100644 index 000000000..291f8bd22 --- /dev/null +++ b/src/cas/example/iocmonitor/monServer.h @@ -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 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 diff --git a/src/cas/example/iocmonitor/tsDLHashList.h b/src/cas/example/iocmonitor/tsDLHashList.h new file mode 100644 index 000000000..36b1bf993 --- /dev/null +++ b/src/cas/example/iocmonitor/tsDLHashList.h @@ -0,0 +1,106 @@ +#ifndef tsDLHashList_H +#define tsDLHashList_H + +extern "C" { +#include "gpHash.h" +} + +template +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 tsDLHashList : public tsDLList +{ +private: + tsHash 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 diff --git a/src/cas/example/iocmonitor/tsHash.h b/src/cas/example/iocmonitor/tsHash.h new file mode 100644 index 000000000..ea4c580ae --- /dev/null +++ b/src/cas/example/iocmonitor/tsHash.h @@ -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 tsHash +{ +private: + void* hash_table; + friend class tsDLHashIter; + +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 tsDLHashList : public tsDLList +{ +private: + tsHash h; + friend class tsDLHashIter; + +public: + tsDLHashList(void) { } + ~tsDLHashList(void) { } + + int add(const char* key, T& item) + { + int rc; + rc=h.add(key,item); + tsDLList::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::remove(*item); + } + else + rc=-1; + return rc; + } +}; + +template +class tsDLHashNode : public tsDLNode +{ +public: + T* getNext(void) { return tsDLNode::getNext(); } + T* getPrev(void) { return tsDLNode::getPrev(); } +}; + +#endif