📄 gateway.cc
字号:
fprintf(stderr,"\tinactive=%ld\n",gr->inactiveTimeout()); fprintf(stderr,"\tmask=%s\n",gr->eventMaskString());#ifndef WIN32 fprintf(stderr,"\tuser id=%ld\n",(long)getuid()); fprintf(stderr,"\tgroup id=%ld\n",(long)getgid());#endif if(gr->isReadOnly()) fprintf(stderr,"\tread only mode\n"); fprintf(stderr," (The default filenames depend on which " "files exist in home)\n"); return -1; } // Change to the specified home directory if(home_dir) { if(chdir(home_dir)<0) { perror("Change to home directory failed"); fprintf(stderr,"-->Bad home <%s>\n",home_dir); fflush(stderr); return -1; } } getcwd(home_directory,HOME_DIR_SIZE); // Get the default resources. The values of access_file, // pvlist_file, command_file, putlog_file, and report_file depend // on whether the default filenames exist in the cwd. global_resources = new gateResources; gateResources* gr = global_resources; // Set command-line values, order is somewhat important if(level) gr->setDebugLevel(level); if(read_only) gr->setReadOnly(); if(mask) gr->setEventMask(mask); if(connect_tout>=0) gr->setConnectTimeout(connect_tout); if(inactive_tout>=0) gr->setInactiveTimeout(inactive_tout); if(dead_tout>=0) gr->setDeadTimeout(dead_tout); if(disconnect_tout>=0) gr->setDisconnectTimeout(disconnect_tout); if(reconnect_tinhib>=0) gr->setReconnectInhibit(reconnect_tinhib); if(access_file) gr->setAccessFile(access_file); if(pvlist_file) gr->setListFile(pvlist_file); if(command_file) gr->setCommandFile(command_file); if(putlog_file) gr->setPutlogFile(putlog_file); if(report_file) gr->setReportFile(report_file);#ifndef WIN32 gr->setServerMode(make_server);#endif#ifndef WIN32 if(make_server) { // Start watcher process if(manage_gateway()) return 0; } else { parent_pid=getpid(); }#endif // ******************************************* // gets here if this is an interactive gateway // ******************************************* // Change stderr and stdout to the log file if(log_file || make_server) { if(log_file==NULL) log_file=GATE_LOG_FILE; time(&t);#ifndef WIN32 char *logerror=NULL; char *putlogerror=NULL; // Save log file if it exists if(stat(log_file,&sbuf)==0) { if(sbuf.st_size>0) { sprintf(logSaveFile,"%s.%lu",log_file,(unsigned long)t); if(link(log_file,logSaveFile)<0) { fprintf(stderr,"%s Failed to move old log to %s\n", timeStamp(),logSaveFile); char *error=strerror(errno); if(error && *error) { logerror=(char *)malloc(strlen(error)+1); if(logerror) { strcpy(logerror,error); fprintf(stderr," Reason: %s\n",logerror); } } } else unlink(log_file); } } // Save putlog file if it exists if(stat(putlog_file,&sbuf)==0) { if(sbuf.st_size>0) { sprintf(putlogSaveFile,"%s.%lu",putlog_file,(unsigned long)t); if(link(putlog_file,putlogSaveFile)<0) { fprintf(stderr,"%s Failed to move old putlog to %s\n", timeStamp(),putlogSaveFile); char *error=strerror(errno); if(error && *error) { putlogerror=(char *)malloc(strlen(error)+1); if(putlogerror) { strcpy(putlogerror,error); fprintf(stderr," Reason: %s\n",putlogerror); } } } else unlink(putlog_file); } }#endif // Redirect stdout and stderr // Open it and close it to empty it (Necessary on WIN32, // apparently not necessary on Solaris) FILE *fp=fopen(log_file,"w"); if(fp == NULL) { fprintf(stderr,"Cannot open %s\n",log_file); fflush(stderr); } else { fclose(fp); } // KE: This was formerly "w" instead of "a" and stderr was // overwriting the top of the log file if((freopen(log_file,"a",stderr))==NULL ) { fprintf(stderr,"Redirect of stderr to file %s failed\n",log_file); fflush(stderr); } if((freopen(log_file,"a",stdout))==NULL ) { fprintf(stderr,"Redirect of stdout to file %s failed\n",log_file); fflush(stderr); }#ifndef WIN32 // Repeat error messages to log if(logerror) { fprintf(stderr,"%s Failed to move old log to %s\n", timeStamp(),logSaveFile); if(logerror) { fprintf(stderr," Reason: %s\n",logerror); fflush(stderr); free(logerror); } } if(putlogerror) { fprintf(stderr,"%s Failed to move old putlog to %s\n", timeStamp(),putlogSaveFile); if(putlogerror) { fprintf(stderr," Reason: %s\n",putlogerror); fflush(stderr); free(putlogerror); } }#endif } else { log_file="<terminal>"; } gr->setUpAccessSecurity(); if(gr->debugLevel()>10) { fprintf(stderr,"\noption dump:\n"); fprintf(stderr," home = <%s>\n",home_directory); fprintf(stderr," log file = <%s>\n",log_file); fprintf(stderr," access file = <%s>\n",gr->accessFile()); fprintf(stderr," list file = <%s>\n",gr->listFile()); fprintf(stderr," command file = <%s>\n",gr->commandFile()); fprintf(stderr," putlog file = <%s>\n",gr->putlogFile()); fprintf(stderr," report file = <%s>\n",gr->reportFile()); fprintf(stderr," debug level = %d\n",gr->debugLevel()); fprintf(stderr," connect timeout = %ld\n",gr->connectTimeout()); fprintf(stderr," disconnect timeout = %ld\n",gr->disconnectTimeout()); fprintf(stderr," reconnect inhibit time = %ld\n",gr->reconnectInhibit()); fprintf(stderr," inactive timeout = %ld\n",gr->inactiveTimeout()); fprintf(stderr," dead timeout = %ld\n",gr->deadTimeout()); fprintf(stderr," event mask = %s\n",gr->eventMaskString());#ifndef WIN32 fprintf(stderr," user id= %ld\n",(long)getuid()); fprintf(stderr," group id= %ld\n",(long)getgid());#endif if(gr->isReadOnly()) { fprintf(stderr," read only mode\n"); } fflush(stderr); } // Open putlog file. This could be done the first time it is // used, but we want to open it and keep it open because of // possible problems with FOPEN_MAX. if(putlog_file) { FILE *fp=fopen(putlog_file,"w"); if(fp == NULL) { fprintf(stderr,"Cannot open %s\n",putlog_file); fflush(stderr); } gr->setPutlogFp(fp); } startEverything(stat_prefix); delete global_resources; return 0;}static void stopEverything(void){ if(server) { // Set the flag and let it stop itself. This will cause it to // clean up. Setting quit_flag to 2 keeps it from printing a // message in the main loop. server->setQuitFlag(2u); } else { exit(0); }}#define pr fprintfstatic void print_instructions(void){ pr(stderr,"-debug value: Enter value between 0-100. 50 gives lots of\n"); pr(stderr," info, 1 gives small amount.\n\n"); pr(stderr,"-pvlist file_name: Name of file with all the allowed PVs in it\n"); pr(stderr," See the sample file gateway.pvlist in the source distribution\n"); pr(stderr," for a description of how to create this file.\n"); pr(stderr,"-access file_name: Name of file with all the EPICS access\n"); pr(stderr," security rules in it. PVs in the pvlist file use groups\n"); pr(stderr," and rules defined in this file.\n"); pr(stderr,"-log file_name: Name of file where all messages from the\n"); pr(stderr," gateway go, including stderr and stdout.\n\n"); pr(stderr,"-command file_name: Name of file where gateway command(s) go\n"); pr(stderr," Commands are executed when a USR1 signal is sent to gateway.\n\n"); pr(stderr,"-putlog file_name: Name of file where gateway put logging goes.\n"); pr(stderr," Put logging is specified with TRAPWRITE in the access file.\n\n"); pr(stderr,"-report file_name: Name of file where gateway reports go.\n"); pr(stderr," Reports are appended to this file if it exists.\n\n"); pr(stderr,"-home directory: Home directory where all your gateway\n"); pr(stderr," configuration files are kept where log and command files go.\n\n"); pr(stderr,"-sip IP_address: IP address that gateway's CA server listens\n"); pr(stderr," for PV requests. Sets env variable EPICS_CAS_INTF_ADDR.\n\n"); pr(stderr,"-signore IP_address_list: IP address that gateway's CA server\n"); pr(stderr," ignores. Sets env variable EPICS_CAS_IGNORE_ADDR_LIST.\n\n"); pr(stderr,"-cip IP_address_list: IP address list that the gateway's CA\n"); pr(stderr," client uses to find the real PVs. See CA reference manual.\n"); pr(stderr," This sets environment variables EPICS_CA_AUTO_LIST=NO and\n"); pr(stderr," EPICS_CA_ADDR_LIST.\n\n"); pr(stderr,"-sport CA_server_port: The port which the gateway's CA server\n"); pr(stderr," uses to listen for PV requests. Sets environment variable\n"); pr(stderr," EPICS_CAS_SERVER_PORT.\n\n"); pr(stderr,"-cport CA_client_port: The port which the gateway's CA client\n"); pr(stderr," uses to find the real PVs. Sets environment variable\n"); pr(stderr," EPICS_CA_SERVER_PORT.\n\n"); pr(stderr,"-connect_timeout seconds: The amount of time that the\n"); pr(stderr," gateway will allow a PV search to continue before marking the\n"); pr(stderr," PV as being not found.\n\n"); pr(stderr,"-inactive_timeout seconds: The amount of time that the gateway\n"); pr(stderr," will hold the real connection to an unused PV. If no gateway\n"); pr(stderr," clients are using the PV, the real connection will still be\n"); pr(stderr," held for this long.\n\n"); pr(stderr,"-dead_timeout seconds: The amount of time that the gateway\n"); pr(stderr," will hold requests for PVs that are not found on the real\n"); pr(stderr," network that the gateway is using. Even if a client's\n"); pr(stderr," requested PV is not found on the real network, the gateway\n"); pr(stderr," marks the PV dead, holds the request and continues trying\n"); pr(stderr," to connect for this long.\n\n"); pr(stderr,"-disconnect_timeout seconds: The amount of time that the gateway\n"); pr(stderr," will hold requests for PVs that were connected but have been\n"); pr(stderr," disconnected. When a disconnected PV reconnects, the gateway will\n"); pr(stderr," broadcast a beacon signal to inform the clients that they may\n"); pr(stderr," reconnect to the gateway.\n\n"); pr(stderr,"-reconnect_inhibit seconds: The minimum amount of time between\n"); pr(stderr," additional beacons that the gateway will send to its clients\n"); pr(stderr," when channels from the real network reconnect.\n\n"); pr(stderr,"-server: Start as server. Detach from controlling terminal\n"); pr(stderr," and start a daemon that watches the gateway and automatically\n"); pr(stderr," restarts it if it dies.\n"); pr(stderr,"-mask event_mask: Event mask that is used for connections on the\n"); pr(stderr," real network: use any combination of v (value), a (alarm), l (log).\n"); pr(stderr," Default is va (forward value and alarm change events).\n"); pr(stderr,"-prefix string: Set the prefix for the gateway statistics PVs.\n"); pr(stderr," Defaults to the hostname the gateway is running on.\n"); pr(stderr,"-uid number: Run the server with this id, server does a\n"); pr(stderr," setuid(2) to this user id number.\n\n"); pr(stderr,"-gid number: Run the server with this id, server does a\n"); pr(stderr," setgid(2) to this group id number.\n\n");}#ifndef WIN32// -------------------------------------------------------------------// part that watches the gateway process and ensures that it stays upstatic int manage_gateway(void){ time_t t,prevt=0; int rc; int i; // Initialize time array for(i=0; i < NRESTARTS; i++) { startTime[i]=0; } save_chld=signal(SIGCHLD,sig_chld); save_hup=signal(SIGHUP,sig_stop); save_term=signal(SIGTERM,sig_stop); save_int=signal(SIGINT,sig_stop); // Fork. Parent will exit, child will be a session leader pid_t pid=fork(); switch(pid) { case -1: // Error perror("Cannot create gateway processes"); return -1; // Will cause main to return 0; case 0: // Child // Make this process a session leader // KE: Not sure why this is necessary // Used to use setgrp() for UNIX, else setgrp(0,0) // but this failed for Darwin setpgid(0,0); // Make a new session setsid(); break; default: // Parent return 1; // Will cause main to return 0; } parent_pid=getpid(); // do { // Don't allow runaway restarts time(&t); if(nStart < NRESTARTS) { startTime[nStart]=t; nStart++; } else { // Check the interval since NRESTARTSth previous start if(t-startTime[0] < RESTART_INTERVAL) { // Too many recent starts fprintf(stderr, "\nGateway: There were too many [%d] restarts in the last %d seconds\n", NRESTARTS+1,RESTART_INTERVAL); fprintf(stderr,"Aborting Gateway ServerPID %d\n",(int)parent_pid); exit(1); } else { // Reset the start times for(i=0; i < NRESTARTS-1; i++) { startTime[i]=startTime[i+1]; } nStart=NRESTARTS; startTime[NRESTARTS-1]=t; } } // Don't respawn faster than every RESTART_DELAY seconds if((t-prevt) < RESTART_DELAY) sleep(RESTART_DELAY); prevt=t; // Fork. Parent will be the server and child will be the // gateway. Parent will pause until receiving a signal that is // handled by sig_stop, which sets death_flag to 1. switch(gate_pid=fork()) { case -1: // Error perror("Cannot create gateway processes"); gate_pid=0; break; case 0: // Child break; default: // Pause until we receive a signal. If the signal is HUP, // TERM, or INT (handled by sig_stop), then death_flag is // set to 1 andc the server exits. If it is SIG_CHLD, // then a new fork occurs after executing sig_chld, which // waits for all information to come in. Note that any // other non-ignored signal will end the pause and fork a // new gateway, if there are any. pause(); break; } } while(gate_pid && death_flag==0); if(death_flag || gate_pid==-1) rc=1; else rc=0; return rc;}#endif //#ifdef WIN32static int setEnv(const char *var, const char *val, char **envString){ int len=strlen(var)+strlen(val)+2; *envString=(char *)malloc(len); if(!*envString) { fprintf(stderr,"Memory allocation error for %s",var); return 1; } sprintf(*envString,"%s=%s",var,val);#if 0 // There is no putenv on Linux int status=putenv(*envString); if(status) { fprintf(stderr,"putenv failed for:\n %s\n",*envString); }#else epicsEnvSet(var,val);#endif return 0;}static int setEnv(const char *var, int ival, char **envString){ // Allow 40 for size of ival int len=strlen(var)+40+2; *envString=(char *)malloc(len); if(!*envString) { fprintf(stderr,"Memory allocation error for %s",var); return 1; } sprintf(*envString,"%s=%d",var,ival);#if 0 // There is no putenv on Linux int status=putenv(*envString); if(status) { fprintf(stderr,"putenv failed for:\n %s\n",*envString); }#else char *pVal=strchr(*envString,'='); if(!pVal || !(pVal+1)) { epicsEnvSet(var,""); } else { epicsEnvSet(var,pVal+1); }#endif return 0;}void printRecentHistory(void){#ifndef WIN32 int nStarts=0; int i; if(nStart < 1) return; for(i=0; i < nStart-1; i++) { if((startTime[nStart-1]-startTime[i]) < RESTART_INTERVAL) { nStarts++; } } if(nStarts) { fflush(stderr); printf("There have been %d restarts for serverPID %d " "in the last %d seconds\n", nStarts+1,parent_pid,RESTART_INTERVAL); printf(" Only %d restarts are allowed in this interval\n",NRESTARTS); fflush(stdout); }#endif}static void printEnv(FILE *fp, const char *var){ if(!fp || !var) return; char *value=getenv(var); fprintf(fp,"%s=%s\n", var, value?value:"Not specified");}/* **************************** Emacs Editing Sequences ***************** *//* Local Variables: *//* tab-width: 4 *//* c-basic-offset: 4 *//* c-comment-only-line-offset: 0 *//* c-file-offsets: ((substatement-open . 0) (label . 0)) *//* End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -