📄 gateserver.cc
字号:
/*************************************************************************\* Copyright (c) 2002 The University of Chicago, as Operator of Argonne* National Laboratory.* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron-* Strahlung mbH (BESSY).* Copyright (c) 2002 The Regents of the University of California, as* Operator of Los Alamos National Laboratory.* This file is distributed subject to a Software License Agreement found* in the file LICENSE that is included with this distribution. \*************************************************************************//*+********************************************************************* * * File: gateServer.cc * Project: CA Proxy Gateway * * Descr.: Gateway server class * - Provides the CAS virtual interface * - Manages Gateway lists and hashes, cleanup * - Server statistics variables * * Author(s): J. Kowalkowski, J. Anderson, K. Evans (APS) * R. Lange (BESSY) * *********************************************************************-*/#define DEBUG_FD 0#define DEBUG_SET_STAT 0#define DEBUG_PV_CON_LIST 0#define DEBUG_PV_LIST 0#define DEBUG_PV_CONNNECT_CLEANUP 0#define DEBUG_EXIST 0#define DEBUG_DELAY 0#define DEBUG_CLOCK 0#define DEBUG_ACCESS 0#define DEBUG_DESC 0#define DEBUG_FDMGR 0#define DEBUG_HISTORY 0#if DEBUG_HISTORY# define HISTNAME "GW:432:S05"# define HISTNUM 10#endif#ifdef __linux__#undef USE_LINUX_PROC_FOR_CPU#endif// DEBUG_TIMES prints a message every minute, which helps determine// when things happen.#define DEBUG_TIMES 0// This is the interval used with DEBUG_TIMES#define GATE_TIME_STAT_INTERVAL 60 /* sec */// This causes traces to be printed when exceptions occur. It// requires Base 3.15.#define DEBUG_EXCEPTION 0// Print only MAX_EXCEPTIONS exceptions unless EXCEPTION_RESET_TIME// has passed since the last one printed#define MAX_EXCEPTIONS 100#define EXCEPTION_RESET_TIME 3600 /* sec */// Interval for rate statistics in seconds#define RATE_STATS_INTERVAL 10u// Number of load elements to get in getloadavg. Should be 1, unless// the implementation in the Gateway is changed.#define N_LOAD 1#define ULONG_DIFF(n1,n2) (((n1) >= (n2))?((n1)-(n2)):((n1)+(ULONG_MAX-(n2))))#include <stdio.h>#include <stdlib.h>#include <string.h>#include <time.h>#include <signal.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#ifdef SOLARIS// Is in stdlib.h elsewhere, not available on WIN32#include <sys/loadavg.h>#endif#ifdef WIN32#else# include <unistd.h>#endif#include <gdd.h>#if DEBUG_EXCEPTION#include <epicsThrowTrace.h>#endif#include "gateResources.h"#include "gateServer.h"#include "gateAs.h"#include "gateVc.h"#include "gatePv.h"#include "gateStat.h"#ifdef __linux__# ifdef USE_LINUX_PROC_FOR_CPUstatic double linuxCpuTimeDiff(void);static pid_t gate_pid=0;# endifstatic clock_t mainClock=(clock_t)(-1);#endif// extern "C" wrappers needed by CA routines for callbacksextern "C" {#ifdef USE_FDS // file descriptor callback static void fdCB(void* ua, int fd, int opened) { gateServer::fdCB(ua, fd, opened); }#endif // exception callback static void exCB(EXCEPT_ARGS args) { gateServer::exCB(args); } // errlog listener callback static void errlogCB(void *userData, const char *message) { gateServer::errlogCB(userData,message); }}// ---------------------------- general main processing function -------------#ifndef WIN32extern "C" {typedef void (*SigFunc)(int);static SigFunc save_usr1=NULL;static SigFunc save_usr2=NULL;static void sig_pipe(int){ fprintf(stderr,"Got SIGPIPE interrupt!"); signal(SIGPIPE,sig_pipe);}static void sig_usr1(int x){ // Call a class function to get access to class variables gateServer::sig_usr1(x);}static void sig_usr2(int x){ // Call a class function to get access to class variables gateServer::sig_usr2(x);}} //extern "C"#endif// Static initializations// KE: Volatile because they can be set in signal handlers?volatile unsigned long gateServer::command_flag = 0;volatile unsigned long gateServer::report1_flag = 0;volatile unsigned long gateServer::report2_flag = 0;volatile unsigned long gateServer::report3_flag = 0;volatile unsigned long gateServer::newAs_flag = 0;volatile unsigned long gateServer::quit_flag = 0;volatile unsigned long gateServer::quitserver_flag = 0;void gateServer::mainLoop(void){ int not_done=1; // KE: ca_poll should be called every 100 ms // fdManager::process can block in select for delay time // so delay must be less than 100 ms to insure ca_poll gets called // if delay = 0.0 select will not block) double delay=.010; // (10 ms) printf("Statistics PV prefix is %s\n",stat_prefix); // Print if too many have been started recently printRecentHistory();#if DEBUG_TIMES epicsTime begin, end, lastPrintTime; double fdTime, pendTime, cleanTime; unsigned long nLoops=0; printf("%s gateServer::mainLoop: Starting and printing statistics every %d seconds\n", timeStamp(),GATE_TIME_STAT_INTERVAL); printf(" Key: [VcTotal|PvTotal|Active,Inactive|Connecting,Dead,Disconnected]\n");#endif#if DEBUG_EXCEPTION epicsThrowTraceEnable = true;#endif // Establish an errorLog listener errlogAddListener(::errlogCB,NULL); // This should create as since this is the first call to getAs() as=global_resources->getAs(); if(!as) { printf("%s gateServer::mainLoop: Failed to set up access security\n", timeStamp()); exit(-1); } gateAsCa(); // as->report(stdout);#ifndef WIN32 save_usr1=signal(SIGUSR1,::sig_usr1); save_usr2=signal(SIGUSR2,::sig_usr2);#if 0 // KE: This should be handled in both CA and CAS now using // osiSigPipeIgnore. There is no sigignore on Linux, so use // osiSigPipeIgnore if it has to be implemented here. SigFunc old=signal(SIGPIPE,sig_pipe); sigignore(SIGPIPE);#endif#endif time(&start_time); markNoRefreshSuppressed();#ifdef USE_LINUX_PROC_FOR_CPU // Save the pid. Could put this in a class variable. gate_pid=getpid(); if(!gate_pid) printf("gateServer::mainLoop: Could not get pid\n"); else printf("gateServer::mainLoop: gate_pid=%d\n",gate_pid);#endif // Initialize stat counters#if defined(RATE_STATS) || defined(CAS_DIAGNOSTICS) // Start a default timer queue (true to use shared queue, false to // have a private one) epicsTimerQueueActive &queue = epicsTimerQueueActive::allocate(true); gateRateStatsTimer *statTimer = new gateRateStatsTimer(queue, RATE_STATS_INTERVAL, this); if(statTimer) { // Call the expire routine to initialize it statTimer->expire(epicsTime::getCurrent()); // Then start the timer statTimer->start(); } else { printf("gateServer::mainLoop: Could not start statistics timer\n"); }#endif#if DEBUG_TIMES lastPrintTime=epicsTime::getCurrent(); fdTime=0.0; pendTime=0.0; cleanTime=0.0;#endif // Main loop while(not_done) {#if defined(RATE_STATS) || defined(CAS_DIAGNOSTICS) loop_count++;#endif#if DEBUG_TIMES nLoops++; begin=epicsTime::getCurrent();#endif // Process fileDescriptorManager.process(delay);#if DEBUG_TIMES end=epicsTime::getCurrent(); fdTime+=(end-begin); begin=end;#endif // Poll // KE: used to be checkEvent(); ca_poll();#if DEBUG_TIMES end=epicsTime::getCurrent(); pendTime+=(end-begin); begin=end;#endif // Cleanup connectCleanup(); inactiveDeadCleanup();#if DEBUG_TIMES end=epicsTime::getCurrent(); cleanTime+=(end-begin); if((end-lastPrintTime) > GATE_TIME_STAT_INTERVAL) {#ifdef STAT_PVS printf("%s gateServer::mainLoop: [%lu|%lu|%lu,%lu|%lu,%lu,%lu] " "loops: %lu process: %.3f pend: %.3f clean: %.3f\n", timeStamp(), total_vc,total_pv,total_active,total_inactive, total_connecting,total_dead,total_disconnected, nLoops, fdTime/(double)nLoops, pendTime/(double)nLoops, cleanTime/(double)nLoops);#else printf("%s gateServer::mainLoop: " "loops: %lu process: %.3f pend: %.3f clean: %.3f\n", timeStamp(), nLoops, fdTime/(double)nLoops, pendTime/(double)nLoops, cleanTime/(double)nLoops);#endif nLoops=0; lastPrintTime=epicsTime::getCurrent(); fdTime=0.0; pendTime=0.0; cleanTime=0.0; }#endif // Make sure messages get out fflush(stderr); fflush(stdout); // Do flagged reports if(command_flag) { gateCommands(global_resources->commandFile()); command_flag=0; setStat(statCommandFlag,0ul); } if(report1_flag) { report1(); report1_flag=0; setStat(statReport1Flag,0ul); } if(report2_flag) { report2(); report2_flag=0; setStat(statReport2Flag,0ul); } if(report3_flag) { report3(); report3_flag=0; setStat(statReport3Flag,0ul); } if(newAs_flag) { printf("%s Reading access security files\n",timeStamp()); newAs(); newAs_flag=0; setStat(statNewAsFlag,0ul); } if(quit_flag) { if(quit_flag == 1) { printf("%s Stopping (quitFlag was set to 1)\n",timeStamp()); fflush(stderr); fflush(stdout); } quit_flag=0; setStat(statQuitFlag,0ul); // return here will delete gateServer return; } if(quitserver_flag) { printf("%s Stopping server (quitServerFlag was set to 1)\n", timeStamp()); quitserver_flag=0; setStat(statQuitServerFlag,0ul); if(global_resources->getServerMode()) { // Has a server#ifndef WIN32 pid_t parentPid=getppid(); if(parentPid >= 0) { kill(parentPid,SIGTERM); } else { exit(0); }#endif } else { // Doesn't have a server, just quit exit(0); } }#ifdef __linux__# ifndef USE_LINUX_PROC_FOR_CPU // Get clock for this thread mainClock=clock();# endif#endif }}// This is a wrapper around caServer::generateBeaconAnomaly. Generate// a beacon anomaly as long as the time since the last one exceeds the// reconnect inhibit time. (The server may also prevent too frequent// beacon anomalies.) If it is not generated, mark it as suppressed,// but suppressed is not currently used. Note that one beacon anomaly// causes the clients to reissue search request sequences consisting// of 100 searches over a period of about 8 min. It is not necessary// to generate beacon anomalies much more frequently than this.void gateServer::generateBeaconAnomaly (){ if(timeSinceLastBeacon() >= global_resources->reconnectInhibit()) { caServer::generateBeaconAnomaly(); setFirstReconnectTime(); markNoRefreshSuppressed(); } else { // KE: Not used markRefreshSuppressed(); }}void gateServer::gateCommands(const char* cfile){ FILE* fp; char inbuf[200]; char *cmd,*ptr; int r1Flag=0,r2Flag=0,r3Flag=0,asFlag=0; if(cfile) { printf("%s Reading command file: %s\n",timeStamp(),cfile); errno=0;#ifdef RESERVE_FOPEN_FD fp=global_resources->fopen(cfile,"r");#else fp=fopen(cfile,"r");#endif if(fp == NULL) { fprintf(stderr,"%s Failed to open command file: %s\n", timeStamp(),cfile); fflush(stderr); perror("Reason"); fflush(stderr); return; } } else { return; } while(fgets(inbuf,sizeof(inbuf),fp)) { if((ptr=strchr(inbuf,'#'))) *ptr='\0'; cmd=strtok(inbuf," \t\n"); while(cmd) { if(strcmp(cmd,"R1")==0) r1Flag=1; else if(strcmp(cmd,"R2")==0) r2Flag=1; else if(strcmp(cmd,"R3")==0) r3Flag=1; else if(strcmp(cmd,"AS")==0) asFlag=1; else { printf(" Invalid command %s\n",cmd); fflush(stdout); } cmd=strtok(NULL," \t\n"); } } // Free the reserved file descriptor before we read access // security or write reports#ifdef RESERVE_FOPEN_FD global_resources->fclose(fp);#else fclose(fp);#endif // Now do the commands if(r1Flag) { report1(); fflush(stdout); } if(r2Flag) { report2(); fflush(stdout); } if(asFlag) { printf("%s Reading access security files\n",timeStamp()); newAs(); fflush(stdout); } // Do the report after the new access security if(r3Flag) { report3(); fflush(stdout); } return;}// We rely on CAS being non-threaded and CAC not calling our callbacks// while this routine completes, otherwise it should be lockedvoid gateServer::newAs(void)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -