diff --git a/src/libCom/logClient/iocLog.c b/src/libCom/logClient/iocLog.c index e62da2050..d835e3c2c 100644 --- a/src/libCom/logClient/iocLog.c +++ b/src/libCom/logClient/iocLog.c @@ -18,8 +18,10 @@ #define epicsExportSharedSymbols #include "envDefs.h" +#include "errlog.h" #include "logClient.h" #include "iocLog.h" +#include "epicsExit.h" int iocLogDisable = 0; @@ -74,6 +76,14 @@ void epicsShareAPI epicsShareAPI iocLogFlush (void) } } +/* + * logClientDestroy() + */ +static void iocLogClientDestroy (logClientId id) +{ + errlogRemoveListener (logClientSendMessage); +} + /* * iocLogClientInit() */ @@ -89,6 +99,10 @@ static logClientId iocLogClientInit (void) return NULL; } id = logClientCreate (addr, port); + if (id != NULL) { + errlogAddListener (logClientSendMessage, id); + epicsAtExit (iocLogClientDestroy, id); + } return id; } diff --git a/src/libCom/logClient/logClient.c b/src/libCom/logClient/logClient.c index 99ee671d9..0056a21fe 100644 --- a/src/libCom/logClient/logClient.c +++ b/src/libCom/logClient/logClient.c @@ -44,6 +44,7 @@ typedef struct { SOCKET sock; epicsThreadId restartThreadId; epicsEventId stateChangeNotify; + epicsEventId shutdownNotify; unsigned connectCount; unsigned nextMsgIndex; unsigned connected; @@ -53,7 +54,6 @@ typedef struct { } logClient; static const double LOG_RESTART_DELAY = 5.0; /* sec */ -static const double LOG_SERVER_CREATE_CONNECT_SYNC_TIMEOUT = 5.0; /* sec */ static const double LOG_SERVER_SHUTDOWN_TIMEOUT = 30.0; /* sec */ /* @@ -84,8 +84,6 @@ static void logClientClose ( logClient *pClient ) pClient->sock = INVALID_SOCKET; } - pClient->nextMsgIndex = 0u; - memset ( pClient->msgBuf, '\0', sizeof ( pClient->msgBuf ) ); pClient->connected = 0u; /* @@ -113,6 +111,7 @@ static void logClientDestroy (logClientId id) epicsMutexMustLock ( pClient->mutex ); pClient->shutdown = 1u; epicsMutexUnlock ( pClient->mutex ); + epicsEventSignal ( pClient->shutdownNotify ); /* unblock log client thread blocking in send() or connect() */ interruptInfo = @@ -154,13 +153,11 @@ static void logClientDestroy (logClientId id) return; } - errlogRemoveListeners ( logClientSendMessage, (void *) pClient ); - logClientClose ( pClient ); epicsMutexDestroy ( pClient->mutex ); - epicsEventDestroy ( pClient->stateChangeNotify ); + epicsEventDestroy ( pClient->shutdownNotify ); free ( pClient ); } @@ -176,57 +173,23 @@ static void sendMessageChunk(logClient * pClient, const char * message) { unsigned msgBufBytesLeft = sizeof ( pClient->msgBuf ) - pClient->nextMsgIndex; - if ( strSize > msgBufBytesLeft ) { - int status; - - if ( ! pClient->connected ) { - break; - } - - if ( msgBufBytesLeft > 0u ) { - memcpy ( & pClient->msgBuf[pClient->nextMsgIndex], - message, msgBufBytesLeft ); - pClient->nextMsgIndex += msgBufBytesLeft; - strSize -= msgBufBytesLeft; - message += msgBufBytesLeft; - } - - status = send ( pClient->sock, pClient->msgBuf, - pClient->nextMsgIndex, 0 ); - if ( status > 0 ) { - unsigned nSent = (unsigned) status; - if ( nSent < pClient->nextMsgIndex ) { - unsigned newNextMsgIndex = pClient->nextMsgIndex - nSent; - memmove ( pClient->msgBuf, & pClient->msgBuf[nSent], - newNextMsgIndex ); - pClient->nextMsgIndex = newNextMsgIndex; - } - else { - pClient->nextMsgIndex = 0u; - } - } - else { - if ( ! pClient->shutdown ) { - char sockErrBuf[64]; - if ( status ) { - epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); - } - else { - strcpy ( sockErrBuf, "server initiated disconnect" ); - } - fprintf ( stderr, "log client: lost contact with log server at \"%s\" because \"%s\"\n", - pClient->name, sockErrBuf ); - } - logClientClose ( pClient ); - break; - } + if ( msgBufBytesLeft < strSize && pClient->nextMsgIndex != 0u && pClient->connected) + { + /* buffer is full, thus flush it */ + logClientFlush ( pClient ); + msgBufBytesLeft = sizeof ( pClient->msgBuf ) - pClient->nextMsgIndex; } - else { - memcpy ( & pClient->msgBuf[pClient->nextMsgIndex], - message, strSize ); - pClient->nextMsgIndex += strSize; + if ( msgBufBytesLeft == 0u ) { + fprintf ( stderr, "log client: messages to \"%s\" are lost\n", + pClient->name ); break; } + if ( msgBufBytesLeft > strSize) msgBufBytesLeft = strSize; + memcpy ( & pClient->msgBuf[pClient->nextMsgIndex], + message, msgBufBytesLeft ); + pClient->nextMsgIndex += msgBufBytesLeft; + strSize -= msgBufBytesLeft; + message += msgBufBytesLeft; } } @@ -255,28 +218,38 @@ void epicsShareAPI logClientSend ( logClientId id, const char * message ) void epicsShareAPI logClientFlush ( logClientId id ) { + unsigned nSent = 0u; + logClient * pClient = ( logClient * ) id; - if ( ! pClient ) { + if ( ! pClient || ! pClient->connected ) { return; } epicsMutexMustLock ( pClient->mutex ); - while ( pClient->nextMsgIndex && pClient->connected ) { - int status = send ( pClient->sock, pClient->msgBuf, - pClient->nextMsgIndex, 0 ); + while (1) { + struct timeval timeout = { 0, 0 }; + fd_set set; + char buffer[256]; + + FD_ZERO ( &set ); + FD_SET ( pClient->sock, &set ); + if ( select ( pClient->sock + 1, &set, NULL, NULL, &timeout ) == 0) + break; + if ( recv ( pClient->sock, buffer, sizeof ( buffer ), 0 ) == 0 ) { + fprintf ( stderr, "log client: connection closed by server \"%s\"\n", + pClient->name ); + logClientClose ( pClient ); + break; + } + } + + while ( nSent < pClient->nextMsgIndex && pClient->connected ) { + int status = send ( pClient->sock, pClient->msgBuf + nSent, + pClient->nextMsgIndex - nSent, 0 ); if ( status > 0 ) { - unsigned nSent = (unsigned) status; - if ( nSent < pClient->nextMsgIndex ) { - unsigned newNextMsgIndex = pClient->nextMsgIndex - nSent; - memmove ( pClient->msgBuf, & pClient->msgBuf[nSent], - newNextMsgIndex ); - pClient->nextMsgIndex = newNextMsgIndex; - } - else { - pClient->nextMsgIndex = 0u; - } + nSent += (unsigned) status; } else { if ( ! pClient->shutdown ) { @@ -294,6 +267,11 @@ void epicsShareAPI logClientFlush ( logClientId id ) break; } } + pClient->nextMsgIndex -= nSent; + if ( nSent > 0 && pClient->nextMsgIndex > 0 ) { + memmove ( pClient->msgBuf, & pClient->msgBuf[nSent], + pClient->nextMsgIndex ); + } epicsMutexUnlock ( pClient->mutex ); } @@ -398,20 +376,6 @@ static void logClientConnect (logClient *pClient) fprintf (stderr, "log client: unable to enable keepalive option because \"%s\"\n", sockErrBuf); } - /* - * we don't need full-duplex (clients only write), so we shutdown - * the read end of our socket - */ - status = shutdown (pClient->sock, SHUT_RD); - if (status < 0) { - char sockErrBuf[64]; - epicsSocketConvertErrnoToString ( - sockErrBuf, sizeof ( sockErrBuf ) ); - fprintf (stderr, "%s:%d shutdown(%d,SHUT_RD) error was \"%s\"\n", - __FILE__, __LINE__, pClient->sock, sockErrBuf); - /* not fatal (although it shouldn't happen) */ - } - /* * set how long we will wait for the TCP state machine * to clean up when we issue a close(). This @@ -457,14 +421,10 @@ static void logClientRestart ( logClientId id ) epicsMutexUnlock ( pClient->mutex ); - if ( isConn ) { - logClientFlush ( pClient ); - } - else { - logClientConnect ( pClient ); - } - - epicsThreadSleep ( LOG_RESTART_DELAY ); + if ( ! isConn ) logClientConnect ( pClient ); + logClientFlush ( pClient ); + + epicsEventWaitWithTimeout ( pClient->shutdownNotify, LOG_RESTART_DELAY); epicsMutexMustLock ( pClient->mutex ); } @@ -480,9 +440,7 @@ static void logClientRestart ( logClientId id ) logClientId epicsShareAPI logClientCreate ( struct in_addr server_addr, unsigned short server_port) { - epicsTimeStamp begin, current; logClient *pClient; - double diff; pClient = calloc (1, sizeof (*pClient)); if (pClient==NULL) { @@ -507,14 +465,22 @@ logClientId epicsShareAPI logClientCreate ( pClient->shutdownConfirm = 0; epicsAtExit (logClientDestroy, (void*) pClient); - + pClient->stateChangeNotify = epicsEventCreate (epicsEventEmpty); if ( ! pClient->stateChangeNotify ) { epicsMutexDestroy ( pClient->mutex ); free ( pClient ); return NULL; } - + + pClient->shutdownNotify = epicsEventCreate (epicsEventEmpty); + if ( ! pClient->shutdownNotify ) { + epicsMutexDestroy ( pClient->mutex ); + epicsEventDestroy ( pClient->stateChangeNotify ); + free ( pClient ); + return NULL; + } + pClient->restartThreadId = epicsThreadCreate ( "logRestart", epicsThreadPriorityLow, epicsThreadGetStackSize(epicsThreadStackSmall), @@ -522,35 +488,12 @@ logClientId epicsShareAPI logClientCreate ( if ( pClient->restartThreadId == NULL ) { epicsMutexDestroy ( pClient->mutex ); epicsEventDestroy ( pClient->stateChangeNotify ); + epicsEventDestroy ( pClient->shutdownNotify ); free (pClient); fprintf(stderr, "log client: unable to start log client connection watch dog thread\n"); return NULL; } - /* - * attempt to synchronize with circuit connect - */ - epicsTimeGetCurrent ( & begin ); - epicsMutexMustLock ( pClient->mutex ); - do { - epicsMutexUnlock ( pClient->mutex ); - epicsEventWaitWithTimeout ( - pClient->stateChangeNotify, - LOG_SERVER_CREATE_CONNECT_SYNC_TIMEOUT / 10.0 ); - epicsTimeGetCurrent ( & current ); - diff = epicsTimeDiffInSeconds ( & current, & begin ); - epicsMutexMustLock ( pClient->mutex ); - } - while ( ! pClient->connected && diff < LOG_SERVER_CREATE_CONNECT_SYNC_TIMEOUT ); - epicsMutexUnlock ( pClient->mutex ); - - if ( ! pClient->connected ) { - fprintf (stderr, "log client create: timed out synchronizing with circuit connect to \"%s\" after %.1f seconds\n", - pClient->name, LOG_SERVER_CREATE_CONNECT_SYNC_TIMEOUT ); - } - - errlogAddListener ( logClientSendMessage, (void *) pClient ); - return (void *) pClient; }