summaryrefslogtreecommitdiff
path: root/tools/omfwd.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/omfwd.c')
-rw-r--r--tools/omfwd.c216
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)! */