diff options
Diffstat (limited to 'tools/omfwd.c')
-rw-r--r-- | tools/omfwd.c | 216 |
1 files changed, 188 insertions, 28 deletions
diff --git a/tools/omfwd.c b/tools/omfwd.c index 129392d..6e5cf80 100644 --- a/tools/omfwd.c +++ b/tools/omfwd.c @@ -4,7 +4,7 @@ * NOTE: read comments in module-template.h to understand how this file * works! * - * Copyright 2007-2012 Adiscon GmbH. + * Copyright 2007-2013 Adiscon GmbH. * * This file is part of rsyslog. * @@ -21,9 +21,6 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - * - * TODO v6 config: - * - permitted peer *list* */ #include "config.h" #include "rsyslog.h" @@ -39,6 +36,7 @@ #include <errno.h> #include <ctype.h> #include <unistd.h> +#include <stdint.h> #ifdef USE_NETZIP #include <zlib.h> #endif @@ -74,6 +72,10 @@ DEFobjCurrIf(netstrms) DEFobjCurrIf(netstrm) DEFobjCurrIf(tcpclt) +/* some local constants (just) for better readybility */ +#define IS_FLUSH 1 +#define NO_FLUSH 0 + typedef struct _instanceData { uchar *tplName; /* name of assigned template */ netstrms_t *pNS; /* netstream subsystem */ @@ -97,8 +99,17 @@ typedef struct _instanceData { TCPFRAMINGMODE tcp_framing; int bResendLastOnRecon; /* should the last message be re-sent on a successful reconnect? */ tcpclt_t *pTCPClt; /* our tcpclt object */ +# define COMPRESS_NEVER 0 +# define COMPRESS_SINGLE_MSG 1 /* old, single-message compression */ + /* all other settings are for stream-compression */ +# define COMPRESS_STREAM_ALWAYS 2 + uint8_t compressionMode; + sbool strmCompFlushOnTxEnd; /* flush stream compression on transaction end? */ + sbool bzInitDone; /* did we do an init of zstrm already? */ + z_stream zstrm; /* zip stream to use for tcp compression */ uchar sndBuf[16*1024]; /* this is intensionally fixed -- see no good reason to make configurable */ unsigned offsSndBuf; /* next free spot in send buffer */ + int errsToReport; /* (remaining) number of errors to report */ } instanceData; /* config data */ @@ -132,6 +143,9 @@ static struct cnfparamdescr actpdescr[] = { { "protocol", eCmdHdlrGetWord, 0 }, { "tcp_framing", eCmdHdlrGetWord, 0 }, { "ziplevel", eCmdHdlrInt, 0 }, + { "compression.mode", eCmdHdlrGetWord, 0 }, + { "compression.stream.flushontxend", eCmdHdlrBinary, 0 }, + { "maxerrormessages", eCmdHdlrInt, 0 }, { "rebindinterval", eCmdHdlrInt, 0 }, { "streamdriver", eCmdHdlrGetWord, 0 }, { "streamdrivermode", eCmdHdlrInt, 0 }, @@ -169,6 +183,7 @@ ENDinitConfVars static rsRetVal doTryResume(instanceData *pData); +static rsRetVal doZipFinish(instanceData *pData); /* this function gets the default template. It coordinates action between * old-style and new-style configuration parts. @@ -240,6 +255,7 @@ static inline void DestructTCPInstanceData(instanceData *pData) { assert(pData != NULL); + doZipFinish(pData); if(pData->pNetstrm != NULL) netstrm.Destruct(&pData->pNetstrm); if(pData->pNS != NULL) @@ -315,6 +331,7 @@ ENDfreeCnf BEGINcreateInstance CODESTARTcreateInstance pData->offsSndBuf = 0; + pData->errsToReport = 5; ENDcreateInstance @@ -358,7 +375,9 @@ static rsRetVal UDPSend(instanceData *pData, char *msg, size_t len) struct addrinfo *r; int i; unsigned lsent = 0; - int bSendSuccess; + sbool bSendSuccess; + int lasterrno; + char errStr[1024]; if(pData->iRebindInterval && (pData->nXmit++ % pData->iRebindInterval == 0)) { dbgprintf("omfwd dropping UDP 'connection' (as configured)\n"); @@ -386,18 +405,30 @@ static rsRetVal UDPSend(instanceData *pData, char *msg, size_t len) bSendSuccess = RSTRUE; break; } else { - int eno = errno; - char errStr[1024]; - dbgprintf("sendto() error: %d = %s.\n", - eno, rs_strerror_r(eno, errStr, sizeof(errStr))); + lasterrno = errno; + DBGPRINTF("sendto() error: %d = %s.\n", + lasterrno, + rs_strerror_r(lasterrno, errStr, sizeof(errStr))); } } if (lsent == len && !send_to_all) break; } /* finished looping */ - if (bSendSuccess == RSFALSE) { + if(bSendSuccess == RSFALSE) { dbgprintf("error forwarding via udp, suspending\n"); + if(pData->errsToReport > 0) { + rs_strerror_r(lasterrno, errStr, sizeof(errStr)); + errmsg.LogError(0, RS_RET_ERR_UDPSEND, "omfwd: error sending " + "via udp: %s", errStr); + if(pData->errsToReport == 1) { + errmsg.LogError(0, RS_RET_LAST_ERRREPORT, "omfwd: " + "max number of error message emitted " + "- further messages will be " + "suppressed"); + } + --pData->errsToReport; + } iRet = RS_RET_SUSPENDED; } } @@ -423,14 +454,8 @@ finalize_it: /* CODE FOR SENDING TCP MESSAGES */ - -/* Send a buffer via TCP. Usually, this is used to send the current - * send buffer, but if a message is larger than the buffer, we need to - * have the capability to send the message buffer directly. - * rgerhards, 2011-04-04 - */ static rsRetVal -TCPSendBuf(instanceData *pData, uchar *buf, unsigned len) +TCPSendBufUncompressed(instanceData *pData, uchar *buf, unsigned len) { DEFiRet; unsigned alreadySent; @@ -438,6 +463,7 @@ TCPSendBuf(instanceData *pData, uchar *buf, unsigned len) alreadySent = 0; CHKiRet(netstrm.CheckConnection(pData->pNetstrm)); /* hack for plain tcp syslog - see ptcp driver for details */ + while(alreadySent != len) { lenSend = len - alreadySent; CHKiRet(netstrm.Send(pData->pNetstrm, buf+alreadySent, &lenSend)); @@ -455,6 +481,104 @@ finalize_it: RETiRet; } +static rsRetVal +TCPSendBufCompressed(instanceData *pData, uchar *buf, unsigned len, sbool bIsFlush) +{ + int zRet; /* zlib return state */ + unsigned outavail; + uchar zipBuf[32*1024]; + int op; + DEFiRet; + + if(!pData->bzInitDone) { + /* allocate deflate state */ + pData->zstrm.zalloc = Z_NULL; + pData->zstrm.zfree = Z_NULL; + pData->zstrm.opaque = Z_NULL; + /* see note in file header for the params we use with deflateInit2() */ + zRet = deflateInit(&pData->zstrm, 9); + if(zRet != Z_OK) { + DBGPRINTF("error %d returned from zlib/deflateInit()\n", zRet); + ABORT_FINALIZE(RS_RET_ZLIB_ERR); + } + pData->bzInitDone = RSTRUE; + } + + /* now doing the compression */ + pData->zstrm.next_in = (Bytef*) buf; + pData->zstrm.avail_in = len; + if(pData->strmCompFlushOnTxEnd && bIsFlush) + op = Z_SYNC_FLUSH; + else + op = Z_NO_FLUSH; + /* run deflate() on buffer until everything has been compressed */ + do { + DBGPRINTF("omfwd: in deflate() loop, avail_in %d, total_in %ld, isFlush %d\n", pData->zstrm.avail_in, pData->zstrm.total_in, bIsFlush); + pData->zstrm.avail_out = sizeof(zipBuf); + pData->zstrm.next_out = zipBuf; + zRet = deflate(&pData->zstrm, op); /* no bad return value */ + DBGPRINTF("after deflate, ret %d, avail_out %d\n", zRet, pData->zstrm.avail_out); + outavail = sizeof(zipBuf) - pData->zstrm.avail_out; + if(outavail != 0) { + CHKiRet(TCPSendBufUncompressed(pData, zipBuf, outavail)); + } + } while (pData->zstrm.avail_out == 0); + +finalize_it: + RETiRet; +} + +static rsRetVal +TCPSendBuf(instanceData *pData, uchar *buf, unsigned len, sbool bIsFlush) +{ + DEFiRet; + if(pData->compressionMode >= COMPRESS_STREAM_ALWAYS) + iRet = TCPSendBufCompressed(pData, buf, len, bIsFlush); + else + iRet = TCPSendBufUncompressed(pData, buf, len); + RETiRet; +} + +/* finish zlib buffer, to be called before closing the ZIP file (if + * running in stream mode). + */ +static rsRetVal +doZipFinish(instanceData *pData) +{ + int zRet; /* zlib return state */ + DEFiRet; + unsigned outavail; + uchar zipBuf[32*1024]; + + if(!pData->bzInitDone) + goto done; + +// TODO: can we get this into a single common function? +dbgprintf("DDDD: in doZipFinish()\n"); + pData->zstrm.avail_in = 0; + /* run deflate() on buffer until everything has been compressed */ + do { + DBGPRINTF("in deflate() loop, avail_in %d, total_in %ld\n", pData->zstrm.avail_in, pData->zstrm.total_in); + pData->zstrm.avail_out = sizeof(zipBuf); + pData->zstrm.next_out = zipBuf; + zRet = deflate(&pData->zstrm, Z_FINISH); /* no bad return value */ + DBGPRINTF("after deflate, ret %d, avail_out %d\n", zRet, pData->zstrm.avail_out); + outavail = sizeof(zipBuf) - pData->zstrm.avail_out; + if(outavail != 0) { + CHKiRet(TCPSendBufUncompressed(pData, zipBuf, outavail)); + } + } while (pData->zstrm.avail_out == 0); + +finalize_it: + zRet = deflateEnd(&pData->zstrm); + if(zRet != Z_OK) { + DBGPRINTF("error %d returned from zlib/deflateEnd()\n", zRet); + } + + pData->bzInitDone = 0; +done: RETiRet; +} + /* Add frame to send buffer (or send, if requried) */ @@ -467,14 +591,14 @@ static rsRetVal TCPSendFrame(void *pvData, char *msg, size_t len) (unsigned) len, pData->offsSndBuf); if(pData->offsSndBuf != 0 && pData->offsSndBuf + len >= sizeof(pData->sndBuf)) { /* no buffer space left, need to commit previous records */ - CHKiRet(TCPSendBuf(pData, pData->sndBuf, pData->offsSndBuf)); + CHKiRet(TCPSendBuf(pData, pData->sndBuf, pData->offsSndBuf, NO_FLUSH)); pData->offsSndBuf = 0; iRet = RS_RET_PREVIOUS_COMMITTED; } /* check if the message is too large to fit into buffer */ if(len > sizeof(pData->sndBuf)) { - CHKiRet(TCPSendBuf(pData, (uchar*)msg, len)); + CHKiRet(TCPSendBuf(pData, (uchar*)msg, len, NO_FLUSH)); ABORT_FINALIZE(RS_RET_OK); /* committed everything so far */ } @@ -496,7 +620,6 @@ static rsRetVal TCPSendPrepRetry(void *pvData) { DEFiRet; instanceData *pData = (instanceData *) pvData; -dbgprintf("TCPSendPrepRetry performs a DestructTCPInstanceData\n"); assert(pData != NULL); DestructTCPInstanceData(pData); @@ -576,7 +699,7 @@ static rsRetVal doTryResume(instanceData *pData) pData->f_addr = res; pData->bIsConnected = 1; if(pData->pSockArray == NULL) { - pData->pSockArray = net.create_udp_socket((uchar*)pData->target, NULL, 0); + pData->pSockArray = net.create_udp_socket((uchar*)pData->target, NULL, 0, 0); } } else { CHKiRet(TCPSendInit((void*)pData)); @@ -636,11 +759,10 @@ CODESTARTdoAction * hard-coded but this may be changed to a config parameter. * rgerhards, 2006-11-30 */ - if(pData->compressionLevel && (l > CONF_MIN_SIZE_FOR_COMPRESS)) { + if(pData->compressionMode == COMPRESS_SINGLE_MSG && (l > CONF_MIN_SIZE_FOR_COMPRESS)) { uLongf destLen = iMaxLine + iMaxLine/100 +12; /* recommended value from zlib doc */ uLong srcLen = l; int ret; - /* TODO: optimize malloc sequence? -- rgerhards, 2008-09-02 */ CHKmalloc(out = (Bytef*) MALLOC(destLen)); out[0] = 'z'; out[1] = '\0'; @@ -679,6 +801,9 @@ CODESTARTdoAction DestructTCPInstanceData(pData); iRet = RS_RET_SUSPENDED; } + if(pData->compressionMode >= COMPRESS_STREAM_ALWAYS && pData->strmCompFlushOnTxEnd) + /* mimic not committed, as we need the EndTx entry point to be called */ + iRet = RS_RET_DEFER_COMMIT; } finalize_it: # ifdef USE_NETZIP @@ -691,7 +816,7 @@ BEGINendTransaction CODESTARTendTransaction dbgprintf("omfwd: endTransaction, offsSndBuf %u\n", pData->offsSndBuf); if(pData->offsSndBuf != 0) { - iRet = TCPSendBuf(pData, pData->sndBuf, pData->offsSndBuf); + iRet = TCPSendBuf(pData, pData->sndBuf, pData->offsSndBuf, IS_FLUSH); pData->offsSndBuf = 0; } ENDendTransaction @@ -732,7 +857,6 @@ initTCP(instanceData *pData) CHKiRet(tcpclt.SetSendPrepRetry(pData->pTCPClt, TCPSendPrepRetry)); CHKiRet(tcpclt.SetFraming(pData->pTCPClt, pData->tcp_framing)); CHKiRet(tcpclt.SetRebindInterval(pData->pTCPClt, pData->iRebindInterval)); - pData->iStrmDrvrMode = cs.iStrmDrvrMode; if(cs.pszStrmDrvr != NULL) CHKmalloc(pData->pszStrmDrvr = (uchar*)strdup((char*)cs.pszStrmDrvr)); if(cs.pszStrmDrvrAuthMode != NULL) @@ -756,14 +880,19 @@ setInstParamDefaults(instanceData *pData) pData->iRebindInterval = 0; pData->bResendLastOnRecon = 0; pData->pPermPeers = NULL; - pData->compressionLevel = 0; + pData->compressionLevel = 9; + pData->strmCompFlushOnTxEnd = 1; + pData->compressionMode = COMPRESS_NEVER; + pData->errsToReport = 5; } BEGINnewActInst struct cnfparamvals *pvals; uchar *tplToUse; + char *cstr; int i; rsRetVal localRet; + int complevel = -1; CODESTARTnewActInst DBGPRINTF("newActInst (omfwd)\n"); @@ -860,9 +989,10 @@ CODESTARTnewActInst free(str); } else if(!strcmp(actpblk.descr[i].name, "ziplevel")) { # ifdef USE_NETZIP - int complevel = pvals[i].val.d.n; + complevel = pvals[i].val.d.n; if(complevel >= 0 && complevel <= 10) { pData->compressionLevel = complevel; + pData->compressionMode = COMPRESS_SINGLE_MSG; } else { errmsg.LogError(0, NO_ERRCODE, "Invalid ziplevel %d specified in " "forwardig action - NOT turning on compression.", @@ -872,15 +1002,45 @@ CODESTARTnewActInst errmsg.LogError(0, NO_ERRCODE, "Compression requested, but rsyslogd is not compiled " "with compression support - request ignored."); # endif /* #ifdef USE_NETZIP */ + } else if(!strcmp(actpblk.descr[i].name, "maxerrormessages")) { + pData->errsToReport = (int) pvals[i].val.d.n; } else if(!strcmp(actpblk.descr[i].name, "resendlastmsgonreconnect")) { pData->bResendLastOnRecon = (int) pvals[i].val.d.n; } else if(!strcmp(actpblk.descr[i].name, "template")) { pData->tplName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(actpblk.descr[i].name, "compression.stream.flushontxend")) { + pData->strmCompFlushOnTxEnd = (sbool) pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "compression.mode")) { + cstr = es_str2cstr(pvals[i].val.d.estr, NULL); + if(!strcasecmp(cstr, "stream:always")) { + pData->compressionMode = COMPRESS_STREAM_ALWAYS; + } else if(!strcasecmp(cstr, "none")) { + pData->compressionMode = COMPRESS_NEVER; + } else if(!strcasecmp(cstr, "single")) { + pData->compressionMode = COMPRESS_SINGLE_MSG; + } else { + errmsg.LogError(0, RS_RET_PARAM_ERROR, "omfwd: invalid value for 'compression.mode' " + "parameter (given is '%s')", cstr); + free(cstr); + ABORT_FINALIZE(RS_RET_PARAM_ERROR); + } + free(cstr); } else { DBGPRINTF("omfwd: program error, non-handled " "param '%s'\n", actpblk.descr[i].name); } } + + if(complevel != -1) { + pData->compressionLevel = complevel; + if(pData->compressionMode == COMPRESS_NEVER) { + /* to keep compatible with pre-7.3.11, only setting the + * compresion level means old-style single-message mode. + */ + pData->compressionMode = COMPRESS_SINGLE_MSG; + } + } + CODE_STD_STRING_REQUESTnewActInst(1) tplToUse = ustrdup((pData->tplName == NULL) ? getDfltTpl() : pData->tplName); @@ -948,6 +1108,7 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1) iLevel = *p - '0'; ++p; /* eat */ pData->compressionLevel = iLevel; + pData->compressionMode = COMPRESS_SINGLE_MSG; } else { errmsg.LogError(0, NO_ERRCODE, "Invalid compression level '%c' specified in " "forwardig action - NOT turning on compression.", @@ -1025,7 +1186,6 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1) while(*p && *p != ';' && *p != '#' && !isspace((int) *p)) ++p; /*JUST SKIP*/ - /* TODO: make this if go away! */ if(*p == ';' || *p == '#' || isspace(*p)) { uchar cTmp = *p; *p = '\0'; /* trick to obtain hostname (later)! */ |