Files
pcas/src/cas/example/iocmonitor/monServer.cc
T
1998-12-19 00:04:53 +00:00

362 lines
6.5 KiB
C++

// Author: Jim Kowalkowski
// Date: 1/97
//
// $Id$
// $Log$
// Revision 1.2 1997/05/13 14:23:02 jbk
// added comments at top
//
#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::pvAttach(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;
}