Files
epics-base/src/libvxWorks/iocLogClient.c
1996-03-29 22:35:56 +00:00

523 lines
9.4 KiB
C
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* $Id$ */
/*
*
* Author: Jeffrey O. Hill
* Date: 080791
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
* NOTES:
*
* Modification Log:
* -----------------
* .00 joh 080791 Created
* .01 joh 081591 Added epics env config
* .02 joh 011995 Allow stdio also
* $Log$
*/
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <assert.h>
#include <socket.h>
#include <in.h>
#include <ioLib.h>
#include <taskLib.h>
#include <logLib.h>
#include <inetLib.h>
#include <sockLib.h>
#include <sysLib.h>
#include <semLib.h>
#include <rebootLib.h>
#include <epicsPrint.h>
#include <envDefs.h>
#include <task_params.h>
/*
* for use by the vxWorks shell
*/
int iocLogDisable = 0;
LOCAL FILE *iocLogFile = NULL;
LOCAL int iocLogFD = ERROR;
LOCAL unsigned iocLogTries = 0U;
LOCAL unsigned iocLogConnectCount = 0U;
LOCAL long ioc_log_port;
LOCAL struct in_addr ioc_log_addr;
int iocLogInit(void);
LOCAL int getConfig(void);
LOCAL void failureNotify(ENV_PARAM *pparam);
LOCAL void logClientShutdown(void);
LOCAL void logRestart(void);
LOCAL int iocLogAttach(void);
LOCAL void logClientRollLocalPort(void);
LOCAL SEM_ID iocLogMutex; /* protects stdio */
LOCAL SEM_ID iocLogSignal; /* reattach to log server */
#define EPICS_IOC_LOG_CLIENT_CONNECT_TMO 5 /* sec */
/*
* iocLogInit()
*/
int iocLogInit(void)
{
int status;
int attachStatus;
int options;
if(iocLogDisable){
return OK;
}
/*
* dont init twice
*/
if (iocLogMutex) {
return OK;
}
options = SEM_Q_PRIORITY|SEM_DELETE_SAFE|SEM_INVERSION_SAFE;
iocLogMutex = semMCreate(options);
if(!iocLogMutex){
return ERROR;
}
iocLogSignal = semBCreate(SEM_Q_PRIORITY, SEM_EMPTY);
if(!iocLogSignal){
return ERROR;
}
attachStatus = iocLogAttach();
status = rebootHookAdd((FUNCPTR)logClientShutdown);
if (status<0) {
printf("Unable to add log server reboot hook\n");
}
status = taskSpawn(
LOG_RESTART_NAME,
LOG_RESTART_PRI,
LOG_RESTART_OPT,
LOG_RESTART_STACK,
(FUNCPTR)logRestart,
0,0,0,0,0,0,0,0,0,0);
if (status<0) {
printf("Unable to start log server connection watch dog\n");
}
return attachStatus;
}
/*
* iocLogAttach()
*/
LOCAL int iocLogAttach(void)
{
int sock;
struct sockaddr_in addr;
int status;
int optval;
struct timeval tval;
FILE *fp;
status = getConfig();
if(status<0){
printf (
"iocLogClient: EPICS environment under specified\n");
printf ("iocLogClient: failed to initialize\n");
return ERROR;
}
/* allocate a socket */
sock = socket(AF_INET, /* domain */
SOCK_STREAM, /* type */
0); /* deflt proto */
if (sock < 0){
printf ("iocLogClient: no socket error %s\n",
strerror(errno));
return ERROR;
}
/* set socket domain */
addr.sin_family = AF_INET;
/* set the port */
addr.sin_port = htons(ioc_log_port);
/* set the addr */
addr.sin_addr.s_addr = ioc_log_addr.s_addr;
/* connect */
#ifdef vxWorks
tval.tv_sec = EPICS_IOC_LOG_CLIENT_CONNECT_TMO;
tval.tv_usec = 0;
status = connectWithTimeout(
sock,
(struct sockaddr *)&addr,
sizeof(addr),
&tval);
#else
status = connect(
sock,
(struct sockaddr *)&addr,
sizeof(addr));
#endif
if (status < 0) {
/*
* only print a message if it is the first try and
* we havent got a valid connection already
*/
if (iocLogTries==0U && iocLogFD==ERROR) {
char name[INET_ADDR_LEN];
inet_ntoa_b(addr.sin_addr, name);
printf(
"iocLogClient: unable to connect to %s port %d because \"%s\"\n",
name,
addr.sin_port,
strerror(errno));
}
iocLogTries++;
close(sock);
return ERROR;
}
iocLogTries=0U;
iocLogConnectCount++;
/*
* discover that the connection has expired
* (after a long delay)
*/
optval = TRUE;
status = setsockopt( sock,
SOL_SOCKET,
SO_KEEPALIVE,
(char *) &optval,
sizeof(optval));
if(status<0){
printf ("iocLogClient: %s\n", strerror(errno));
close(sock);
return ERROR;
}
/*
* set how long we will wait for the TCP state machine
* to clean up when we issue a close(). This
* guarantees that messages are serialized when we
* switch connections.
*/
{
struct linger lingerval;
lingerval.l_onoff = TRUE;
lingerval.l_linger = 60*5;
status = setsockopt( sock,
SOL_SOCKET,
SO_LINGER,
(char *) &lingerval,
sizeof(lingerval));
if(status<0){
printf ("iocLogClient: %s\n", strerror(errno));
close(sock);
return ERROR;
}
}
fp = fdopen (sock, "a");
/*
* mutex on
*/
status = semTake(iocLogMutex, WAIT_FOREVER);
assert(status==OK);
/*
* close any preexisting connection to the log server
*/
if (iocLogFile) {
logFdDelete(iocLogFD);
fclose(iocLogFile);
iocLogFile = NULL;
iocLogFD = ERROR;
}
else if (iocLogFD!=ERROR) {
logFdDelete(iocLogFD);
close(iocLogFD);
iocLogFD = ERROR;
}
/*
* export the new connection
*/
iocLogFD = sock;
logFdAdd (iocLogFD);
iocLogFile = fp;
/*
* mutex off
*/
status = semGive(iocLogMutex);
assert(status==OK);
return OK;
}
/*
* logRestart()
*/
LOCAL void logRestart(void)
{
int status;
int reattach;
int delay = LOG_RESTART_DELAY;
/*
* roll the local port forward so that we dont collide
* with the first port assigned when we reboot
*/
logClientRollLocalPort();
while (1) {
semTake(iocLogSignal, delay);
/*
* mutex on
*/
status = semTake(iocLogMutex, WAIT_FOREVER);
assert(status==OK);
if (iocLogFile==NULL) {
reattach = TRUE;
}
else {
reattach = ferror(iocLogFile);
}
/*
* mutex off
*/
status = semGive(iocLogMutex);
assert(status==OK);
if (reattach==FALSE) {
continue;
}
/*
* restart log server
*/
iocLogConnectCount = 0U;
logClientRollLocalPort();
}
}
/*
* logClientRollLocalPort()
*/
LOCAL void logClientRollLocalPort(void)
{
int status;
/*
* roll the local port forward so that we dont collide
* with it when we reboot
*/
while (iocLogConnectCount<10U) {
/*
* switch to a new log server connection
*/
status = iocLogAttach();
if (status==OK) {
/*
* only print a message after the first connect
*/
if (iocLogConnectCount==1U) {
printf(
"iocLogClient: reconnected to the log server\n");
}
}
else {
/*
* if we cant connect then we will roll
* the port later when we can
* (we must not spin on connect fail)
*/
if (errno!=ETIMEDOUT) {
return;
}
}
}
}
/*
* logClientShutdown()
*/
LOCAL void logClientShutdown(void)
{
if (iocLogFD!=ERROR) {
/*
* unfortunately this does not currently work because WRS
* runs the reboot hooks in the order that
* they are installed (and the network is already shutdown
* by the time we get here)
*/
#if 0
/*
* this aborts the connection because we
* have specified a nill linger interval
*/
printf("log client: lingering for connection close...");
close(iocLogFD);
printf("done\n");
#endif
}
}
/*
*
* getConfig()
* Get Server Configuration
*
*
*/
LOCAL int getConfig(void)
{
long status;
status = envGetLongConfigParam(
&EPICS_IOC_LOG_PORT,
&ioc_log_port);
if(status<0){
failureNotify(&EPICS_IOC_LOG_PORT);
return ERROR;
}
status = envGetInetAddrConfigParam(
&EPICS_IOC_LOG_INET,
&ioc_log_addr);
if(status<0){
failureNotify(&EPICS_IOC_LOG_INET);
return ERROR;
}
return OK;
}
/*
* failureNotify()
*/
LOCAL void failureNotify(ENV_PARAM *pparam)
{
printf(
"IocLogClient: EPICS environment variable \"%s\" undefined\n",
pparam->name);
}
/*
* iocLogPrintf()
*/
int iocLogPrintf(const char *pFormat, ...)
{
va_list pvar;
va_start (pvar, pFormat);
return iocLogVPrintf (pFormat, pvar);
}
/*
* iocLogVPrintf()
*/
int iocLogVPrintf(const char *pFormat, va_list pvar)
{
int status;
int semStatus;
if (!pFormat || iocLogDisable) {
return 0;
}
/*
* Check for init
*/
if (!iocLogMutex) {
status = iocLogInit();
if (status) {
return 0;
}
}
/*
* mutex on
*/
semStatus = semTake(iocLogMutex, WAIT_FOREVER);
assert(semStatus==OK);
if (iocLogFile) {
status = vfprintf(iocLogFile, pFormat, pvar);
if (status>0) {
status = fflush(iocLogFile);
}
if (status<0) {
logFdDelete(iocLogFD);
fclose(iocLogFile);
iocLogFile = NULL;
iocLogFD = ERROR;
semStatus = semGive(iocLogSignal);
assert(semStatus==OK);
}
}
else {
status = EOF;
}
/*
* mutex off
*/
semStatus = semGive(iocLogMutex);
assert(semStatus==OK);
return status;
}