summaryrefslogtreecommitdiffstats
path: root/runtime
diff options
context:
space:
mode:
authorRainer Gerhards <rgerhards@adiscon.com>2009-06-22 15:12:35 +0200
committerRainer Gerhards <rgerhards@adiscon.com>2009-06-22 15:12:35 +0200
commit651bee9cf55ca6aaea73e7921928bf6f9bd65404 (patch)
tree8c3ce1b498e01839fe6ef0c6adb8cfbcb2f42bad /runtime
parentb5f3387357ffa11e238ddfe0fa38af4fffba6081 (diff)
parent3abf567d2b57014381eda49018a0e2c21fa1b853 (diff)
downloadrsyslog-651bee9cf55ca6aaea73e7921928bf6f9bd65404.tar.gz
rsyslog-651bee9cf55ca6aaea73e7921928bf6f9bd65404.tar.xz
rsyslog-651bee9cf55ca6aaea73e7921928bf6f9bd65404.zip
Merge branch 'omfile' into tmp
This was a complex manual merge, especially in action.c. So if there occur some problems, this would be a good point to start troubleshooting. I run a couple of tests before commiting and they all went well. Conflicts: action.c action.h runtime/queue.c runtime/queue.h runtime/wti.c runtime/wti.h
Diffstat (limited to 'runtime')
-rw-r--r--runtime/Makefile.am2
-rw-r--r--runtime/apc.c2
-rw-r--r--runtime/conf.c2
-rw-r--r--runtime/ctok.c17
-rw-r--r--runtime/datetime.c246
-rw-r--r--runtime/msg.c722
-rw-r--r--runtime/msg.h58
-rw-r--r--runtime/nsd_gtls.c34
-rw-r--r--runtime/obj.c16
-rw-r--r--runtime/parser.c84
-rw-r--r--runtime/prop.c124
-rw-r--r--runtime/prop.h46
-rw-r--r--runtime/queue.c124
-rw-r--r--runtime/queue.h16
-rw-r--r--runtime/rsyslog.h14
-rw-r--r--runtime/rule.c4
-rw-r--r--runtime/stream.c10
-rw-r--r--runtime/stringbuf.c77
-rw-r--r--runtime/stringbuf.h24
-rw-r--r--runtime/vm.c12
-rw-r--r--runtime/vmop.c2
-rw-r--r--runtime/wti.c13
-rw-r--r--runtime/wti.h3
-rw-r--r--runtime/wtp.c1
-rw-r--r--runtime/wtp.h3
25 files changed, 1068 insertions, 588 deletions
diff --git a/runtime/Makefile.am b/runtime/Makefile.am
index d274d9e4..caf7c5ca 100644
--- a/runtime/Makefile.am
+++ b/runtime/Makefile.am
@@ -74,6 +74,8 @@ librsyslog_la_SOURCES = \
ruleset.h \
rule.c \
rule.h \
+ prop.c \
+ prop.h \
cfsysline.c \
cfsysline.h \
\
diff --git a/runtime/apc.c b/runtime/apc.c
index b0b5f298..1bcaee39 100644
--- a/runtime/apc.c
+++ b/runtime/apc.c
@@ -332,9 +332,11 @@ CancelApc(apc_id_t id)
{
DEFVARS_mutexProtection_uncond;
+ BEGINfunc
BEGIN_MTX_PROTECTED_OPERATIONS_UNCOND(&listMutex);
deleteApc(id);
END_MTX_PROTECTED_OPERATIONS_UNCOND(&listMutex);
+ ENDfunc
return RS_RET_OK;
}
diff --git a/runtime/conf.c b/runtime/conf.c
index 538af7d6..f9c37610 100644
--- a/runtime/conf.c
+++ b/runtime/conf.c
@@ -216,7 +216,7 @@ doIncludeLine(uchar **pp, __attribute__((unused)) void* pVal)
* Required by doIncludeDirectory().
*/
result = glob(pattern, GLOB_MARK, NULL, &cfgFiles);
- if(result != 0) {
+ if(result == GLOB_NOSPACE || result == GLOB_ABORTED) {
char errStr[1024];
rs_strerror_r(errno, errStr, sizeof(errStr));
errmsg.LogError(0, RS_RET_FILE_NOT_FOUND, "error accessing config file or directory '%s': %s",
diff --git a/runtime/ctok.c b/runtime/ctok.c
index 263e656c..6f5f0273 100644
--- a/runtime/ctok.c
+++ b/runtime/ctok.c
@@ -258,13 +258,13 @@ ctokGetVar(ctok_t *pThis, ctok_token_t *pToken)
pToken->tok = ctok_MSGVAR;
}
- CHKiRet(rsCStrConstruct(&pstrVal));
+ CHKiRet(cstrConstruct(&pstrVal));
/* this loop is quite simple, a variable name is terminated when a non-supported
* character is detected. Note that we currently permit a numerical digit as the
* first char, which is not permitted by ABNF. -- rgerhards, 2009-03-10
*/
while(isalpha(c) || isdigit(c) || (c == '_') || (c == '-')) {
- CHKiRet(rsCStrAppendChar(pstrVal, tolower(c)));
+ CHKiRet(cstrAppendChar(pstrVal, tolower(c)));
CHKiRet(ctokGetCharFromStream(pThis, &c));
}
CHKiRet(ctokUngetCharFromStream(pThis, c)); /* put not processed char back */
@@ -277,7 +277,7 @@ ctokGetVar(ctok_t *pThis, ctok_token_t *pToken)
finalize_it:
if(iRet != RS_RET_OK) {
if(pstrVal != NULL) {
- rsCStrDestruct(&pstrVal);
+ cstrDestruct(&pstrVal);
}
}
@@ -301,20 +301,20 @@ ctokGetSimpStr(ctok_t *pThis, ctok_token_t *pToken)
pToken->tok = ctok_SIMPSTR;
- CHKiRet(rsCStrConstruct(&pstrVal));
+ CHKiRet(cstrConstruct(&pstrVal));
CHKiRet(ctokGetCharFromStream(pThis, &c));
/* while we are in escape mode (had a backslash), no sequence
* terminates the loop. If outside, it is terminated by a single quote.
*/
while(bInEsc || c != '\'') {
if(bInEsc) {
- CHKiRet(rsCStrAppendChar(pstrVal, c));
+ CHKiRet(cstrAppendChar(pstrVal, c));
bInEsc = 0;
} else {
if(c == '\\') {
bInEsc = 1;
} else {
- CHKiRet(rsCStrAppendChar(pstrVal, c));
+ CHKiRet(cstrAppendChar(pstrVal, c));
}
}
CHKiRet(ctokGetCharFromStream(pThis, &c));
@@ -327,7 +327,7 @@ ctokGetSimpStr(ctok_t *pThis, ctok_token_t *pToken)
finalize_it:
if(iRet != RS_RET_OK) {
if(pstrVal != NULL) {
- rsCStrDestruct(&pstrVal);
+ cstrDestruct(&pstrVal);
}
}
@@ -519,8 +519,9 @@ ctokGetToken(ctok_t *pThis, ctok_token_t **ppToken)
CHKiRet(ctokUngetCharFromStream(pThis, c));
pToken->tok = ctok_FUNCTION;
/* fill function name */
- CHKiRet(rsCStrConstruct(&pstrVal));
+ CHKiRet(cstrConstruct(&pstrVal));
CHKiRet(rsCStrSetSzStr(pstrVal, szWord));
+ CHKiRet(cstrFinalize(pstrVal));
CHKiRet(var.SetString(pToken->pVar, pstrVal));
} else { /* give up... */
dbgprintf("parser has an invalid word (token) '%s'\n", szWord);
diff --git a/runtime/datetime.c b/runtime/datetime.c
index afd709c3..a1ba164e 100644
--- a/runtime/datetime.c
+++ b/runtime/datetime.c
@@ -49,6 +49,8 @@
DEFobjStaticHelpers
DEFobjCurrIf(errmsg)
+/* the following table of ten powers saves us some computation */
+static const int tenPowers[6] = { 1, 10, 100, 1000, 10000, 100000 };
/* ------------------------------ methods ------------------------------ */
@@ -546,7 +548,7 @@ finalize_it:
* returns the size of the timestamp written in bytes (without
* the string terminator). If 0 is returend, an error occured.
*/
-int formatTimestampToMySQL(struct syslogTime *ts, char* pDst, size_t iLenDst)
+int formatTimestampToMySQL(struct syslogTime *ts, char* pBuf, size_t iLenDst)
{
/* currently we do not consider localtime/utc. This may later be
* added. If so, I recommend using a property replacer option
@@ -555,28 +557,56 @@ int formatTimestampToMySQL(struct syslogTime *ts, char* pDst, size_t iLenDst)
* rgerhards, 2007-06-26
*/
assert(ts != NULL);
- assert(pDst != NULL);
-
- if (iLenDst < 15) /* we need at least 14 bytes
- 14 digits for timestamp + '\n' */
- return(0);
-
- return(snprintf(pDst, iLenDst, "%4.4d%2.2d%2.2d%2.2d%2.2d%2.2d",
- ts->year, ts->month, ts->day, ts->hour, ts->minute, ts->second));
+ assert(pBuf != NULL);
+ assert(iLenDst >= 15);
+
+ pBuf[0] = (ts->year / 1000) % 10 + '0';
+ pBuf[1] = (ts->year / 100) % 10 + '0';
+ pBuf[2] = (ts->year / 10) % 10 + '0';
+ pBuf[3] = ts->year % 10 + '0';
+ pBuf[4] = (ts->month / 10) % 10 + '0';
+ pBuf[5] = ts->month % 10 + '0';
+ pBuf[6] = (ts->day / 10) % 10 + '0';
+ pBuf[7] = ts->day % 10 + '0';
+ pBuf[8] = (ts->hour / 10) % 10 + '0';
+ pBuf[9] = ts->hour % 10 + '0';
+ pBuf[10] = (ts->minute / 10) % 10 + '0';
+ pBuf[11] = ts->minute % 10 + '0';
+ pBuf[12] = (ts->second / 10) % 10 + '0';
+ pBuf[13] = ts->second % 10 + '0';
+ pBuf[14] = '\0';
+ return 15;
}
-int formatTimestampToPgSQL(struct syslogTime *ts, char *pDst, size_t iLenDst)
+int formatTimestampToPgSQL(struct syslogTime *ts, char *pBuf, size_t iLenDst)
{
- /* see note in formatTimestampToMySQL, applies here as well */
- assert(ts != NULL);
- assert(pDst != NULL);
-
- if (iLenDst < 21) /* we need 20 bytes + '\n' */
- return(0);
-
- return(snprintf(pDst, iLenDst, "%4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d",
- ts->year, ts->month, ts->day, ts->hour, ts->minute, ts->second));
+ /* see note in formatTimestampToMySQL, applies here as well */
+ assert(ts != NULL);
+ assert(pBuf != NULL);
+ assert(iLenDst >= 20);
+
+ pBuf[0] = (ts->year / 1000) % 10 + '0';
+ pBuf[1] = (ts->year / 100) % 10 + '0';
+ pBuf[2] = (ts->year / 10) % 10 + '0';
+ pBuf[3] = ts->year % 10 + '0';
+ pBuf[4] = '-';
+ pBuf[5] = (ts->month / 10) % 10 + '0';
+ pBuf[6] = ts->month % 10 + '0';
+ pBuf[7] = '-';
+ pBuf[8] = (ts->day / 10) % 10 + '0';
+ pBuf[9] = ts->day % 10 + '0';
+ pBuf[10] = ' ';
+ pBuf[11] = (ts->hour / 10) % 10 + '0';
+ pBuf[12] = ts->hour % 10 + '0';
+ pBuf[13] = ':';
+ pBuf[14] = (ts->minute / 10) % 10 + '0';
+ pBuf[15] = ts->minute % 10 + '0';
+ pBuf[16] = ':';
+ pBuf[17] = (ts->second / 10) % 10 + '0';
+ pBuf[18] = ts->second % 10 + '0';
+ pBuf[19] = '\0';
+ return 19;
}
@@ -591,30 +621,32 @@ int formatTimestampToPgSQL(struct syslogTime *ts, char *pDst, size_t iLenDst)
*/
int formatTimestampSecFrac(struct syslogTime *ts, char* pBuf, size_t iLenBuf)
{
- int lenRet;
- char szFmtStr[64];
+ int iBuf;
+ int power;
+ int secfrac;
+ short digit;
assert(ts != NULL);
assert(pBuf != NULL);
assert(iLenBuf >= 10);
+ iBuf = 0;
if(ts->secfracPrecision > 0)
- { /* We must look at
- * the precision specified. For example, if we have millisec precision (3 digits), a
- * secFrac value of 12 is not equivalent to ".12" but ".012". Obviously, this
- * is a huge difference ;). To avoid this, we first create a format string with
- * the specific precision and *then* use that format string to do the actual formating.
- */
- /* be careful: there is ONE actual %d in the format string below ;) */
- snprintf(szFmtStr, sizeof(szFmtStr), "%%0%dd", ts->secfracPrecision);
- lenRet = snprintf(pBuf, iLenBuf, szFmtStr, ts->secfrac);
+ {
+ power = tenPowers[(ts->secfracPrecision - 1) % 6];
+ secfrac = ts->secfrac;
+ while(power > 0) {
+ digit = secfrac / power;
+ secfrac -= digit * power;
+ power /= 10;
+ pBuf[iBuf++] = digit + '0';
+ }
} else {
- pBuf[0] = '0';
- pBuf[1] = '\0';
- lenRet = 1;
+ pBuf[iBuf++] = '0';
}
+ pBuf[iBuf] = '\0';
- return(lenRet);
+ return iBuf;
}
@@ -628,46 +660,72 @@ int formatTimestampSecFrac(struct syslogTime *ts, char* pBuf, size_t iLenBuf)
*/
int formatTimestamp3339(struct syslogTime *ts, char* pBuf, size_t iLenBuf)
{
- int iRet;
- char szTZ[7]; /* buffer for TZ information */
+ int iBuf;
+ int power;
+ int secfrac;
+ short digit;
+ BEGINfunc
assert(ts != NULL);
assert(pBuf != NULL);
-
- if(iLenBuf < 20)
- return(0); /* we NEED at least 20 bytes */
+ assert(iLenBuf >= 33);
+
+ /* start with fixed parts */
+ /* year yyyy */
+ pBuf[0] = (ts->year / 1000) % 10 + '0';
+ pBuf[1] = (ts->year / 100) % 10 + '0';
+ pBuf[2] = (ts->year / 10) % 10 + '0';
+ pBuf[3] = ts->year % 10 + '0';
+ pBuf[4] = '-';
+ /* month */
+ pBuf[5] = (ts->month / 10) % 10 + '0';
+ pBuf[6] = ts->month % 10 + '0';
+ pBuf[7] = '-';
+ /* day */
+ pBuf[8] = (ts->day / 10) % 10 + '0';
+ pBuf[9] = ts->day % 10 + '0';
+ pBuf[10] = 'T';
+ /* hour */
+ pBuf[11] = (ts->hour / 10) % 10 + '0';
+ pBuf[12] = ts->hour % 10 + '0';
+ pBuf[13] = ':';
+ /* minute */
+ pBuf[14] = (ts->minute / 10) % 10 + '0';
+ pBuf[15] = ts->minute % 10 + '0';
+ pBuf[16] = ':';
+ /* second */
+ pBuf[17] = (ts->second / 10) % 10 + '0';
+ pBuf[18] = ts->second % 10 + '0';
+
+ iBuf = 19; /* points to next free entry, now it becomes dynamic! */
+
+ if(ts->secfracPrecision > 0) {
+ pBuf[iBuf++] = '.';
+ power = tenPowers[(ts->secfracPrecision - 1) % 6];
+ secfrac = ts->secfrac;
+ while(power > 0) {
+ digit = secfrac / power;
+ secfrac -= digit * power;
+ power /= 10;
+ pBuf[iBuf++] = digit + '0';
+ }
+ }
- /* do TZ information first, this is easier to take care of "Z" zone in rfc3339 */
if(ts->OffsetMode == 'Z') {
- szTZ[0] = 'Z';
- szTZ[1] = '\0';
+ pBuf[iBuf++] = 'Z';
} else {
- snprintf(szTZ, sizeof(szTZ) / sizeof(char), "%c%2.2d:%2.2d",
- ts->OffsetMode, ts->OffsetHour, ts->OffsetMinute);
+ pBuf[iBuf++] = ts->OffsetMode;
+ pBuf[iBuf++] = (ts->OffsetHour / 10) % 10 + '0';
+ pBuf[iBuf++] = ts->OffsetHour % 10 + '0';
+ pBuf[iBuf++] = ':';
+ pBuf[iBuf++] = (ts->OffsetMinute / 10) % 10 + '0';
+ pBuf[iBuf++] = ts->OffsetMinute % 10 + '0';
}
- if(ts->secfracPrecision > 0)
- { /* we now need to include fractional seconds. While doing so, we must look at
- * the precision specified. For example, if we have millisec precision (3 digits), a
- * secFrac value of 12 is not equivalent to ".12" but ".012". Obviously, this
- * is a huge difference ;). To avoid this, we first create a format string with
- * the specific precision and *then* use that format string to do the actual
- * formating (mmmmhhh... kind of self-modifying code... ;)).
- */
- char szFmtStr[64];
- /* be careful: there is ONE actual %d in the format string below ;) */
- snprintf(szFmtStr, sizeof(szFmtStr),
- "%%04d-%%02d-%%02dT%%02d:%%02d:%%02d.%%0%dd%%s",
- ts->secfracPrecision);
- iRet = snprintf(pBuf, iLenBuf, szFmtStr, ts->year, ts->month, ts->day,
- ts->hour, ts->minute, ts->second, ts->secfrac, szTZ);
- }
- else
- iRet = snprintf(pBuf, iLenBuf,
- "%4.4d-%2.2d-%2.2dT%2.2d:%2.2d:%2.2d%s",
- ts->year, ts->month, ts->day,
- ts->hour, ts->minute, ts->second, szTZ);
- return(iRet);
+ pBuf[iBuf] = '\0';
+
+ ENDfunc
+ return iBuf;
}
/**
@@ -679,44 +737,35 @@ int formatTimestamp3339(struct syslogTime *ts, char* pBuf, size_t iLenBuf)
*/
int formatTimestamp3164(struct syslogTime *ts, char* pBuf, size_t iLenBuf)
{
- static char* monthNames[13] = {"ERR", "Jan", "Feb", "Mar",
- "Apr", "May", "Jun", "Jul",
- "Aug", "Sep", "Oct", "Nov", "Dec"};
+ static char* monthNames[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+ int iDay;
assert(ts != NULL);
assert(pBuf != NULL);
- if(iLenBuf < 16)
- return(0); /* we NEED 16 bytes */
- return(snprintf(pBuf, iLenBuf, "%s %2d %2.2d:%2.2d:%2.2d",
- monthNames[ts->month], ts->day, ts->hour,
- ts->minute, ts->second
- ));
+ assert(iLenBuf >= 16);
+
+ pBuf[0] = monthNames[(ts->month - 1)% 12][0];
+ pBuf[1] = monthNames[(ts->month - 1) % 12][1];
+ pBuf[2] = monthNames[(ts->month - 1) % 12][2];
+ pBuf[3] = ' ';
+ iDay = (ts->day / 10) % 10; /* we need to write a space if the first digit is 0 */
+ pBuf[4] = iDay ? iDay + '0' : ' ';
+ pBuf[5] = ts->day % 10 + '0';
+ pBuf[6] = ' ';
+ pBuf[7] = (ts->hour / 10) % 10 + '0';
+ pBuf[8] = ts->hour % 10 + '0';
+ pBuf[9] = ':';
+ pBuf[10] = (ts->minute / 10) % 10 + '0';
+ pBuf[11] = ts->minute % 10 + '0';
+ pBuf[12] = ':';
+ pBuf[13] = (ts->second / 10) % 10 + '0';
+ pBuf[14] = ts->second % 10 + '0';
+ pBuf[15] = '\0';
+ return 16; /* traditional: number of bytes written */
}
-/**
- * Format a syslogTimestamp to a text format.
- * The caller must provide the timestamp as well as a character
- * buffer that will receive the resulting string. The function
- * returns the size of the timestamp written in bytes (without
- * the string termnator). If 0 is returend, an error occured.
- */
-#if 0 /* This method is currently not called, be we like to preserve it */
-static int formatTimestamp(struct syslogTime *ts, char* pBuf, size_t iLenBuf)
-{
- assert(ts != NULL);
- assert(pBuf != NULL);
-
- if(ts->timeType == 1) {
- return(formatTimestamp3164(ts, pBuf, iLenBuf));
- }
-
- if(ts->timeType == 2) {
- return(formatTimestamp3339(ts, pBuf, iLenBuf));
- }
- return(0);
-}
-#endif
/* queryInterface function
* rgerhards, 2008-03-05
*/
@@ -750,7 +799,6 @@ ENDobjQueryInterface(datetime)
BEGINAbstractObjClassInit(datetime, 1, OBJ_IS_CORE_MODULE) /* class, version */
/* request objects we use */
CHKiRet(objUse(errmsg, CORE_COMPONENT));
-
ENDObjClassInit(datetime)
/* vi:set ai:
diff --git a/runtime/msg.c b/runtime/msg.c
index 65041a31..4b7a0ad4 100644
--- a/runtime/msg.c
+++ b/runtime/msg.c
@@ -55,53 +55,219 @@ DEFobjCurrIf(datetime)
DEFobjCurrIf(glbl)
DEFobjCurrIf(regexp)
-static syslogCODE rs_prioritynames[] =
- {
- { "alert", LOG_ALERT },
- { "crit", LOG_CRIT },
- { "debug", LOG_DEBUG },
- { "emerg", LOG_EMERG },
- { "err", LOG_ERR },
- { "error", LOG_ERR }, /* DEPRECATED */
- { "info", LOG_INFO },
- { "none", INTERNAL_NOPRI }, /* INTERNAL */
- { "notice", LOG_NOTICE },
- { "panic", LOG_EMERG }, /* DEPRECATED */
- { "warn", LOG_WARNING }, /* DEPRECATED */
- { "warning", LOG_WARNING },
- { NULL, -1 }
- };
-
-#ifndef LOG_AUTHPRIV
-# define LOG_AUTHPRIV LOG_AUTH
-#endif
-static syslogCODE rs_facilitynames[] =
- {
- { "auth", LOG_AUTH },
- { "authpriv", LOG_AUTHPRIV },
- { "cron", LOG_CRON },
- { "daemon", LOG_DAEMON },
-#if defined(LOG_FTP)
- {"ftp", LOG_FTP},
-#endif
- { "kern", LOG_KERN },
- { "lpr", LOG_LPR },
- { "mail", LOG_MAIL },
- { "news", LOG_NEWS },
- { "security", LOG_AUTH }, /* DEPRECATED */
- { "syslog", LOG_SYSLOG },
- { "user", LOG_USER },
- { "uucp", LOG_UUCP },
- { "local0", LOG_LOCAL0 },
- { "local1", LOG_LOCAL1 },
- { "local2", LOG_LOCAL2 },
- { "local3", LOG_LOCAL3 },
- { "local4", LOG_LOCAL4 },
- { "local5", LOG_LOCAL5 },
- { "local6", LOG_LOCAL6 },
- { "local7", LOG_LOCAL7 },
- { NULL, -1 }
- };
+static struct {
+ uchar *pszName;
+ short lenName;
+} syslog_pri_names[192] = {
+ { UCHAR_CONSTANT("0"), 3},
+ { UCHAR_CONSTANT("1"), 3},
+ { UCHAR_CONSTANT("2"), 3},
+ { UCHAR_CONSTANT("3"), 3},
+ { UCHAR_CONSTANT("4"), 3},
+ { UCHAR_CONSTANT("5"), 3},
+ { UCHAR_CONSTANT("6"), 3},
+ { UCHAR_CONSTANT("7"), 3},
+ { UCHAR_CONSTANT("8"), 3},
+ { UCHAR_CONSTANT("9"), 3},
+ { UCHAR_CONSTANT("10"), 4},
+ { UCHAR_CONSTANT("11"), 4},
+ { UCHAR_CONSTANT("12"), 4},
+ { UCHAR_CONSTANT("13"), 4},
+ { UCHAR_CONSTANT("14"), 4},
+ { UCHAR_CONSTANT("15"), 4},
+ { UCHAR_CONSTANT("16"), 4},
+ { UCHAR_CONSTANT("17"), 4},
+ { UCHAR_CONSTANT("18"), 4},
+ { UCHAR_CONSTANT("19"), 4},
+ { UCHAR_CONSTANT("20"), 4},
+ { UCHAR_CONSTANT("21"), 4},
+ { UCHAR_CONSTANT("22"), 4},
+ { UCHAR_CONSTANT("23"), 4},
+ { UCHAR_CONSTANT("24"), 4},
+ { UCHAR_CONSTANT("25"), 4},
+ { UCHAR_CONSTANT("26"), 4},
+ { UCHAR_CONSTANT("27"), 4},
+ { UCHAR_CONSTANT("28"), 4},
+ { UCHAR_CONSTANT("29"), 4},
+ { UCHAR_CONSTANT("30"), 4},
+ { UCHAR_CONSTANT("31"), 4},
+ { UCHAR_CONSTANT("32"), 4},
+ { UCHAR_CONSTANT("33"), 4},
+ { UCHAR_CONSTANT("34"), 4},
+ { UCHAR_CONSTANT("35"), 4},
+ { UCHAR_CONSTANT("36"), 4},
+ { UCHAR_CONSTANT("37"), 4},
+ { UCHAR_CONSTANT("38"), 4},
+ { UCHAR_CONSTANT("39"), 4},
+ { UCHAR_CONSTANT("40"), 4},
+ { UCHAR_CONSTANT("41"), 4},
+ { UCHAR_CONSTANT("42"), 4},
+ { UCHAR_CONSTANT("43"), 4},
+ { UCHAR_CONSTANT("44"), 4},
+ { UCHAR_CONSTANT("45"), 4},
+ { UCHAR_CONSTANT("46"), 4},
+ { UCHAR_CONSTANT("47"), 4},
+ { UCHAR_CONSTANT("48"), 4},
+ { UCHAR_CONSTANT("49"), 4},
+ { UCHAR_CONSTANT("50"), 4},
+ { UCHAR_CONSTANT("51"), 4},
+ { UCHAR_CONSTANT("52"), 4},
+ { UCHAR_CONSTANT("53"), 4},
+ { UCHAR_CONSTANT("54"), 4},
+ { UCHAR_CONSTANT("55"), 4},
+ { UCHAR_CONSTANT("56"), 4},
+ { UCHAR_CONSTANT("57"), 4},
+ { UCHAR_CONSTANT("58"), 4},
+ { UCHAR_CONSTANT("59"), 4},
+ { UCHAR_CONSTANT("60"), 4},
+ { UCHAR_CONSTANT("61"), 4},
+ { UCHAR_CONSTANT("62"), 4},
+ { UCHAR_CONSTANT("63"), 4},
+ { UCHAR_CONSTANT("64"), 4},
+ { UCHAR_CONSTANT("65"), 4},
+ { UCHAR_CONSTANT("66"), 4},
+ { UCHAR_CONSTANT("67"), 4},
+ { UCHAR_CONSTANT("68"), 4},
+ { UCHAR_CONSTANT("69"), 4},
+ { UCHAR_CONSTANT("70"), 4},
+ { UCHAR_CONSTANT("71"), 4},
+ { UCHAR_CONSTANT("72"), 4},
+ { UCHAR_CONSTANT("73"), 4},
+ { UCHAR_CONSTANT("74"), 4},
+ { UCHAR_CONSTANT("75"), 4},
+ { UCHAR_CONSTANT("76"), 4},
+ { UCHAR_CONSTANT("77"), 4},
+ { UCHAR_CONSTANT("78"), 4},
+ { UCHAR_CONSTANT("79"), 4},
+ { UCHAR_CONSTANT("80"), 4},
+ { UCHAR_CONSTANT("81"), 4},
+ { UCHAR_CONSTANT("82"), 4},
+ { UCHAR_CONSTANT("83"), 4},
+ { UCHAR_CONSTANT("84"), 4},
+ { UCHAR_CONSTANT("85"), 4},
+ { UCHAR_CONSTANT("86"), 4},
+ { UCHAR_CONSTANT("87"), 4},
+ { UCHAR_CONSTANT("88"), 4},
+ { UCHAR_CONSTANT("89"), 4},
+ { UCHAR_CONSTANT("90"), 4},
+ { UCHAR_CONSTANT("91"), 4},
+ { UCHAR_CONSTANT("92"), 4},
+ { UCHAR_CONSTANT("93"), 4},
+ { UCHAR_CONSTANT("94"), 4},
+ { UCHAR_CONSTANT("95"), 4},
+ { UCHAR_CONSTANT("96"), 4},
+ { UCHAR_CONSTANT("97"), 4},
+ { UCHAR_CONSTANT("98"), 4},
+ { UCHAR_CONSTANT("99"), 4},
+ { UCHAR_CONSTANT("100"), 5},
+ { UCHAR_CONSTANT("101"), 5},
+ { UCHAR_CONSTANT("102"), 5},
+ { UCHAR_CONSTANT("103"), 5},
+ { UCHAR_CONSTANT("104"), 5},
+ { UCHAR_CONSTANT("105"), 5},
+ { UCHAR_CONSTANT("106"), 5},
+ { UCHAR_CONSTANT("107"), 5},
+ { UCHAR_CONSTANT("108"), 5},
+ { UCHAR_CONSTANT("109"), 5},
+ { UCHAR_CONSTANT("110"), 5},
+ { UCHAR_CONSTANT("111"), 5},
+ { UCHAR_CONSTANT("112"), 5},
+ { UCHAR_CONSTANT("113"), 5},
+ { UCHAR_CONSTANT("114"), 5},
+ { UCHAR_CONSTANT("115"), 5},
+ { UCHAR_CONSTANT("116"), 5},
+ { UCHAR_CONSTANT("117"), 5},
+ { UCHAR_CONSTANT("118"), 5},
+ { UCHAR_CONSTANT("119"), 5},
+ { UCHAR_CONSTANT("120"), 5},
+ { UCHAR_CONSTANT("121"), 5},
+ { UCHAR_CONSTANT("122"), 5},
+ { UCHAR_CONSTANT("123"), 5},
+ { UCHAR_CONSTANT("124"), 5},
+ { UCHAR_CONSTANT("125"), 5},
+ { UCHAR_CONSTANT("126"), 5},
+ { UCHAR_CONSTANT("127"), 5},
+ { UCHAR_CONSTANT("128"), 5},
+ { UCHAR_CONSTANT("129"), 5},
+ { UCHAR_CONSTANT("130"), 5},
+ { UCHAR_CONSTANT("131"), 5},
+ { UCHAR_CONSTANT("132"), 5},
+ { UCHAR_CONSTANT("133"), 5},
+ { UCHAR_CONSTANT("134"), 5},
+ { UCHAR_CONSTANT("135"), 5},
+ { UCHAR_CONSTANT("136"), 5},
+ { UCHAR_CONSTANT("137"), 5},
+ { UCHAR_CONSTANT("138"), 5},
+ { UCHAR_CONSTANT("139"), 5},
+ { UCHAR_CONSTANT("140"), 5},
+ { UCHAR_CONSTANT("141"), 5},
+ { UCHAR_CONSTANT("142"), 5},
+ { UCHAR_CONSTANT("143"), 5},
+ { UCHAR_CONSTANT("144"), 5},
+ { UCHAR_CONSTANT("145"), 5},
+ { UCHAR_CONSTANT("146"), 5},
+ { UCHAR_CONSTANT("147"), 5},
+ { UCHAR_CONSTANT("148"), 5},
+ { UCHAR_CONSTANT("149"), 5},
+ { UCHAR_CONSTANT("150"), 5},
+ { UCHAR_CONSTANT("151"), 5},
+ { UCHAR_CONSTANT("152"), 5},
+ { UCHAR_CONSTANT("153"), 5},
+ { UCHAR_CONSTANT("154"), 5},
+ { UCHAR_CONSTANT("155"), 5},
+ { UCHAR_CONSTANT("156"), 5},
+ { UCHAR_CONSTANT("157"), 5},
+ { UCHAR_CONSTANT("158"), 5},
+ { UCHAR_CONSTANT("159"), 5},
+ { UCHAR_CONSTANT("160"), 5},
+ { UCHAR_CONSTANT("161"), 5},
+ { UCHAR_CONSTANT("162"), 5},
+ { UCHAR_CONSTANT("163"), 5},
+ { UCHAR_CONSTANT("164"), 5},
+ { UCHAR_CONSTANT("165"), 5},
+ { UCHAR_CONSTANT("166"), 5},
+ { UCHAR_CONSTANT("167"), 5},
+ { UCHAR_CONSTANT("168"), 5},
+ { UCHAR_CONSTANT("169"), 5},
+ { UCHAR_CONSTANT("170"), 5},
+ { UCHAR_CONSTANT("171"), 5},
+ { UCHAR_CONSTANT("172"), 5},
+ { UCHAR_CONSTANT("173"), 5},
+ { UCHAR_CONSTANT("174"), 5},
+ { UCHAR_CONSTANT("175"), 5},
+ { UCHAR_CONSTANT("176"), 5},
+ { UCHAR_CONSTANT("177"), 5},
+ { UCHAR_CONSTANT("178"), 5},
+ { UCHAR_CONSTANT("179"), 5},
+ { UCHAR_CONSTANT("180"), 5},
+ { UCHAR_CONSTANT("181"), 5},
+ { UCHAR_CONSTANT("182"), 5},
+ { UCHAR_CONSTANT("183"), 5},
+ { UCHAR_CONSTANT("184"), 5},
+ { UCHAR_CONSTANT("185"), 5},
+ { UCHAR_CONSTANT("186"), 5},
+ { UCHAR_CONSTANT("187"), 5},
+ { UCHAR_CONSTANT("188"), 5},
+ { UCHAR_CONSTANT("189"), 5},
+ { UCHAR_CONSTANT("190"), 5},
+ { UCHAR_CONSTANT("191"), 5}
+ };
+
+/*syslog facility names (as of RFC5424) */
+static char *syslog_fac_names[24] = { "kern", "user", "mail", "daemon", "auth", "syslog", "lpr",
+ "news", "uucp", "cron", "authpriv", "ftp", "ntp", "audit",
+ "alert", "clock", "local0", "local1", "local2", "local3",
+ "local4", "local5", "local6", "local7" };
+
+/* table of severity names (in numerical order)*/
+static char *syslog_severity_names[8] = { "emerg", "alert", "crit", "err", "warning", "notice", "info", "debug" };
+
+/* numerical values as string - this is the most efficient approach to convert severity
+ * and facility values to a numerical string... -- rgerhars, 2009-06-17
+ */
+
+static char *syslog_number_names[24] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14",
+ "15", "16", "17", "18", "19", "20", "21", "22", "23" };
/* some forward declarations */
static int getAPPNAMELen(msg_t *pM);
@@ -272,6 +438,7 @@ static inline rsRetVal msgBaseConstruct(msg_t **ppThis)
pM->iRefCount = 1;
pM->iSeverity = -1;
pM->iFacility = -1;
+ pM->offMSG = -1;
objConstructSetObjInfo(pM);
/* DEV debugging only! dbgprintf("msgConstruct\t0x%x, ref 1\n", (int)pM);*/
@@ -331,6 +498,16 @@ finalize_it:
}
+/* some free handlers for (slightly) complicated cases... All of them may be called
+ * with an empty element.
+ */
+static inline void freeTAG(msg_t *pThis)
+{
+ if(pThis->iLenTAG >= CONF_TAG_BUFSIZE)
+ free(pThis->TAG.pszTAG);
+}
+
+
BEGINobjDestruct(msg) /* be sure to specify the object type also in END and CODESTART macros! */
int currRefCount;
CODESTARTobjDestruct(msg)
@@ -344,24 +521,18 @@ CODESTARTobjDestruct(msg)
if(currRefCount == 0)
{
/* DEV Debugging Only! dbgprintf("msgDestruct\t0x%lx, RefCount now 0, doing DESTROY\n", (unsigned long)pThis); */
- free(pThis->pszRawMsg);
- free(pThis->pszTAG);
+ if(pThis->pszRawMsg != pThis->szRawMsg)
+ free(pThis->pszRawMsg);
+ freeTAG(pThis);
free(pThis->pszHOSTNAME);
free(pThis->pszInputName);
free(pThis->pszRcvFrom);
free(pThis->pszRcvFromIP);
- free(pThis->pszMSG);
- free(pThis->pszFacility);
- free(pThis->pszFacilityStr);
- free(pThis->pszSeverity);
- free(pThis->pszSeverityStr);
free(pThis->pszRcvdAt3164);
free(pThis->pszRcvdAt3339);
free(pThis->pszRcvdAt_SecFrac);
free(pThis->pszRcvdAt_MySQL);
free(pThis->pszRcvdAt_PgSQL);
- free(pThis->pszTIMESTAMP3164);
- free(pThis->pszTIMESTAMP3339);
free(pThis->pszTIMESTAMP_SecFrac);
free(pThis->pszTIMESTAMP_MySQL);
free(pThis->pszTIMESTAMP_PgSQL);
@@ -437,19 +608,23 @@ msg_t* MsgDup(msg_t* pOld)
pNew->msgFlags = pOld->msgFlags;
pNew->iProtocolVersion = pOld->iProtocolVersion;
pNew->ttGenTime = pOld->ttGenTime;
+ pNew->offMSG = pOld->offMSG;
/* enable this, if someone actually uses UxTradMsg, delete after some time has
* passed and nobody complained -- rgerhards, 2009-06-16
pNew->offAfterPRI = pOld->offAfterPRI;
*/
- memcpy(pNew->bufPRI, pOld->bufPRI, pOld->iLenPRI);
- pNew->iLenPRI = pOld->iLenPRI;
- tmpCOPYSZ(Severity);
- tmpCOPYSZ(SeverityStr);
- tmpCOPYSZ(Facility);
- tmpCOPYSZ(FacilityStr);
+ if(pOld->iLenTAG > 0) {
+ if(pOld->iLenTAG < CONF_TAG_BUFSIZE) {
+ memcpy(pNew->TAG.szBuf, pOld->TAG.szBuf, pOld->iLenTAG);
+ } else {
+ if((pNew->TAG.pszTAG = srUtilStrDup(pOld->TAG.pszTAG, pOld->iLenTAG)) == NULL) {
+ msgDestruct(&pNew);
+ return NULL;
+ }
+ pNew->iLenTAG = pOld->iLenTAG;
+ }
+ }
tmpCOPYSZ(RawMsg);
- tmpCOPYSZ(MSG);
- tmpCOPYSZ(TAG);
tmpCOPYSZ(HOSTNAME);
tmpCOPYSZ(RcvFrom);
@@ -493,6 +668,7 @@ static rsRetVal MsgSerialize(msg_t *pThis, strm_t *pStrm)
objSerializeSCALAR(pStrm, iProtocolVersion, SHORT);
objSerializeSCALAR(pStrm, iSeverity, SHORT);
objSerializeSCALAR(pStrm, iFacility, SHORT);
+ objSerializeSCALAR(pStrm, offMSG, SHORT);
objSerializeSCALAR(pStrm, msgFlags, INT);
objSerializeSCALAR(pStrm, ttGenTime, INT);
objSerializeSCALAR(pStrm, tRcvdAt, SYSLOGTIME);
@@ -502,9 +678,10 @@ static rsRetVal MsgSerialize(msg_t *pThis, strm_t *pStrm)
objSerializeSCALAR(pStrm, offsAfterPRI, SHORT);
*/
+ CHKiRet(obj.SerializeProp(pStrm, UCHAR_CONSTANT("pszTAG"), PROPTYPE_PSZ, (void*)
+ ((pThis->iLenTAG < CONF_TAG_BUFSIZE) ? pThis->TAG.szBuf : pThis->TAG.pszTAG)));
+
objSerializePTR(pStrm, pszRawMsg, PSZ);
- objSerializePTR(pStrm, pszMSG, PSZ);
- objSerializePTR(pStrm, pszTAG, PSZ);
objSerializePTR(pStrm, pszHOSTNAME, PSZ);
objSerializePTR(pStrm, pszInputName, PSZ);
objSerializePTR(pStrm, pszRcvFrom, PSZ);
@@ -557,18 +734,22 @@ msg_t *MsgAddRef(msg_t *pM)
static rsRetVal aquirePROCIDFromTAG(msg_t *pM)
{
register int i;
+ uchar *pszTag;
DEFiRet;
assert(pM != NULL);
+
if(pM->pCSPROCID != NULL)
return RS_RET_OK; /* we are already done ;) */
if(getProtocolVersion(pM) != 0)
return RS_RET_OK; /* we can only emulate if we have legacy format */
+ pszTag = (uchar*) ((pM->iLenTAG < CONF_TAG_BUFSIZE) ? pM->TAG.szBuf : pM->TAG.pszTAG);
+
/* find first '['... */
i = 0;
- while((i < pM->iLenTAG) && (pM->pszTAG[i] != '['))
+ while((i < pM->iLenTAG) && (pszTag[i] != '['))
++i;
if(!(i < pM->iLenTAG))
return RS_RET_OK; /* no [, so can not emulate... */
@@ -576,10 +757,10 @@ static rsRetVal aquirePROCIDFromTAG(msg_t *pM)
++i; /* skip '[' */
/* now obtain the PROCID string... */
- CHKiRet(rsCStrConstruct(&pM->pCSPROCID));
+ CHKiRet(cstrConstruct(&pM->pCSPROCID));
rsCStrSetAllocIncrement(pM->pCSPROCID, 16);
- while((i < pM->iLenTAG) && (pM->pszTAG[i] != ']')) {
- CHKiRet(rsCStrAppendChar(pM->pCSPROCID, pM->pszTAG[i]));
+ while((i < pM->iLenTAG) && (pszTag[i] != ']')) {
+ CHKiRet(cstrAppendChar(pM->pCSPROCID, pszTag[i]));
++i;
}
@@ -589,7 +770,7 @@ static rsRetVal aquirePROCIDFromTAG(msg_t *pM)
* the buffer and simply return. Note that this is NOT an error
* case!
*/
- rsCStrDestruct(&pM->pCSPROCID);
+ cstrDestruct(&pM->pCSPROCID);
FINALIZE;
}
@@ -619,22 +800,24 @@ finalize_it:
*/
static rsRetVal aquireProgramName(msg_t *pM)
{
- DEFiRet;
register int i;
+ uchar *pszTag;
+ DEFiRet;
assert(pM != NULL);
if(pM->pCSProgName == NULL) {
/* ok, we do not yet have it. So let's parse the TAG
* to obtain it.
*/
- CHKiRet(rsCStrConstruct(&pM->pCSProgName));
+ pszTag = (uchar*) ((pM->iLenTAG < CONF_TAG_BUFSIZE) ? pM->TAG.szBuf : pM->TAG.pszTAG);
+ CHKiRet(cstrConstruct(&pM->pCSProgName));
rsCStrSetAllocIncrement(pM->pCSProgName, 33);
for( i = 0
- ; (i < pM->iLenTAG) && isprint((int) pM->pszTAG[i])
- && (pM->pszTAG[i] != '\0') && (pM->pszTAG[i] != ':')
- && (pM->pszTAG[i] != '[') && (pM->pszTAG[i] != '/')
+ ; (i < pM->iLenTAG) && isprint((int) pszTag[i])
+ && (pszTag[i] != '\0') && (pszTag[i] != ':')
+ && (pszTag[i] != '[') && (pszTag[i] != '/')
; ++i) {
- CHKiRet(rsCStrAppendChar(pM->pCSProgName, pM->pszTAG[i]));
+ CHKiRet(cstrAppendChar(pM->pCSProgName, pszTag[i]));
}
CHKiRet(cstrFinalize(pM->pCSProgName));
}
@@ -653,14 +836,16 @@ finalize_it:
* This is especially important as this can be a very common case, e.g.
* when BSD syslog is acting as a sender.
* rgerhards, 2005-11-10.
+ * NOTE ********* 2009-06-18 / rgerhards *************
+ * This function is being obsoleted by the new handling. I keep it for
+ * a while, and for oversize tags it is somewhat less optimal than in previous
+ * versions. This should only happen very seldom.
*/
void moveHOSTNAMEtoTAG(msg_t *pM)
{
assert(pM != NULL);
- if(pM->pszTAG != NULL)
- free(pM->pszTAG);
- pM->pszTAG = pM->pszHOSTNAME;
- pM->iLenTAG = pM->iLenHOSTNAME;
+ MsgSetTAG(pM, pM->pszHOSTNAME, pM->iLenHOSTNAME);
+ free(pM->pszHOSTNAME);
pM->pszHOSTNAME = NULL;
pM->iLenHOSTNAME = 0;
}
@@ -690,11 +875,6 @@ char *getProtocolVersionString(msg_t *pM)
return(pM->iProtocolVersion ? "1" : "0");
}
-int getMSGLen(msg_t *pM)
-{
- return((pM == NULL) ? 0 : pM->iLenMSG);
-}
-
static char *getRawMsg(msg_t *pM)
{
@@ -719,42 +899,46 @@ char *getUxTradMsg(msg_t *pM)
}
*/
+
+int getMSGLen(msg_t *pM)
+{
+ return((pM == NULL) ? 0 : pM->iLenMSG);
+}
+
char *getMSG(msg_t *pM)
{
if(pM == NULL)
return "";
- else
- if(pM->pszMSG == NULL)
+ else {
+ if(pM->offMSG == -1)
return "";
else
- return (char*)pM->pszMSG;
+ return (char*)(pM->pszRawMsg + pM->offMSG);
+ }
}
/* Get PRI value as integer */
static int getPRIi(msg_t *pM)
{
- assert(pM != NULL);
return (pM->iFacility << 3) + (pM->iSeverity);
}
-/* Get PRI value in text form */
+/* Get PRI value in text form
+ */
static inline char *getPRI(msg_t *pM)
{
+ /* PRI is a number in the range 0..191. Thus, we use a simple lookup table to obtain the
+ * string value. It looks a bit clumpsy here in code ;)
+ */
+ int iPRI;
+
if(pM == NULL)
return "";
- /* there are some cases where bufPRI may not contain a valid string,
- * and then we need to build it.
- */
- MsgLock(pM);
- if(pM->bufPRI[0] == '\0') {
- snprintf((char*)pM->bufPRI, sizeof(pM->bufPRI), "<%d>", getPRIi(pM));
- }
- MsgUnlock(pM);
-
- return (char*)pM->bufPRI;
+ iPRI = getPRIi(pM);
+ return (iPRI > 191) ? "invld" : (char*)syslog_pri_names[iPRI].pszName;
}
@@ -766,12 +950,10 @@ static inline char *getTimeReported(msg_t *pM, enum tplFormatTypes eFmt)
switch(eFmt) {
case tplFmtDefault:
+ case tplFmtRFC3164Date:
MsgLock(pM);
if(pM->pszTIMESTAMP3164 == NULL) {
- if((pM->pszTIMESTAMP3164 = malloc(16)) == NULL) {
- MsgUnlock(pM);
- return "";
- }
+ pM->pszTIMESTAMP3164 = pM->pszTimestamp3164;
datetime.formatTimestamp3164(&pM->tTIMESTAMP, pM->pszTIMESTAMP3164, 16);
}
MsgUnlock(pM);
@@ -798,24 +980,10 @@ static inline char *getTimeReported(msg_t *pM, enum tplFormatTypes eFmt)
}
MsgUnlock(pM);
return(pM->pszTIMESTAMP_PgSQL);
- case tplFmtRFC3164Date:
- MsgLock(pM);
- if(pM->pszTIMESTAMP3164 == NULL) {
- if((pM->pszTIMESTAMP3164 = malloc(16)) == NULL) {
- MsgUnlock(pM);
- return "";
- }
- datetime.formatTimestamp3164(&pM->tTIMESTAMP, pM->pszTIMESTAMP3164, 16);
- }
- MsgUnlock(pM);
- return(pM->pszTIMESTAMP3164);
case tplFmtRFC3339Date:
MsgLock(pM);
if(pM->pszTIMESTAMP3339 == NULL) {
- if((pM->pszTIMESTAMP3339 = malloc(33)) == NULL) {
- MsgUnlock(pM);
- return ""; /* TODO: check this: can it cause a free() of constant memory?) */
- }
+ pM->pszTIMESTAMP3339 = pM->pszTimestamp3339;
datetime.formatTimestamp3339(&pM->tTIMESTAMP, pM->pszTIMESTAMP3339, 33);
}
MsgUnlock(pM);
@@ -917,101 +1085,67 @@ static inline char *getTimeGenerated(msg_t *pM, enum tplFormatTypes eFmt)
static inline char *getSeverity(msg_t *pM)
{
+ char *name = NULL;
+
if(pM == NULL)
return "";
- MsgLock(pM);
- if(pM->pszSeverity == NULL) {
- /* we use a 2 byte buffer - can only be one digit */
- if((pM->pszSeverity = malloc(2)) == NULL) { MsgUnlock(pM) ; return ""; }
- pM->iLenSeverity =
- snprintf((char*)pM->pszSeverity, 2, "%d", pM->iSeverity);
+ if(pM->iSeverity < 0 || pM->iSeverity > 7) {
+ name = "invld";
+ } else {
+ name = syslog_number_names[pM->iSeverity];
}
- MsgUnlock(pM);
- return((char*)pM->pszSeverity);
+
+ return name;
}
static inline char *getSeverityStr(msg_t *pM)
{
- syslogCODE *c;
- int val;
char *name = NULL;
if(pM == NULL)
return "";
- MsgLock(pM);
- if(pM->pszSeverityStr == NULL) {
- for(c = rs_prioritynames, val = pM->iSeverity; c->c_name; c++)
- if(c->c_val == val) {
- name = c->c_name;
- break;
- }
- if(name == NULL) {
- /* we use a 2 byte buffer - can only be one digit */
- if((pM->pszSeverityStr = malloc(2)) == NULL) { MsgUnlock(pM) ; return ""; }
- pM->iLenSeverityStr =
- snprintf((char*)pM->pszSeverityStr, 2, "%d", pM->iSeverity);
- } else {
- if((pM->pszSeverityStr = (uchar*) strdup(name)) == NULL) { MsgUnlock(pM) ; return ""; }
- pM->iLenSeverityStr = strlen((char*)name);
- }
+ if(pM->iSeverity < 0 || pM->iSeverity > 7) {
+ name = "invld";
+ } else {
+ name = syslog_severity_names[pM->iSeverity];
}
- MsgUnlock(pM);
- return((char*)pM->pszSeverityStr);
+
+ return name;
}
static inline char *getFacility(msg_t *pM)
{
+ char *name = NULL;
+
if(pM == NULL)
return "";
- MsgLock(pM);
- if(pM->pszFacility == NULL) {
- /* we use a 12 byte buffer - as of
- * syslog-protocol, facility can go
- * up to 2^32 -1
- */
- if((pM->pszFacility = malloc(12)) == NULL) { MsgUnlock(pM) ; return ""; }
- pM->iLenFacility =
- snprintf((char*)pM->pszFacility, 12, "%d", pM->iFacility);
+ if(pM->iFacility < 0 || pM->iFacility > 23) {
+ name = "invld";
+ } else {
+ name = syslog_number_names[pM->iFacility];
}
- MsgUnlock(pM);
- return((char*)pM->pszFacility);
+
+ return name;
}
static inline char *getFacilityStr(msg_t *pM)
{
- syslogCODE *c;
- int val;
char *name = NULL;
if(pM == NULL)
return "";
- MsgLock(pM);
- if(pM->pszFacilityStr == NULL) {
- for(c = rs_facilitynames, val = pM->iFacility << 3; c->c_name; c++)
- if(c->c_val == val) {
- name = c->c_name;
- break;
- }
- if(name == NULL) {
- /* we use a 12 byte buffer - as of
- * syslog-protocol, facility can go
- * up to 2^32 -1
- */
- if((pM->pszFacilityStr = malloc(12)) == NULL) { MsgUnlock(pM) ; return ""; }
- pM->iLenFacilityStr =
- snprintf((char*)pM->pszFacilityStr, 12, "%d", val >> 3);
- } else {
- if((pM->pszFacilityStr = (uchar*)strdup(name)) == NULL) { MsgUnlock(pM) ; return ""; }
- pM->iLenFacilityStr = strlen((char*)name);
- }
- }
- MsgUnlock(pM);
- return((char*)pM->pszFacilityStr);
+ if(pM->iFacility < 0 || pM->iFacility > 23) {
+ name = "invld";
+ } else {
+ name = syslog_fac_names[pM->iFacility];
+ }
+
+ return name;
}
@@ -1087,11 +1221,11 @@ rsRetVal MsgSetPROCID(msg_t *pMsg, char* pszPROCID)
ISOBJ_TYPE_assert(pMsg, msg);
if(pMsg->pCSPROCID == NULL) {
/* we need to obtain the object first */
- CHKiRet(rsCStrConstruct(&pMsg->pCSPROCID));
- rsCStrSetAllocIncrement(pMsg->pCSPROCID, 128);
+ CHKiRet(cstrConstruct(&pMsg->pCSPROCID));
}
/* if we reach this point, we have the object */
iRet = rsCStrSetSzStr(pMsg->pCSPROCID, (uchar*) pszPROCID);
+ CHKiRet(cstrFinalize(pMsg->pCSPROCID));
finalize_it:
RETiRet;
@@ -1120,7 +1254,8 @@ char *getPROCID(msg_t *pM)
MsgLock(pM);
if(pM->pCSPROCID == NULL)
aquirePROCIDFromTAG(pM);
- pszRet = (pM->pCSPROCID == NULL) ? "-" : (char*) rsCStrGetSzStrNoNULL(pM->pCSPROCID);
+ pszRet = (pM->pCSPROCID == NULL) ? "-" : (char*) cstrGetSzStrNoNULL(pM->pCSPROCID);
+ //pszRet = (pM->pCSPROCID == NULL) ? "-" : (char*) rsCStrGetSzStrNoNULL(pM->pCSPROCID);
MsgUnlock(pM);
return pszRet;
}
@@ -1161,8 +1296,8 @@ static inline char *getMSGID(msg_t *pM)
void MsgAssignTAG(msg_t *pMsg, uchar *pBuf)
{
assert(pMsg != NULL);
- pMsg->iLenTAG = (pBuf == NULL) ? 0 : strlen((char*)pBuf);
- pMsg->pszTAG = (uchar*) pBuf;
+ MsgSetTAG(pMsg, pBuf, ustrlen(pBuf));
+ free(pBuf);
}
@@ -1175,17 +1310,32 @@ void MsgSetRuleset(msg_t *pMsg, ruleset_t *pRuleset)
}
-/* rgerhards 2004-11-16: set TAG in msg object
+/* set TAG in msg object
+ * (rewritten 2009-06-18 rgerhards)
*/
-void MsgSetTAG(msg_t *pMsg, char* pszTAG)
+void MsgSetTAG(msg_t *pMsg, uchar* pszBuf, size_t lenBuf)
{
+ uchar *pBuf;
assert(pMsg != NULL);
- free(pMsg->pszTAG);
- pMsg->iLenTAG = strlen(pszTAG);
- if((pMsg->pszTAG = malloc(pMsg->iLenTAG + 1)) != NULL)
- memcpy(pMsg->pszTAG, pszTAG, pMsg->iLenTAG + 1);
- else
- dbgprintf("Could not allocate memory in MsgSetTAG()\n");
+
+ freeTAG(pMsg);
+
+ pMsg->iLenTAG = lenBuf;
+ if(pMsg->iLenTAG < CONF_TAG_BUFSIZE) {
+ /* small enough: use fixed buffer (faster!) */
+ pBuf = pMsg->TAG.szBuf;
+ } else {
+ if((pBuf = (uchar*) malloc(pMsg->iLenTAG + 1)) == NULL) {
+ /* truncate message, better than completely loosing it... */
+ pBuf = pMsg->TAG.szBuf;
+ pMsg->iLenTAG = CONF_TAG_BUFSIZE - 1;
+ } else {
+ pMsg->TAG.pszTAG = pBuf;
+ }
+ }
+
+ memcpy(pBuf, pszBuf, pMsg->iLenTAG);
+ pBuf[pMsg->iLenTAG] = '\0'; /* this also works with truncation! */
}
@@ -1202,13 +1352,13 @@ static void tryEmulateTAG(msg_t *pM)
uchar *pBuf;
assert(pM != NULL);
- if(pM->pszTAG != NULL)
+ if(pM->iLenTAG > 0)
return; /* done, no need to emulate */
if(getProtocolVersion(pM) == 1) {
if(!strcmp(getPROCID(pM), "-")) {
/* no process ID, use APP-NAME only */
- MsgSetTAG(pM, getAPPNAME(pM));
+ MsgSetTAG(pM, (uchar*) getAPPNAME(pM), getAPPNAMELen(pM));
} else {
/* now we can try to emulate */
iTAGLen = getAPPNAMELen(pM) + getPROCIDLen(pM) + 3;
@@ -1221,22 +1371,6 @@ static void tryEmulateTAG(msg_t *pM)
}
-#if 0 /* This method is currently not called, be we like to preserve it */
-static int getTAGLen(msg_t *pM)
-{
- if(pM == NULL)
- return 0;
- else {
- tryEmulateTAG(pM);
- if(pM->pszTAG == NULL)
- return 0;
- else
- return pM->iLenTAG;
- }
-}
-#endif
-
-
static inline char *getTAG(msg_t *pM)
{
char *ret;
@@ -1246,10 +1380,10 @@ static inline char *getTAG(msg_t *pM)
else {
MsgLock(pM);
tryEmulateTAG(pM);
- if(pM->pszTAG == NULL)
+ if(pM->iLenTAG == 0)
ret = "";
else
- ret = (char*) pM->pszTAG;
+ ret = (char*) ((pM->iLenTAG < CONF_TAG_BUFSIZE) ? pM->TAG.szBuf : pM->TAG.pszTAG);
MsgUnlock(pM);
}
return(ret);
@@ -1558,34 +1692,47 @@ void MsgSetHOSTNAME(msg_t *pMsg, uchar* pszHOSTNAME)
/* rgerhards 2004-11-09: set MSG in msg object
*/
-void MsgSetMSG(msg_t *pMsg, char* pszMSG)
+void MsgSetMSGoffs(msg_t *pMsg, short offs)
{
assert(pMsg != NULL);
- assert(pszMSG != NULL);
- if(pMsg->pszMSG != NULL)
- free(pMsg->pszMSG);
-
- pMsg->iLenMSG = strlen(pszMSG);
- if((pMsg->pszMSG = (uchar*) malloc(pMsg->iLenMSG + 1)) != NULL)
- memcpy(pMsg->pszMSG, pszMSG, pMsg->iLenMSG + 1);
- else
- dbgprintf("MsgSetMSG could not allocate memory for pszMSG buffer.");
+ pMsg->iLenMSG = ustrlen(pMsg->pszRawMsg + offs);
+ pMsg->offMSG = offs;
}
-/* rgerhards 2004-11-11: set RawMsg in msg object
+
+/* set raw message in message object. Size of message is provided.
+ * rgerhards, 2009-06-16
*/
-void MsgSetRawMsg(msg_t *pMsg, char* pszRawMsg)
+void MsgSetRawMsg(msg_t *pMsg, char* pszRawMsg, size_t lenMsg)
{
assert(pMsg != NULL);
- if(pMsg->pszRawMsg != NULL)
+ if(pMsg->pszRawMsg != pMsg->szRawMsg)
free(pMsg->pszRawMsg);
- pMsg->iLenRawMsg = strlen(pszRawMsg);
- if((pMsg->pszRawMsg = (uchar*) malloc(pMsg->iLenRawMsg + 1)) != NULL)
- memcpy(pMsg->pszRawMsg, pszRawMsg, pMsg->iLenRawMsg + 1);
- else
- dbgprintf("Could not allocate memory for pszRawMsg buffer.");
+ pMsg->iLenRawMsg = lenMsg;
+ if(pMsg->iLenRawMsg < CONF_RAWMSG_BUFSIZE) {
+ /* small enough: use fixed buffer (faster!) */
+ pMsg->pszRawMsg = pMsg->szRawMsg;
+ } else if((pMsg->pszRawMsg = (uchar*) malloc(pMsg->iLenRawMsg + 1)) == NULL) {
+ /* truncate message, better than completely loosing it... */
+ pMsg->pszRawMsg = pMsg->szRawMsg;
+ pMsg->iLenRawMsg = CONF_RAWMSG_BUFSIZE - 1;
+ }
+
+ memcpy(pMsg->pszRawMsg, pszRawMsg, pMsg->iLenRawMsg);
+ pMsg->pszRawMsg[pMsg->iLenRawMsg] = '\0'; /* this also works with truncation! */
+}
+
+
+/* set raw message in message object. Size of message is not provided. This
+ * function should only be used when it is unavoidable (and over time we should
+ * try to remove it altogether).
+ * rgerhards, 2009-06-16
+ */
+void MsgSetRawMsgWOSize(msg_t *pMsg, char* pszRawMsg)
+{
+ MsgSetRawMsg(pMsg, pszRawMsg, strlen(pszRawMsg));
}
@@ -1599,15 +1746,11 @@ void MsgSetRawMsg(msg_t *pMsg, char* pszRawMsg)
*/
char *textpri(char *pRes, size_t pResLen, int pri)
{
- syslogCODE *c_pri, *c_fac;
-
assert(pRes != NULL);
assert(pResLen > 0);
- for (c_fac = rs_facilitynames; c_fac->c_name && !(c_fac->c_val == LOG_FAC(pri)<<3); c_fac++);
- for (c_pri = rs_prioritynames; c_pri->c_name && !(c_pri->c_val == LOG_PRI(pri)); c_pri++);
-
- snprintf (pRes, pResLen, "%s.%s<%d>", c_fac->c_name, c_pri->c_name, pri);
+ snprintf(pRes, pResLen, "%s.%s<%d>", syslog_fac_names[LOG_FAC(pri)],
+ syslog_severity_names[LOG_PRI(pri)], pri);
return pRes;
}
@@ -1702,15 +1845,18 @@ static uchar *getNOW(eNOWType eNow)
* rgerhards 2005-09-15
*/
char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
- cstr_t *pCSPropName, unsigned short *pbMustBeFreed)
+ cstr_t *pCSPropName, size_t *pPropLen,
+ unsigned short *pbMustBeFreed)
{
uchar *pName;
char *pRes; /* result pointer */
+ int bufLen = -1; /* length of string or -1, if not known */
char *pBufStart;
char *pBuf;
int iLen;
short iOffs;
+ BEGINfunc
#ifdef FEATURE_REGEXP
/* Variables necessary for regular expression matching */
size_t nmatch = 10;
@@ -1732,6 +1878,14 @@ char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
* property names. These come after || in the ifs below. */
if(!strcmp((char*) pName, "msg")) {
pRes = getMSG(pMsg);
+ bufLen = getMSGLen(pMsg);
+ } else if(!strcmp((char*) pName, "timestamp")
+ || !strcmp((char*) pName, "timereported")) {
+ pRes = getTimeReported(pMsg, pTpe->data.field.eDateFormat);
+ } else if(!strcmp((char*) pName, "hostname") || !strcmp((char*) pName, "source")) {
+ pRes = getHOSTNAME(pMsg);
+ } else if(!strcmp((char*) pName, "syslogtag")) {
+ pRes = getTAG(pMsg);
} else if(!strcmp((char*) pName, "rawmsg")) {
pRes = getRawMsg(pMsg);
/* enable this, if someone actually uses UxTradMsg, delete after some time has
@@ -1745,10 +1899,6 @@ char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
pRes = (char*) getRcvFrom(pMsg);
} else if(!strcmp((char*) pName, "fromhost-ip")) {
pRes = (char*) getRcvFromIP(pMsg);
- } else if(!strcmp((char*) pName, "source") || !strcmp((char*) pName, "hostname")) {
- pRes = getHOSTNAME(pMsg);
- } else if(!strcmp((char*) pName, "syslogtag")) {
- pRes = getTAG(pMsg);
} else if(!strcmp((char*) pName, "pri")) {
pRes = getPRI(pMsg);
} else if(!strcmp((char*) pName, "pri-text")) {
@@ -1772,9 +1922,6 @@ char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
pRes = getSeverityStr(pMsg);
} else if(!strcmp((char*) pName, "timegenerated")) {
pRes = getTimeGenerated(pMsg, pTpe->data.field.eDateFormat);
- } else if(!strcmp((char*) pName, "timereported")
- || !strcmp((char*) pName, "timestamp")) {
- pRes = getTimeReported(pMsg, pTpe->data.field.eDateFormat);
} else if(!strcmp((char*) pName, "programname")) {
pRes = getProgramName(pMsg);
} else if(!strcmp((char*) pName, "protocol-version")) {
@@ -1897,6 +2044,7 @@ char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
}
/* now copy */
memcpy(pBuf, pFld, iLen);
+ bufLen = iLen;
pBuf[iLen] = '\0'; /* terminate it */
if(*pbMustBeFreed == 1)
free(pRes);
@@ -1941,6 +2089,7 @@ char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
}
}
/* OK, we are at the begin - now let's copy... */
+ bufLen = iLen;
while(*pSb && iLen) {
*pBuf++ = *pSb;
++pSb;
@@ -2036,6 +2185,7 @@ char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
/* Lets copy the matched substring to the buffer */
memcpy(pB, pRes + iOffs + pmatch[pTpe->data.field.iSubMatchToUse].rm_so, iLenBuf);
+ bufLen = iLenBuf - 1;
pB[iLenBuf] = '\0';/* terminate string, did not happen before */
if (*pbMustBeFreed == 1)
@@ -2061,28 +2211,13 @@ char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
/* now check if we need to do our "SP if first char is non-space" hack logic */
if(*pRes && pTpe->data.field.options.bSPIffNo1stSP) {
- char *pB;
- uchar cFirst = *pRes;
-
/* here, we always destruct the buffer and return a new one */
- pB = (char *) malloc(2 * sizeof(char));
- if(pB == NULL) {
- if(*pbMustBeFreed == 1)
- free(pRes);
- *pbMustBeFreed = 0;
- return "**OUT OF MEMORY**";
- }
- pRes = pB;
- *pbMustBeFreed = 1;
-
- if(cFirst == ' ') {
- /* if we have a SP, we must return an empty string */
- *pRes = '\0'; /* empty */
- } else {
- /* if it is no SP, we need to return one */
- *pRes = ' ';
- *(pRes+1) = '\0';
- }
+ uchar cFirst = *pRes; /* save first char */
+ if(*pbMustBeFreed == 1)
+ free(pRes);
+ pRes = (cFirst == ' ') ? "" : " ";
+ bufLen = (cFirst == ' ') ? 0 : 1;
+ *pbMustBeFreed = 0;
}
if(*pRes) {
@@ -2091,11 +2226,12 @@ char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
*/
if(pTpe->data.field.eCaseConv != tplCaseConvNo) {
/* we need to obtain a private copy */
- int iBufLen = strlen(pRes);
+ if(bufLen == -1)
+ bufLen = strlen(pRes);
char *pBStart;
char *pB;
char *pSrc;
- pBStart = pB = malloc((iBufLen + 1) * sizeof(char));
+ pBStart = pB = malloc((bufLen + 1) * sizeof(char));
if(pB == NULL) {
if(*pbMustBeFreed == 1)
free(pRes);
@@ -2157,6 +2293,7 @@ char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
if(*pbMustBeFreed == 1)
free(pRes);
pRes = pDstStart;
+ bufLen = iLenBuf;
*pbMustBeFreed = 1;
}
} else if(pTpe->data.field.options.bSpaceCC) {
@@ -2175,7 +2312,9 @@ char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
*pDst = ' ';
}
} else {
- pDst = pDstStart = malloc(strlen(pRes) + 1);
+ if(bufLen == -1)
+ bufLen = strlen(pRes);
+ pDst = pDstStart = malloc(bufLen + 1);
if(pDst == NULL) {
if(*pbMustBeFreed == 1)
free(pRes);
@@ -2236,6 +2375,7 @@ char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
if(*pbMustBeFreed == 1)
free(pRes);
pRes = pBStart;
+ bufLen = -1;
*pbMustBeFreed = 1;
}
}
@@ -2275,6 +2415,7 @@ char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
if(*pbMustBeFreed == 1)
free(pRes);
pRes = pDstStart;
+ bufLen = -1; /* TODO: can we do better? */
*pbMustBeFreed = 1;
}
} else {
@@ -2293,7 +2434,9 @@ char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
*pDst++ = '_';
}
} else {
- pDst = pDstStart = malloc(strlen(pRes) + 1);
+ if(bufLen == -1)
+ bufLen = strlen(pRes);
+ pDst = pDstStart = malloc(bufLen + 1);
if(pDst == NULL) {
if(*pbMustBeFreed == 1)
free(pRes);
@@ -2331,16 +2474,20 @@ char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
if(*pbMustBeFreed == 1)
free(pRes);
pRes = "_";
+ bufLen = 1;
*pbMustBeFreed = 0;
}
}
/* Now drop last LF if present (pls note that this must not be done
- * if bEscapeCC was set!
+ * if bEscapeCC was set)!
*/
if(pTpe->data.field.options.bDropLastLF && !pTpe->data.field.options.bEscapeCC) {
- int iLn = strlen(pRes);
+ int iLn;
char *pB;
+ if(bufLen == -1)
+ bufLen = strlen(pRes);
+ iLn = bufLen;
if(iLn > 0 && *(pRes + iLn - 1) == '\n') {
/* we have a LF! */
/* check if we need to obtain a private copy */
@@ -2356,6 +2503,7 @@ char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
*pbMustBeFreed = 1;
}
*(pRes + iLn - 1) = '\0'; /* drop LF ;) */
+ --bufLen;
}
}
@@ -2366,10 +2514,13 @@ char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
*/
if(pTpe->data.field.options.bCSV) {
/* we need to obtain a private copy, as we need to at least add the double quotes */
- int iBufLen = strlen(pRes);
+ int iBufLen;
char *pBStart;
char *pDst;
char *pSrc;
+ if(bufLen == -1)
+ bufLen = strlen(pRes);
+ iBufLen = bufLen;
/* the malloc may be optimized, we currently use the worst case... */
pBStart = pDst = malloc((2 * iBufLen + 3) * sizeof(char));
if(pDst == NULL) {
@@ -2390,10 +2541,16 @@ char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
if(*pbMustBeFreed == 1)
free(pRes);
pRes = pBStart;
+ bufLen = -1;
*pbMustBeFreed = 1;
}
+ if(bufLen == -1)
+ bufLen = strlen(pRes);
+ *pPropLen = bufLen;
+
/*dbgprintf("MsgGetProp(\"%s\"): \"%s\"\n", pName, pRes); only for verbose debug logging */
+ ENDfunc
return(pRes);
}
@@ -2408,6 +2565,7 @@ msgGetMsgVar(msg_t *pThis, cstr_t *pstrPropName, var_t **ppVar)
{
DEFiRet;
var_t *pVar;
+ size_t propLen;
uchar *pszProp = NULL;
cstr_t *pstrProp;
unsigned short bMustBeFreed = 0;
@@ -2421,7 +2579,7 @@ msgGetMsgVar(msg_t *pThis, cstr_t *pstrPropName, var_t **ppVar)
CHKiRet(var.ConstructFinalize(pVar));
/* always call MsgGetProp() without a template specifier */
- pszProp = (uchar*) MsgGetProp(pThis, NULL, pstrPropName, &bMustBeFreed);
+ pszProp = (uchar*) MsgGetProp(pThis, NULL, pstrPropName, &propLen, &bMustBeFreed);
/* now create a string object out of it and hand that over to the var */
CHKiRet(rsCStrConstructFromszStr(&pstrProp, pszProp));
@@ -2460,19 +2618,19 @@ rsRetVal MsgSetProperty(msg_t *pThis, var_t *pProp)
pThis->iFacility = pProp->val.num;
} else if(isProp("msgFlags")) {
pThis->msgFlags = pProp->val.num;
+ } else if(isProp("offMSG")) {
+ pThis->offMSG = pProp->val.num;
} else if(isProp("pszRawMsg")) {
- MsgSetRawMsg(pThis, (char*) rsCStrGetSzStrNoNULL(pProp->val.pStr));
+ MsgSetRawMsg(pThis, (char*) rsCStrGetSzStrNoNULL(pProp->val.pStr), cstrLen(pProp->val.pStr));
/* enable this, if someone actually uses UxTradMsg, delete after some time has
* passed and nobody complained -- rgerhards, 2009-06-16
} else if(isProp("offAfterPRI")) {
pThis->offAfterPRI = pProp->val.num;
*/
- } else if(isProp("pszMSG")) {
- MsgSetMSG(pThis, (char*) rsCStrGetSzStrNoNULL(pProp->val.pStr));
} else if(isProp("pszUxTradMsg")) {
/*IGNORE*/; /* this *was* a property, but does no longer exist */
} else if(isProp("pszTAG")) {
- MsgSetTAG(pThis, (char*) rsCStrGetSzStrNoNULL(pProp->val.pStr));
+ MsgSetTAG(pThis, rsCStrGetSzStrNoNULL(pProp->val.pStr), cstrLen(pProp->val.pStr));
} else if(isProp("pszInputName")) {
MsgSetInputName(pThis, rsCStrGetSzStrNoNULL(pProp->val.pStr), rsCStrLen(pProp->val.pStr));
} else if(isProp("pszRcvFromIP")) {
@@ -2495,6 +2653,8 @@ rsRetVal MsgSetProperty(msg_t *pThis, var_t *pProp)
memcpy(&pThis->tRcvdAt, &pProp->val.vSyslogTime, sizeof(struct syslogTime));
} else if(isProp("tTIMESTAMP")) {
memcpy(&pThis->tTIMESTAMP, &pProp->val.vSyslogTime, sizeof(struct syslogTime));
+ } else if(isProp("pszMSG")) {
+ dbgprintf("no longer supported property pszMSG silently ignored\n");
}
RETiRet;
diff --git a/runtime/msg.h b/runtime/msg.h
index 74ff9e60..ec18b29d 100644
--- a/runtime/msg.h
+++ b/runtime/msg.h
@@ -28,6 +28,10 @@
#ifndef MSG_H_INCLUDED
#define MSG_H_INCLUDED 1
+/* some configuration constants */
+#define CONF_RAWMSG_BUFSIZE 101
+#define CONF_TAG_BUFSIZE 33 /* RFC says 32 chars (+ \0), but in practice we see longer ones... */
+
#include <pthread.h>
#include "obj.h"
#include "syslogd-types.h"
@@ -50,13 +54,13 @@
*/
struct msg {
BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */
- pthread_mutexattr_t mutAttr;
- bool bDoLock; /* use the mutex? */
- pthread_mutex_t mut;
flowControl_t flowCtlType; /**< type of flow control we can apply, for enqueueing, needs not to be persisted because
once data has entered the queue, this property is no longer needed. */
+ pthread_mutexattr_t mutAttr;
+ pthread_mutex_t mut;
+ bool bDoLock; /* use the mutex? */
+ bool bParseHOSTNAME; /* should the hostname be parsed from the message? */
short iRefCount; /* reference counter (0 = unused) */
- short bParseHOSTNAME; /* should the hostname be parsed from the message? */
/* background: the hostname is not present on "regular" messages
* received via UNIX domain sockets from the same machine. However,
* it is available when we have a forwarder (e.g. rfc3195d) using local
@@ -64,28 +68,13 @@ struct msg {
* resolve all these issues... rgerhards, 2005-10-06
*/
short iSeverity; /* the severity 0..7 */
- uchar *pszSeverity; /* severity as string... */
- int iLenSeverity; /* ... and its length. */
- uchar *pszSeverityStr; /* severity name... */
- int iLenSeverityStr; /* ... and its length. */
short iFacility; /* Facility code 0 .. 23*/
- uchar *pszFacility; /* Facility as string... */
- int iLenFacility; /* ... and its length. */
- uchar *pszFacilityStr; /* facility name... */
- int iLenFacilityStr; /* ... and its length. */
- uchar bufPRI[5]; /* PRI as string */
- int iLenPRI; /* and its length */
- uchar *pszRawMsg; /* message as it was received on the
- * wire. This is important in case we
- * need to preserve cryptographic verifiers.
- */
- short offAfterPRI; /* offset, at which raw message WITHOUT PRI part starts in pszRawMsg */
+ uchar *pszRawMsg; /* message as it was received on the wire. This is important in case we
+ * need to preserve cryptographic verifiers. */
int iLenRawMsg; /* length of raw message */
- uchar *pszMSG; /* the MSG part itself */
+ short offAfterPRI; /* offset, at which raw message WITHOUT PRI part starts in pszRawMsg */
+ short offMSG; /* offset at which the MSG part starts in pszRawMsg */
int iLenMSG; /* Length of the MSG part */
- uchar *pszUxTradMsg; /* the traditional UNIX message */
- int iLenUxTradMsg;/* Length of the traditional UNIX message */
- uchar *pszTAG; /* pointer to tag value */
int iLenTAG; /* Length of the TAG part */
uchar *pszHOSTNAME; /* HOSTNAME from syslog message */
int iLenHOSTNAME; /* Length of HOSTNAME */
@@ -122,7 +111,14 @@ struct msg {
char *pszTIMESTAMP_SecFrac;/* TIMESTAMP fractional seconds (always 6 characters) */
int msgFlags; /* flags associated with this message */
ruleset_t *pRuleset; /* ruleset to be used for processing this message */
- /* now follow fixed-size buffers to safe some time otherwise used for allocs */
+ /* some fixed-size buffers to save malloc()/free() for frequently used fields (from the default templates) */
+ uchar szRawMsg[CONF_RAWMSG_BUFSIZE]; /* most messages are small, and these are stored here (without malloc/free!) */
+ union {
+ uchar *pszTAG; /* pointer to tag value */
+ uchar szBuf[CONF_TAG_BUFSIZE];
+ } TAG;
+ char pszTimestamp3164[16];
+ char pszTimestamp3339[33];
};
@@ -151,7 +147,7 @@ rsRetVal MsgSetAPPNAME(msg_t *pMsg, char* pszAPPNAME);
rsRetVal MsgSetPROCID(msg_t *pMsg, char* pszPROCID);
rsRetVal MsgSetMSGID(msg_t *pMsg, char* pszMSGID);
void MsgAssignTAG(msg_t *pMsg, uchar *pBuf);
-void MsgSetTAG(msg_t *pMsg, char* pszTAG);
+void MsgSetTAG(msg_t *pMsg, uchar* pszBuf, size_t lenBuf);
void MsgSetRuleset(msg_t *pMsg, ruleset_t*);
rsRetVal MsgSetFlowControlType(msg_t *pMsg, flowControl_t eFlowCtl);
rsRetVal MsgSetStructuredData(msg_t *pMsg, char* pszStrucData);
@@ -160,11 +156,12 @@ rsRetVal MsgSetRcvFromIP(msg_t *pMsg, uchar* pszRcvFromIP);
void MsgAssignHOSTNAME(msg_t *pMsg, char *pBuf);
void MsgSetHOSTNAME(msg_t *pMsg, uchar* pszHOSTNAME);
rsRetVal MsgSetAfterPRIOffs(msg_t *pMsg, short offs);
-void MsgSetMSG(msg_t *pMsg, char* pszMSG);
-void MsgSetRawMsg(msg_t *pMsg, char* pszRawMsg);
+void MsgSetMSGoffs(msg_t *pMsg, short offs);
+void MsgSetRawMsgWOSize(msg_t *pMsg, char* pszRawMsg);
+void MsgSetRawMsg(msg_t *pMsg, char* pszRawMsg, size_t lenMsg);
void moveHOSTNAMEtoTAG(msg_t *pM);
char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
- cstr_t *pCSPropName, unsigned short *pbMustBeFreed);
+ cstr_t *pCSPropName, size_t *pPropLen, unsigned short *pbMustBeFreed);
char *textpri(char *pRes, size_t pResLen, int pri);
rsRetVal msgGetMsgVar(msg_t *pThis, cstr_t *pstrPropName, var_t **ppVar);
rsRetVal MsgEnableThreadSafety(void);
@@ -182,11 +179,6 @@ char *getProgramName(msg_t *pM);
int getProgramNameLen(msg_t *pM);
uchar *getRcvFrom(msg_t *pM);
-#if 0
-char *getUxTradMsg(msg_t *pM);
-int MsgSetUxTradMsg(msg_t *pMsg, char* pszUxTradMsg);
-#endif
-
/* The MsgPrepareEnqueue() function is a macro for performance reasons.
* It needs one global variable to work. This is acceptable, as it gains
* us quite some performance and is fully abstracted using this header file.
diff --git a/runtime/nsd_gtls.c b/runtime/nsd_gtls.c
index 19dc8678..79ceffb3 100644
--- a/runtime/nsd_gtls.c
+++ b/runtime/nsd_gtls.c
@@ -710,16 +710,16 @@ gtlsGetCN(nsd_gtls_t *pThis, gnutls_x509_crt *pCert, cstr_t **ppstrCN)
}
/* we found a common name, now extract it */
- CHKiRet(rsCStrConstruct(&pstrCN));
+ CHKiRet(cstrConstruct(&pstrCN));
while(szDN[i] != '\0' && szDN[i] != ',') {
if(szDN[i] == '\\') {
/* hex escapes are not implemented */
++i; /* escape char processed */
if(szDN[i] == '\0')
ABORT_FINALIZE(RS_RET_CERT_INVALID_DN);
- CHKiRet(rsCStrAppendChar(pstrCN, szDN[i]));
+ CHKiRet(cstrAppendChar(pstrCN, szDN[i]));
} else {
- CHKiRet(rsCStrAppendChar(pstrCN, szDN[i]));
+ CHKiRet(cstrAppendChar(pstrCN, szDN[i]));
}
++i; /* char processed */
}
@@ -734,7 +734,7 @@ gtlsGetCN(nsd_gtls_t *pThis, gnutls_x509_crt *pCert, cstr_t **ppstrCN)
finalize_it:
if(iRet != RS_RET_OK) {
if(pstrCN != NULL)
- rsCStrDestruct(&pstrCN);
+ cstrDestruct(&pstrCN);
}
RETiRet;
@@ -761,7 +761,7 @@ gtlsChkPeerFingerprint(nsd_gtls_t *pThis, gnutls_x509_crt *pCert)
size = sizeof(fingerprint);
CHKgnutls(gnutls_x509_crt_get_fingerprint(*pCert, GNUTLS_DIG_SHA1, fingerprint, &size));
CHKiRet(GenFingerprintStr(fingerprint, size, &pstrFingerprint));
- dbgprintf("peer's certificate SHA1 fingerprint: %s\n", rsCStrGetSzStr(pstrFingerprint));
+ dbgprintf("peer's certificate SHA1 fingerprint: %s\n", cstrGetSzStr(pstrFingerprint));
/* now search through the permitted peers to see if we can find a permitted one */
bFoundPositiveMatch = 0;
@@ -779,7 +779,7 @@ gtlsChkPeerFingerprint(nsd_gtls_t *pThis, gnutls_x509_crt *pCert)
if(pThis->bReportAuthErr == 1) {
errno = 0;
errmsg.LogError(0, RS_RET_INVALID_FINGERPRINT, "error: peer fingerprint '%s' unknown - we are "
- "not permitted to talk to it", rsCStrGetSzStr(pstrFingerprint));
+ "not permitted to talk to it", cstrGetSzStr(pstrFingerprint));
pThis->bReportAuthErr = 0;
}
ABORT_FINALIZE(RS_RET_INVALID_FINGERPRINT);
@@ -787,7 +787,7 @@ gtlsChkPeerFingerprint(nsd_gtls_t *pThis, gnutls_x509_crt *pCert)
finalize_it:
if(pstrFingerprint != NULL)
- rsCStrDestruct(&pstrFingerprint);
+ cstrDestruct(&pstrFingerprint);
RETiRet;
}
@@ -874,10 +874,10 @@ gtlsChkPeerName(nsd_gtls_t *pThis, gnutls_x509_crt *pCert)
/* if we did not succeed so far, we try the CN part of the DN... */
CHKiRet(gtlsGetCN(pThis, pCert, &pstrCN));
if(pstrCN != NULL) { /* NULL if there was no CN present */
- dbgprintf("gtls now checking auth for CN '%s'\n", rsCStrGetSzStr(pstrCN));
- snprintf((char*)lnBuf, sizeof(lnBuf), "CN: %s; ", rsCStrGetSzStr(pstrCN));
+ dbgprintf("gtls now checking auth for CN '%s'\n", cstrGetSzStr(pstrCN));
+ snprintf((char*)lnBuf, sizeof(lnBuf), "CN: %s; ", cstrGetSzStr(pstrCN));
CHKiRet(rsCStrAppendStr(pStr, lnBuf));
- CHKiRet(gtlsChkOnePeerName(pThis, rsCStrGetSzStr(pstrCN), &bFoundPositiveMatch));
+ CHKiRet(gtlsChkOnePeerName(pThis, cstrGetSzStr(pstrCN), &bFoundPositiveMatch));
}
}
@@ -888,7 +888,7 @@ gtlsChkPeerName(nsd_gtls_t *pThis, gnutls_x509_crt *pCert)
errno = 0;
errmsg.LogError(0, RS_RET_INVALID_FINGERPRINT, "error: peer name not authorized - "
"not permitted to talk to it. Names: %s",
- rsCStrGetSzStr(pStr));
+ cstrGetSzStr(pStr));
pThis->bReportAuthErr = 0;
}
ABORT_FINALIZE(RS_RET_INVALID_FINGERPRINT);
@@ -1010,8 +1010,8 @@ gtlsChkPeerCertValidity(nsd_gtls_t *pThis)
errmsg.LogError(0, NO_ERRCODE, "not permitted to talk to peer, certificate invalid: %s",
pszErrCause);
gtlsGetCertInfo(pThis, &pStr);
- errmsg.LogError(0, NO_ERRCODE, "invalid cert info: %s", rsCStrGetSzStr(pStr));
- rsCStrDestruct(&pStr);
+ errmsg.LogError(0, NO_ERRCODE, "invalid cert info: %s", cstrGetSzStr(pStr));
+ cstrDestruct(&pStr);
ABORT_FINALIZE(RS_RET_CERT_INVALID);
}
@@ -1032,8 +1032,8 @@ gtlsChkPeerCertValidity(nsd_gtls_t *pThis)
else if(ttCert > ttNow) {
errmsg.LogError(0, RS_RET_CERT_NOT_YET_ACTIVE, "not permitted to talk to peer: certificate %d not yet active", i);
gtlsGetCertInfo(pThis, &pStr);
- errmsg.LogError(0, RS_RET_CERT_NOT_YET_ACTIVE, "invalid cert info: %s", rsCStrGetSzStr(pStr));
- rsCStrDestruct(&pStr);
+ errmsg.LogError(0, RS_RET_CERT_NOT_YET_ACTIVE, "invalid cert info: %s", cstrGetSzStr(pStr));
+ cstrDestruct(&pStr);
ABORT_FINALIZE(RS_RET_CERT_NOT_YET_ACTIVE);
}
@@ -1043,8 +1043,8 @@ gtlsChkPeerCertValidity(nsd_gtls_t *pThis)
else if(ttCert < ttNow) {
errmsg.LogError(0, RS_RET_CERT_EXPIRED, "not permitted to talk to peer: certificate %d expired", i);
gtlsGetCertInfo(pThis, &pStr);
- errmsg.LogError(0, RS_RET_CERT_EXPIRED, "invalid cert info: %s", rsCStrGetSzStr(pStr));
- rsCStrDestruct(&pStr);
+ errmsg.LogError(0, RS_RET_CERT_EXPIRED, "invalid cert info: %s", cstrGetSzStr(pStr));
+ cstrDestruct(&pStr);
ABORT_FINALIZE(RS_RET_CERT_EXPIRED);
}
gnutls_x509_crt_deinit(cert);
diff --git a/runtime/obj.c b/runtime/obj.c
index f2cb447e..6ca05cc4 100644
--- a/runtime/obj.c
+++ b/runtime/obj.c
@@ -440,11 +440,11 @@ objDeserializeEmbedStr(cstr_t **ppStr, strm_t *pStrm)
assert(ppStr != NULL);
- CHKiRet(rsCStrConstruct(&pStr));
+ CHKiRet(cstrConstruct(&pStr));
NEXTC;
while(c != ':') {
- CHKiRet(rsCStrAppendChar(pStr, c));
+ CHKiRet(cstrAppendChar(pStr, c));
NEXTC;
}
CHKiRet(cstrFinalize(pStr));
@@ -453,7 +453,7 @@ objDeserializeEmbedStr(cstr_t **ppStr, strm_t *pStrm)
finalize_it:
if(iRet != RS_RET_OK && pStr != NULL)
- rsCStrDestruct(&pStr);
+ cstrDestruct(&pStr);
RETiRet;
}
@@ -508,11 +508,11 @@ static rsRetVal objDeserializeStr(cstr_t **ppCStr, int iLen, strm_t *pStrm)
assert(ppCStr != NULL);
assert(iLen >= 0);
- CHKiRet(rsCStrConstruct(&pCStr));
+ CHKiRet(cstrConstruct(&pCStr));
NEXTC;
for(i = 0 ; i < iLen ; ++i) {
- CHKiRet(rsCStrAppendChar(pCStr, c));
+ CHKiRet(cstrAppendChar(pCStr, c));
NEXTC;
}
CHKiRet(cstrFinalize(pCStr));
@@ -524,7 +524,7 @@ static rsRetVal objDeserializeStr(cstr_t **ppCStr, int iLen, strm_t *pStrm)
finalize_it:
if(iRet != RS_RET_OK && pCStr != NULL)
- rsCStrDestruct(&pCStr);
+ cstrDestruct(&pCStr);
RETiRet;
}
@@ -622,11 +622,11 @@ static rsRetVal objDeserializeProperty(var_t *pProp, strm_t *pStrm)
}
/* get the property name first */
- CHKiRet(rsCStrConstruct(&pProp->pcsName));
+ CHKiRet(cstrConstruct(&pProp->pcsName));
NEXTC;
while(c != ':') {
- CHKiRet(rsCStrAppendChar(pProp->pcsName, c));
+ CHKiRet(cstrAppendChar(pProp->pcsName, c));
NEXTC;
}
CHKiRet(cstrFinalize(pProp->pcsName));
diff --git a/runtime/parser.c b/runtime/parser.c
index 0b45bfd5..75cde343 100644
--- a/runtime/parser.c
+++ b/runtime/parser.c
@@ -114,10 +114,8 @@ static inline rsRetVal uncompressMessage(msg_t *pMsg)
"Message ignored.", ret);
FINALIZE; /* unconditional exit, nothing left to do... */
}
- free(pMsg->pszRawMsg);
- pMsg->pszRawMsg = deflateBuf;
- pMsg->iLenRawMsg = iLenDefBuf;
- deflateBuf = NULL; /* logically "freed" - caller is now responsible */
+ MsgSetRawMsg(pMsg, (char*)deflateBuf, iLenDefBuf);
+ free(deflateBuf);
}
finalize_it:
if(deflateBuf != NULL)
@@ -165,6 +163,8 @@ sanitizeMessage(msg_t *pMsg)
size_t iSrc;
size_t iDst;
size_t iMaxLine;
+ size_t maxDest;
+ uchar szSanBuf[32*1024]; /* buffer used for sanitizing a string */
assert(pMsg != NULL);
@@ -205,70 +205,43 @@ sanitizeMessage(msg_t *pMsg)
}
}
}
- if(bNeedSanitize == 0) {
- /* what a shame - we do not have a \0 byte...
- * TODO: think about adding it or otherwise be able to use it...
- */
- uchar *pRaw;
- CHKmalloc(pRaw = realloc(pMsg->pszRawMsg, pMsg->iLenRawMsg + 1));
- pRaw[pMsg->iLenRawMsg] = '\0';
- pMsg->pszRawMsg = pRaw;
+
+ if(!bNeedSanitize)
FINALIZE;
- }
/* now copy over the message and sanitize it */
- /* TODO: can we get cheaper memory alloc? {alloca()?}*/
iMaxLine = glbl.GetMaxLine();
- CHKmalloc(pDst = malloc(sizeof(uchar) * (iMaxLine + 1)));
+ maxDest = lenMsg * 4; /* message can grow at most four-fold */
+ if(maxDest > iMaxLine)
+ maxDest = iMaxLine; /* but not more than the max size! */
+ if(maxDest < sizeof(szSanBuf))
+ pDst = szSanBuf;
+ else
+ CHKmalloc(pDst = malloc(sizeof(uchar) * (iMaxLine + 1)));
iSrc = iDst = 0;
- while(iSrc < lenMsg && iDst < iMaxLine) {
+ while(iSrc < lenMsg && iDst < maxDest - 3) { /* leave some space if last char must be escaped */
if(pszMsg[iSrc] == '\0') { /* guard against \0 characters... */
- /* changed to the sequence (somewhat) proposed in
- * draft-ietf-syslog-protocol-19. rgerhards, 2006-11-30
- */
- if(iDst + 3 < iMaxLine) { /* do we have space? */
- pDst[iDst++] = cCCEscapeChar;
- pDst[iDst++] = '0';
- pDst[iDst++] = '0';
- pDst[iDst++] = '0';
- } /* if we do not have space, we simply ignore the '\0'... */
- /* log an error? Very questionable... rgerhards, 2006-11-30 */
- /* decided: we do not log an error, it won't help... rger, 2007-06-21 */
- } else if(bEscapeCCOnRcv && iscntrl((int) pszMsg[iSrc])) {
+ } else if(iscntrl((int) pszMsg[iSrc])) {
+ if(pszMsg[iSrc] == '\0' || bEscapeCCOnRcv) {
/* we are configured to escape control characters. Please note
* that this most probably break non-western character sets like
* Japanese, Korean or Chinese. rgerhards, 2007-07-17
- * Note: sysklogd logs octal values only for DEL and CCs above 127.
- * For others, it logs ^n where n is the control char converted to an
- * alphabet character. We like consistency and thus escape it to octal
- * in all cases. If someone complains, we may change the mode. At least
- * we known now what's going on.
- * rgerhards, 2007-07-17
*/
- if(iDst + 3 < iMaxLine) { /* do we have space? */
- pDst[iDst++] = cCCEscapeChar;
- pDst[iDst++] = '0' + ((pszMsg[iSrc] & 0300) >> 6);
- pDst[iDst++] = '0' + ((pszMsg[iSrc] & 0070) >> 3);
- pDst[iDst++] = '0' + ((pszMsg[iSrc] & 0007));
- } /* again, if we do not have space, we ignore the char - see comment at '\0' */
+ pDst[iDst++] = cCCEscapeChar;
+ pDst[iDst++] = '0' + ((pszMsg[iSrc] & 0300) >> 6);
+ pDst[iDst++] = '0' + ((pszMsg[iSrc] & 0070) >> 3);
+ pDst[iDst++] = '0' + ((pszMsg[iSrc] & 0007));
+ }
} else {
pDst[iDst++] = pszMsg[iSrc];
}
++iSrc;
}
- pDst[iDst] = '\0'; /* space *is* reserved for this! */
-
- /* we have a sanitized string. Let's save it now */
- free(pMsg->pszRawMsg);
- if((pMsg->pszRawMsg = malloc((iDst+1) * sizeof(uchar))) == NULL) {
- /* when we get no new buffer, we use what we already have ;) */
- pMsg->pszRawMsg = pDst;
- } else {
- /* trim buffer */
- memcpy(pMsg->pszRawMsg, pDst, iDst+1);
- free(pDst); /* too big! */
- pMsg->iLenRawMsg = iDst;
- }
+
+ MsgSetRawMsg(pMsg, (char*)pDst, iDst); /* save sanitized string */
+
+ if(pDst != szSanBuf)
+ free(pDst);
finalize_it:
RETiRet;
@@ -284,7 +257,6 @@ rsRetVal parseMsg(msg_t *pMsg)
DEFiRet;
uchar *msg;
int pri;
- int iPriText;
CHKiRet(sanitizeMessage(pMsg));
@@ -294,7 +266,6 @@ rsRetVal parseMsg(msg_t *pMsg)
/* pull PRI */
pri = DEFUPRI;
msg = pMsg->pszRawMsg;
- iPriText = 0;
if(*msg == '<') {
/* while we process the PRI, we also fill the PRI textual representation
* inside the msg object. This may not be ideal from an OOP point of view,
@@ -302,11 +273,8 @@ rsRetVal parseMsg(msg_t *pMsg)
*/
pri = 0;
while(isdigit((int) *++msg)) {
- pMsg->bufPRI[iPriText++ % 4] = *msg; /* mod 4 to guard against malformed messages! */
pri = 10 * pri + (*msg - '0');
}
- pMsg->bufPRI[iPriText % 4] = '\0';
- pMsg->iLenPRI = iPriText % 4;
if(*msg == '>')
++msg;
if(pri & ~(LOG_FACMASK|LOG_PRIMASK))
diff --git a/runtime/prop.c b/runtime/prop.c
new file mode 100644
index 00000000..02be315f
--- /dev/null
+++ b/runtime/prop.c
@@ -0,0 +1,124 @@
+/* prop.c - rsyslog's prop object
+ *
+ * This object is meant to support message properties that are stored
+ * seperately from the message. The main intent is to support properties
+ * that are "constant" during a period of time, so that many messages may
+ * contain a reference to the same property. It is important, though, that
+ * properties are destroyed when they are no longer needed.
+ *
+ * Please note that this is a performance-critical part of the software and
+ * as such we may use some methods in here which do not look elegant, but
+ * which are fast...
+ *
+ * Module begun 2009-06-17 by Rainer Gerhards
+ *
+ * Copyright 2009 Rainer Gerhards and Adiscon GmbH.
+ *
+ * This file is part of the rsyslog runtime library.
+ *
+ * The rsyslog runtime library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The rsyslog runtime library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the rsyslog runtime library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * A copy of the GPL can be found in the file "COPYING" in this distribution.
+ * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution.
+ */
+
+#include "config.h"
+#include <stdlib.h>
+#include <assert.h>
+
+#include "rsyslog.h"
+#include "obj.h"
+#include "prop.h"
+
+/* static data */
+DEFobjStaticHelpers
+
+
+/* Standard-Constructor
+ */
+BEGINobjConstruct(prop) /* be sure to specify the object type also in END macro! */
+ENDobjConstruct(prop)
+
+
+/* ConstructionFinalizer
+ * rgerhards, 2008-01-09
+ */
+static rsRetVal
+propConstructFinalize(prop_t __attribute__((unused)) *pThis)
+{
+ DEFiRet;
+ ISOBJ_TYPE_assert(pThis, prop);
+ RETiRet;
+}
+
+
+/* destructor for the prop object */
+BEGINobjDestruct(prop) /* be sure to specify the object type also in END and CODESTART macros! */
+CODESTARTobjDestruct(prop)
+ENDobjDestruct(prop)
+
+
+/* debugprint for the prop object */
+BEGINobjDebugPrint(prop) /* be sure to specify the object type also in END and CODESTART macros! */
+CODESTARTobjDebugPrint(prop)
+ dbgprintf("prop object %p - no further debug info implemented\n", pThis);
+ENDobjDebugPrint(prop)
+
+
+/* queryInterface function
+ * rgerhards, 2008-02-21
+ */
+BEGINobjQueryInterface(prop)
+CODESTARTobjQueryInterface(prop)
+ if(pIf->ifVersion != propCURR_IF_VERSION) { /* check for current version, increment on each change */
+ ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED);
+ }
+
+ /* ok, we have the right interface, so let's fill it
+ * Please note that we may also do some backwards-compatibility
+ * work here (if we can support an older interface version - that,
+ * of course, also affects the "if" above).
+ */
+ pIf->Construct = propConstruct;
+ pIf->ConstructFinalize = propConstructFinalize;
+ pIf->Destruct = propDestruct;
+ pIf->DebugPrint = propDebugPrint;
+
+finalize_it:
+ENDobjQueryInterface(prop)
+
+
+/* Exit the prop class.
+ * rgerhards, 2009-04-06
+ */
+BEGINObjClassExit(prop, OBJ_IS_CORE_MODULE) /* class, version */
+// objRelease(errmsg, CORE_COMPONENT);
+ENDObjClassExit(prop)
+
+
+/* Initialize the prop class. Must be called as the very first method
+ * before anything else is called inside this class.
+ * rgerhards, 2008-02-19
+ */
+BEGINObjClassInit(prop, 1, OBJ_IS_CORE_MODULE) /* class, version */
+ /* request objects we use */
+// CHKiRet(objUse(errmsg, CORE_COMPONENT));
+
+ /* set our own handlers */
+ OBJSetMethodHandler(objMethod_DEBUGPRINT, propDebugPrint);
+ OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, propConstructFinalize);
+ENDObjClassInit(prop)
+
+/* vi:set ai:
+ */
diff --git a/runtime/prop.h b/runtime/prop.h
new file mode 100644
index 00000000..7fc466b5
--- /dev/null
+++ b/runtime/prop.h
@@ -0,0 +1,46 @@
+/* The prop object.
+ *
+ * This implements props within rsyslog.
+ *
+ * Copyright 2009 Rainer Gerhards and Adiscon GmbH.
+ *
+ * This file is part of the rsyslog runtime library.
+ *
+ * The rsyslog runtime library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The rsyslog runtime library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the rsyslog runtime library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * A copy of the GPL can be found in the file "COPYING" in this distribution.
+ * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution.
+ */
+#ifndef INCLUDED_PROP_H
+#define INCLUDED_PROP_H
+
+/* the prop object */
+struct prop_s {
+ BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */
+};
+
+/* interfaces */
+BEGINinterface(prop) /* name must also be changed in ENDinterface macro! */
+ INTERFACEObjDebugPrint(prop);
+ rsRetVal (*Construct)(prop_t **ppThis);
+ rsRetVal (*ConstructFinalize)(prop_t __attribute__((unused)) *pThis);
+ rsRetVal (*Destruct)(prop_t **ppThis);
+ENDinterface(prop)
+#define propCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */
+
+
+/* prototypes */
+PROTOTYPEObj(prop);
+
+#endif /* #ifndef INCLUDED_PROP_H */
diff --git a/runtime/queue.c b/runtime/queue.c
index 9c7e524c..e18ce3d7 100644
--- a/runtime/queue.c
+++ b/runtime/queue.c
@@ -53,6 +53,7 @@
#include "obj.h"
#include "wtp.h"
#include "wti.h"
+#include "msg.h"
#include "atomic.h"
#include "msg.h" /* TODO: remove once we remove MsgAddRef() call */
@@ -67,6 +68,7 @@ DEFobjCurrIf(glbl)
DEFobjCurrIf(strm)
/* forward-definitions */
+static rsRetVal ChkStrtDA(qqueue_t *pThis);
static rsRetVal qqueueChkPersist(qqueue_t *pThis, int nUpdates);
static rsRetVal SetEnqOnly(qqueue_t *pThis, int bEnqOnly, int bLockMutex);
static rsRetVal RateLimiter(qqueue_t *pThis);
@@ -504,7 +506,7 @@ finalize_it:
* complete.
* rgerhards, 2008-01-14
*/
-static inline rsRetVal
+static rsRetVal
ChkStrtDA(qqueue_t *pThis)
{
DEFiRet;
@@ -1431,7 +1433,6 @@ rsRetVal qqueueConstruct(qqueue_t **ppThis, queueType_t qType, int iWorkerThread
/* we have an object, so let's fill the properties */
objConstructSetObjInfo(pThis);
- pThis->bOptimizeUniProc = glbl.GetOptimizeUniProc();
if((pThis->pszSpoolDir = (uchar*) strdup((char*)glbl.GetWorkDir())) == NULL)
ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
@@ -2274,7 +2275,6 @@ finalize_it:
static rsRetVal qqueueChkPersist(qqueue_t *pThis, int nUpdates)
{
DEFiRet;
-
ISOBJ_TYPE_assert(pThis, qqueue);
assert(nUpdates >= 0);
@@ -2564,6 +2564,124 @@ finalize_it:
}
+/* enqueue a single data object. This currently is a helper to qqueueMultiEnqObj.
+ * Note that the queue mutex MUST already be locked when this function is called.
+ * rgerhards, 2009-06-16
+ */
+static inline rsRetVal
+doEnqSingleObj(qqueue_t *pThis, flowControl_t flowCtlType, void *pUsr)
+{
+ DEFiRet;
+ struct timespec t;
+
+ /* first check if we need to discard this message (which will cause CHKiRet() to exit)
+ */
+ CHKiRet(qqueueChkDiscardMsg(pThis, pThis->iQueueSize, pThis->bRunsDA, pUsr));
+
+ /* then check if we need to add an assistance disk queue */
+ if(pThis->bIsDA)
+ CHKiRet(ChkStrtDA(pThis));
+
+ /* handle flow control
+ * There are two different flow control mechanisms: basic and advanced flow control.
+ * Basic flow control has always been implemented and protects the queue structures
+ * in that it makes sure no more data is enqueued than the queue is configured to
+ * support. Enhanced flow control is being added today. There are some sources which
+ * can easily be stopped, e.g. a file reader. This is the case because it is unlikely
+ * that blocking those sources will have negative effects (after all, the file is
+ * continued to be written). Other sources can somewhat be blocked (e.g. the kernel
+ * log reader or the local log stream reader): in general, nothing is lost if messages
+ * from these sources are not picked up immediately. HOWEVER, they can not block for
+ * an extended period of time, as this either causes message loss or - even worse - some
+ * other bad effects (e.g. unresponsive system in respect to the main system log socket).
+ * Finally, there are some (few) sources which can not be blocked at all. UDP syslog is
+ * a prime example. If a UDP message is not received, it is simply lost. So we can't
+ * do anything against UDP sockets that come in too fast. The core idea of advanced
+ * flow control is that we take into account the different natures of the sources and
+ * select flow control mechanisms that fit these needs. This also means, in the end
+ * result, that non-blockable sources like UDP syslog receive priority in the system.
+ * It's a side effect, but a good one ;) -- rgerhards, 2008-03-14
+ */
+ if(flowCtlType == eFLOWCTL_FULL_DELAY) {
+ while(pThis->iQueueSize >= pThis->iFullDlyMrk) {
+ dbgoprint((obj_t*) pThis, "enqueueMsg: FullDelay mark reached for full delayable message - blocking.\n");
+ pthread_cond_wait(&pThis->belowFullDlyWtrMrk, pThis->mut); /* TODO error check? But what do then? */
+ }
+ } else if(flowCtlType == eFLOWCTL_LIGHT_DELAY) {
+ if(pThis->iQueueSize >= pThis->iLightDlyMrk) {
+ dbgoprint((obj_t*) pThis, "enqueueMsg: LightDelay mark reached for light delayable message - blocking a bit.\n");
+ timeoutComp(&t, 1000); /* 1000 millisconds = 1 second TODO: make configurable */
+ pthread_cond_timedwait(&pThis->belowLightDlyWtrMrk, pThis->mut, &t); /* TODO error check? But what do then? */
+ }
+ }
+
+ /* from our regular flow control settings, we are now ready to enqueue the object.
+ * However, we now need to do a check if the queue permits to add more data. If that
+ * is not the case, basic flow control enters the field, which means we wait for
+ * the queue to become ready or drop the new message. -- rgerhards, 2008-03-14
+ */
+ while( (pThis->iMaxQueueSize > 0 && pThis->iQueueSize >= pThis->iMaxQueueSize)
+ || (pThis->qType == QUEUETYPE_DISK && pThis->sizeOnDiskMax != 0
+ && pThis->tVars.disk.sizeOnDisk > pThis->sizeOnDiskMax)) {
+ dbgoprint((obj_t*) pThis, "enqueueMsg: queue FULL - waiting to drain.\n");
+ timeoutComp(&t, pThis->toEnq);
+ if(pthread_cond_timedwait(&pThis->notFull, pThis->mut, &t) != 0) {
+ dbgoprint((obj_t*) pThis, "enqueueMsg: cond timeout, dropping message!\n");
+ objDestruct(pUsr);
+ ABORT_FINALIZE(RS_RET_QUEUE_FULL);
+ }
+ }
+
+ /* and finally enqueue the message */
+ CHKiRet(qqueueAdd(pThis, pUsr));
+ qqueueChkPersist(pThis, 1); // TODO: optimize, do in outer function! (but we need parts from v5?)
+
+finalize_it:
+ RETiRet;
+}
+
+/* enqueue multiple user data elements at once. The aim is to provide a faster interface
+ * for object submission. Uses the multi_submit_t helper object.
+ * Please note that this function is not cancel-safe and consequently
+ * sets the calling thread's cancelibility state to PTHREAD_CANCEL_DISABLE
+ * during its execution. If that is not done, race conditions occur if the
+ * thread is canceled (most important use case is input module termination).
+ * rgerhards, 2009-06-16
+ */
+rsRetVal
+qqueueMultiEnqObj(qqueue_t *pThis, multi_submit_t *pMultiSub)
+{
+ int iCancelStateSave;
+ int i;
+ DEFiRet;
+
+ ISOBJ_TYPE_assert(pThis, qqueue);
+ assert(pMultiSub != NULL);
+
+ if(pThis->qType != QUEUETYPE_DIRECT) {
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &iCancelStateSave);
+ d_pthread_mutex_lock(pThis->mut);
+ }
+
+ for(i = 0 ; i < pMultiSub->nElem ; ++i) {
+dbgprintf("queueMultiEnq: %d\n", i);
+ CHKiRet(doEnqSingleObj(pThis, pMultiSub->ppMsgs[i]->flowCtlType, (void*)pMultiSub->ppMsgs[i]));
+ }
+
+finalize_it:
+ if(pThis->qType != QUEUETYPE_DIRECT) {
+ /* make sure at least one worker is running. */
+ qqueueAdviseMaxWorkers(pThis);
+ /* and release the mutex */
+ d_pthread_mutex_unlock(pThis->mut);
+ pthread_setcancelstate(iCancelStateSave, NULL);
+ dbgoprint((obj_t*) pThis, "MultiEnqObj advised worker start\n");
+ }
+
+ RETiRet;
+}
+
+
/* set queue mode to enqueue only or not
* There is one subtle issue: this method may be called during queue
* construction or while it is running. In the former case, the queue
diff --git a/runtime/queue.h b/runtime/queue.h
index 1a26a9ff..e873c456 100644
--- a/runtime/queue.h
+++ b/runtime/queue.h
@@ -69,13 +69,12 @@ typedef struct qWrkThrd_s {
typedef struct queue_s {
BEGINobjInstance;
queueType_t qType;
- int bOptimizeUniProc; /* cache for the equally-named global setting, pulled at time of queue creation */
- int bEnqOnly; /* does queue run in enqueue-only mode (1) or not (0)? */
- int bSaveOnShutdown;/* persists everthing on shutdown (if DA!)? 1-yes, 0-no */
- int bQueueStarted; /* has queueStart() been called on this queue? 1-yes, 0-no */
- int bQueueInDestruction;/* 1 if queue is in destruction process, 0 otherwise */
- int iQueueSize; /* Current number of elements in queue store (some are already logically dequeued!) */
int nLogDeq; /* number of elements currently logically dequeued */
+ bool bEnqOnly; /* does queue run in enqueue-only mode (1) or not (0)? */
+ bool bSaveOnShutdown;/* persists everthing on shutdown (if DA!)? 1-yes, 0-no */
+ bool bQueueStarted; /* has queueStart() been called on this queue? 1-yes, 0-no */
+ bool bQueueInDestruction;/* 1 if queue is in destruction process, 0 otherwise */
+ int iQueueSize; /* Current number of elements in the queue */
int iMaxQueueSize; /* how large can the queue grow? */
int iNumWorkerThreads;/* number of worker threads to use */
int iCurNumWrkThrd;/* current number of active worker threads */
@@ -85,14 +84,14 @@ typedef struct queue_s {
void *pUsr; /* a global, user-supplied pointer. Is passed back to consumer. */
int iUpdsSincePersist;/* nbr of queue updates since the last persist call */
int iPersistUpdCnt; /* persits queue info after this nbr of updates - 0 -> persist only on shutdown */
- int bSyncQueueFiles;/* if working with files, sync them after each write? */
+ bool bSyncQueueFiles;/* if working with files, sync them after each write? */
int iHighWtrMrk; /* high water mark for disk-assisted memory queues */
int iLowWtrMrk; /* low water mark for disk-assisted memory queues */
int iDiscardMrk; /* if the queue is above this mark, low-severity messages are discarded */
int iFullDlyMrk; /* if the queue is above this mark, FULL_DELAYable message are put on hold */
int iLightDlyMrk; /* if the queue is above this mark, LIGHT_DELAYable message are put on hold */
int iDiscardSeverity;/* messages of this severity above are discarded on too-full queue */
- int bNeedDelQIF; /* does the QIF file need to be deleted when queue becomes empty? */
+ bool bNeedDelQIF; /* does the QIF file need to be deleted when queue becomes empty? */
int toQShutdown; /* timeout for regular queue shutdown in ms */
int toActShutdown; /* timeout for long-running action shutdown in ms */
int toWrkShutdown; /* timeout for idle workers in ms, -1 means indefinite (0 is immediate) */
@@ -192,6 +191,7 @@ typedef struct queue_s {
/* prototypes */
rsRetVal qqueueDestruct(qqueue_t **ppThis);
+rsRetVal qqueueMultiEnqObj(qqueue_t *pThis, multi_submit_t *pMultiSub);
rsRetVal qqueueEnqObj(qqueue_t *pThis, flowControl_t flwCtlType, void *pUsr);
rsRetVal qqueueStart(qqueue_t *pThis);
rsRetVal qqueueSetMaxFileSize(qqueue_t *pThis, size_t iMaxFileSize);
diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h
index fa854175..ea78e823 100644
--- a/runtime/rsyslog.h
+++ b/runtime/rsyslog.h
@@ -95,6 +95,7 @@ typedef struct wti_s wti_t;
typedef obj_t nsd_t;
typedef obj_t nsdsel_t;
typedef struct msg msg_t;
+typedef struct prop_s prop_t;
typedef struct interface_s interface_t;
typedef struct objInfo_s objInfo_t;
typedef enum rsRetVal_ rsRetVal; /**< friendly type for global return value */
@@ -143,6 +144,19 @@ typedef enum {
} fiop_t;
+/* multi-submit support.
+ * This is done via a simple data structure, which holds the number of elements
+ * as well as an array of to-be-submitted messages.
+ * rgerhards, 2009-06-16
+ */
+typedef struct multi_submit_s multi_submit_t;
+struct multi_submit_s {
+ short maxElem; /* maximum number of Elements */
+ short nElem; /* current number of Elements, points to the next one FREE */
+ msg_t **ppMsgs;
+};
+
+
#ifndef _PATH_CONSOLE
#define _PATH_CONSOLE "/dev/console"
#endif
diff --git a/runtime/rule.c b/runtime/rule.c
index f17c524e..12494543 100644
--- a/runtime/rule.c
+++ b/runtime/rule.c
@@ -106,6 +106,7 @@ shouldProcessThisMessage(rule_t *pRule, msg_t *pMsg, int *bProcessMsg)
unsigned short pbMustBeFreed;
char *pszPropVal;
int bRet = 0;
+ size_t propLen;
vm_t *pVM = NULL;
var_t *pResult = NULL;
@@ -177,7 +178,8 @@ shouldProcessThisMessage(rule_t *pRule, msg_t *pMsg, int *bProcessMsg)
bRet = (pResult->val.num) ? 1 : 0;
} else {
assert(pRule->f_filter_type == FILTER_PROP); /* assert() just in case... */
- pszPropVal = MsgGetProp(pMsg, NULL, pRule->f_filterData.prop.pCSPropName, &pbMustBeFreed);
+ pszPropVal = MsgGetProp(pMsg, NULL, pRule->f_filterData.prop.pCSPropName, &propLen, &pbMustBeFreed);
+ // TODO: optimize, we now have the length of the property!
/* Now do the compares (short list currently ;)) */
switch(pRule->f_filterData.prop.operation ) {
diff --git a/runtime/stream.c b/runtime/stream.c
index 372a3a5f..a05f4c9b 100644
--- a/runtime/stream.c
+++ b/runtime/stream.c
@@ -72,9 +72,11 @@ flushApc(void *param1, void __attribute__((unused)) *param2)
strm_t *pThis = (strm_t*) param1;
ISOBJ_TYPE_assert(pThis, strm);
+ BEGINfunc
BEGIN_MTX_PROTECTED_OPERATIONS_UNCOND(&pThis->mut);
strmFlush(pThis);
END_MTX_PROTECTED_OPERATIONS_UNCOND(&pThis->mut);
+ ENDfunc
}
@@ -188,7 +190,7 @@ finalize_it:
static rsRetVal
doPhysOpen(strm_t *pThis)
{
- int iFlags;
+ int iFlags = 0;
DEFiRet;
ISOBJ_TYPE_assert(pThis, strm);
@@ -531,19 +533,19 @@ strmReadLine(strm_t *pThis, cstr_t **ppCStr)
ASSERT(pThis != NULL);
ASSERT(ppCStr != NULL);
- CHKiRet(rsCStrConstruct(ppCStr));
+ CHKiRet(cstrConstruct(ppCStr));
/* now read the line */
CHKiRet(strmReadChar(pThis, &c));
while(c != '\n') {
- CHKiRet(rsCStrAppendChar(*ppCStr, c));
+ CHKiRet(cstrAppendChar(*ppCStr, c));
CHKiRet(strmReadChar(pThis, &c));
}
CHKiRet(cstrFinalize(*ppCStr));
finalize_it:
if(iRet != RS_RET_OK && *ppCStr != NULL)
- rsCStrDestruct(ppCStr);
+ cstrDestruct(ppCStr);
RETiRet;
}
diff --git a/runtime/stringbuf.c b/runtime/stringbuf.c
index a2d9c599..d3ddf33a 100644
--- a/runtime/stringbuf.c
+++ b/runtime/stringbuf.c
@@ -1,3 +1,4 @@
+#include <stdio.h>
/* This is the byte-counted string class for rsyslog. It is a replacement
* for classical \0 terminated string functions. We introduce it in
* the hope it will make the program more secure, obtain some performance
@@ -157,7 +158,7 @@ static rsRetVal
rsCStrExtendBuf(cstr_t *pThis, size_t iMinNeeded)
{
uchar *pNewBuf;
- size_t iNewSize;
+ unsigned short iNewSize;
DEFiRet;
/* first compute the new size needed */
@@ -224,7 +225,7 @@ rsRetVal rsCStrAppendStr(cstr_t *pThis, uchar* psz)
/* append the contents of one cstr_t object to another
* rgerhards, 2008-02-25
*/
-rsRetVal rsCStrAppendCStr(cstr_t *pThis, cstr_t *pstrAppend)
+rsRetVal cstrAppendCStr(cstr_t *pThis, cstr_t *pstrAppend)
{
return rsCStrAppendStrWithLen(pThis, pstrAppend->pBuf, pstrAppend->iStrLen);
}
@@ -245,32 +246,7 @@ finalize_it:
}
-rsRetVal rsCStrAppendChar(cstr_t *pThis, uchar c)
-{
- DEFiRet;
-
- rsCHECKVALIDOBJECT(pThis, OIDrsCStr);
-
- if(pThis->iStrLen >= pThis->iBufSize) {
- CHKiRet(rsCStrExtendBuf(pThis, 1)); /* need more memory! */
- }
-
- /* ok, when we reach this, we have sufficient memory */
- *(pThis->pBuf + pThis->iStrLen++) = c;
-
- /* check if we need to invalidate an sz representation! */
- if(pThis->pszBuf != NULL) {
- free(pThis->pszBuf);
- pThis->pszBuf = NULL;
- }
-
-finalize_it:
- RETiRet;
-}
-
-
-/* NEW VARIANT
- * Append a character to the current string object. This may only be done until
+/* Append a character to the current string object. This may only be done until
* cstrFinalize() is called.
* rgerhards, 2009-06-16
*/
@@ -392,7 +368,24 @@ uchar* rsCStrGetSzStr(cstr_t *pThis)
}
-/* NEW VERSION for interface without separate psz buffer! */
+/* Converts the CStr object to a classical sz string and returns that.
+ * Same restrictions as in cstrGetSzStr() applies (see there!). This
+ * function here guarantees that a valid string is returned, even if
+ * the CStr object currently holds a NULL pointer string buffer. If so,
+ * "" is returned.
+ * rgerhards 2005-10-19
+ * WARNING: The returned pointer MUST NOT be freed, as it may be
+ * obtained from that constant memory pool (in case of NULL!)
+ */
+uchar* cstrGetSzStrNoNULL(cstr_t *pThis)
+{
+ rsCHECKVALIDOBJECT(pThis, OIDrsCStr);
+ if(pThis->pBuf == NULL)
+ return (uchar*) "";
+ else
+ return cstrGetSzStr(pThis);
+}
+
/* Returns the cstr data as a classical C sz string. We use that the
* Finalizer did properly terminate our string (but we may stil be NULL).
* So it is vital that the finalizer is called BEFORe this function here!
@@ -468,14 +461,11 @@ cstrFinalize(cstr_t *pThis)
DEFiRet;
rsCHECKVALIDOBJECT(pThis, OIDrsCStr);
- assert(pThis->bIsFinalized == 0);
-
if(pThis->iStrLen > 0) {
/* terminate string only if one exists */
CHKiRet(cstrAppendChar(pThis, '\0'));
--pThis->iStrLen; /* do NOT count the \0 byte */
}
- pThis->bIsFinalized = 1;
finalize_it:
RETiRet;
@@ -497,7 +487,7 @@ void rsCStrSetAllocIncrement(cstr_t *pThis, int iNewIncrement)
* This is due to performance reasons.
*/
#ifndef NDEBUG
-int rsCStrLen(cstr_t *pThis)
+int cstrLen(cstr_t *pThis)
{
rsCHECKVALIDOBJECT(pThis, OIDrsCStr);
return(pThis->iStrLen);
@@ -548,6 +538,27 @@ rsRetVal rsCStrTrimTrailingWhiteSpace(cstr_t *pThis)
return RS_RET_OK;
}
+/* Trim trailing whitespace from a given string
+ */
+rsRetVal cstrTrimTrailingWhiteSpace(cstr_t *pThis)
+{
+ register int i;
+ register uchar *pC;
+ rsCHECKVALIDOBJECT(pThis, OIDrsCStr);
+
+ i = pThis->iStrLen;
+ pC = pThis->pBuf + i - 1;
+ while(i > 0 && isspace((int)*pC)) {
+ --pC;
+ --i;
+ }
+ /* i now is the new string length! */
+ pThis->iStrLen = i;
+ pThis->pBuf[pThis->iStrLen] = '0'; /* we always have this space */
+
+ return RS_RET_OK;
+}
+
/* compare two string objects - works like strcmp(), but operates
* on CStr objects. Please note that this version here is
* faster in the majority of cases, simply because it can
diff --git a/runtime/stringbuf.h b/runtime/stringbuf.h
index d28aee26..9d2e7865 100644
--- a/runtime/stringbuf.h
+++ b/runtime/stringbuf.h
@@ -1,5 +1,5 @@
-/*! \file stringbuf.h
- * \brief The counted string object
+/* stringbuf.h
+ * The counted string object
*
* This is the byte-counted string class for rsyslog. It is a replacement
* for classical \0 terminated string functions. We introduce it in
@@ -11,8 +11,7 @@
* \date 2005-09-07
* Initial version begun.
*
- * All functions in this "class" start with rsCStr (rsyslog Counted String).
- * Copyright 2005
+ * Copyright 2005-2009
* Rainer Gerhards and Adiscon GmbH. All Rights Reserved.
*
* This file is part of the rsyslog runtime library.
@@ -48,8 +47,8 @@ typedef struct cstr_s
uchar *pszBuf; /**< pointer to the sz version of the string (after it has been created )*/
size_t iBufSize; /**< current maximum size of the string buffer */
size_t iStrLen; /**< length of the string in characters. */
- size_t iAllocIncrement; /**< the amount of bytes the string should be expanded if it needs to */
- bool bIsFinalized; /**< is this object finished and ready for use? (a debug aid, may be removed later TODO 2009-06-16) */
+ unsigned short iAllocIncrement; /**< the amount of bytes the string should be expanded if it needs to */
+ bool bIsForeignBuf; /**< is pBuf a buffer provided by someone else? */
} cstr_t;
@@ -73,7 +72,6 @@ void rsCStrDestruct(cstr_t **ppThis);
*
* \param c Character to append to string.
*/
-rsRetVal rsCStrAppendChar(cstr_t *pThis, uchar c);
rsRetVal cstrAppendChar(cstr_t *pThis, uchar c);
/**
@@ -85,6 +83,7 @@ rsRetVal cstrAppendChar(cstr_t *pThis, uchar c);
rsRetVal rsCStrTruncate(cstr_t *pThis, size_t nTrunc);
rsRetVal rsCStrTrimTrailingWhiteSpace(cstr_t *pThis);
+rsRetVal cstrTrimTrailingWhiteSpace(cstr_t *pThis);
/**
* Append a string to the buffer. For performance reasons,
@@ -143,19 +142,24 @@ rsRetVal rsCStrSzStrMatchRegex(cstr_t *pCS1, uchar *psz, int iType, void *cache)
void rsCStrRegexDestruct(void *rc);
rsRetVal rsCStrConvertToNumber(cstr_t *pStr, number_t *pNumber);
rsRetVal rsCStrConvertToBool(cstr_t *pStr, number_t *pBool);
-rsRetVal rsCStrAppendCStr(cstr_t *pThis, cstr_t *pstrAppend);
+
+/* in migration */
+#define rsCStrAppendCStr(pThis, pstrAppend) cstrAppendCStr(pThis, pstrAppend)
/* new calling interface */
rsRetVal cstrFinalize(cstr_t *pThis);
rsRetVal cstrConvSzStrAndDestruct(cstr_t *pThis, uchar **ppSz, int bRetNULL);
uchar* cstrGetSzStr(cstr_t *pThis);
+uchar* cstrGetSzStrNoNULL(cstr_t *pThis);
+rsRetVal cstrAppendCStr(cstr_t *pThis, cstr_t *pstrAppend);
/* now come inline-like functions */
#ifdef NDEBUG
-# define rsCStrLen(x) ((int)((x)->iStrLen))
+# define cstrLen(x) ((int)((x)->iStrLen))
#else
- int rsCStrLen(cstr_t *pThis);
+ int cstrLen(cstr_t *pThis);
#endif
+#define rsCStrLen(s) cstrLen((s))
#define rsCStrGetBufBeg(x) ((x)->pBuf)
diff --git a/runtime/vm.c b/runtime/vm.c
index 8cbf9e12..d7cd52d5 100644
--- a/runtime/vm.c
+++ b/runtime/vm.c
@@ -82,6 +82,7 @@ rsfrAddFunction(uchar *szName, prsf_t rsf)
/* unique name, so add to head of list */
CHKmalloc(pEntry = calloc(1, sizeof(rsf_entry_t)));
CHKiRet(rsCStrConstructFromszStr(&pEntry->pName, szName));
+ CHKiRet(cstrFinalize(pEntry->pName));
pEntry->rsf = rsf;
pEntry->pNext = funcRegRoot;
funcRegRoot = pEntry;
@@ -167,7 +168,7 @@ rsfrRemoveAll(void)
while(pEntry != NULL) {
pEntryDel = pEntry;
pEntry = pEntry->pNext;
- rsCStrDestruct(&pEntryDel->pName);
+ cstrDestruct(&pEntryDel->pName);
free(pEntryDel);
}
funcRegRoot = NULL;
@@ -405,6 +406,7 @@ CODESTARTop(STRADD)
vmstk.PopString(pThis->pStk, &operand1);
CHKiRet(rsCStrAppendCStr(operand1->val.pStr, operand2->val.pStr));
+ CHKiRet(cstrFinalize(operand1->val.pStr));
/* we have a result, so let's push it */
vmstk.Push(pThis->pStk, operand1);
@@ -554,12 +556,12 @@ rsf_tolower(vmstk_t *pStk, int numOperands)
ABORT_FINALIZE(RS_RET_INVLD_NBR_ARGUMENTS);
/* pop args and do operaton */
- CHKiRet(rsCStrConstruct(&pcstr));
+ CHKiRet(cstrConstruct(&pcstr));
vmstk.PopString(pStk, &operand1);
- pSrc = rsCStrGetSzStr(operand1->val.pStr);
- iStrlen = strlen((char*)pSrc);
+ pSrc = cstrGetSzStr(operand1->val.pStr);
+ iStrlen = strlen((char*)pSrc); // TODO: use count from string!
while(iStrlen--) {
- CHKiRet(rsCStrAppendChar(pcstr, tolower(*pSrc++)));
+ CHKiRet(cstrAppendChar(pcstr, tolower(*pSrc++)));
}
/* Store result and cleanup */
diff --git a/runtime/vmop.c b/runtime/vmop.c
index acacfc9e..ea627220 100644
--- a/runtime/vmop.c
+++ b/runtime/vmop.c
@@ -125,7 +125,7 @@ Obj2Str(vmop_t *pThis, cstr_t *pstrPrg)
if(pThis->operand.pVar != NULL)
CHKiRet(var.Obj2Str(pThis->operand.pVar, pstrPrg));
}
- CHKiRet(rsCStrAppendChar(pstrPrg, '\n'));
+ CHKiRet(cstrAppendChar(pstrPrg, '\n'));
finalize_it:
RETiRet;
diff --git a/runtime/wti.c b/runtime/wti.c
index 465dc3e1..8b39764e 100644
--- a/runtime/wti.c
+++ b/runtime/wti.c
@@ -209,7 +209,6 @@ ENDobjDestruct(wti)
/* Standard-Constructor for the wti object
*/
BEGINobjConstruct(wti) /* be sure to specify the object type also in END macro! */
- pThis->bOptimizeUniProc = glbl.GetOptimizeUniProc();
pthread_cond_init(&pThis->condExitDone, NULL);
pthread_mutex_init(&pThis->mut, NULL);
ENDobjConstruct(wti)
@@ -362,17 +361,6 @@ doIdleProcessing(wti_t *pThis, wtp_t *pWtp, int *pbInactivityTOOccured)
/* generic worker thread framework
- *
- * Some special comments below, so that they do not clutter the main function code:
- *
- * On the use of pthread_testcancel():
- * Now make sure we can get canceled - it is not specified if pthread_setcancelstate() is
- * a cancellation point in itself. As we run most of the time without cancel enabled, I fear
- * we may never get cancelled if we do not create a cancellation point ourselfs.
- * Note on rate-limiters:
- * If we have a rate-limiter set for this worker pool, let's call it. Please
- * keep in mind that the rate-limiter may hold us for an extended period
- * of time. -- rgerhards, 2008-04-02
*/
#pragma GCC diagnostic ignored "-Wempty-body"
rsRetVal
@@ -401,7 +389,6 @@ wtiWorker(wti_t *pThis)
while(1) { /* loop will be broken below - need to do mutex locks */
/* process any pending thread requests */
wtpProcessThrdChanges(pWtp);
- pthread_testcancel(); /* see big comment in function header */
if(pWtp->pfRateLimiter != NULL) { /* call rate-limiter, if defined */
pWtp->pfRateLimiter(pWtp->pUsr);
diff --git a/runtime/wti.h b/runtime/wti.h
index 17038ec5..2acd3cf6 100644
--- a/runtime/wti.h
+++ b/runtime/wti.h
@@ -33,14 +33,13 @@
/* the worker thread instance class */
struct wti_s {
BEGINobjInstance;
- int bOptimizeUniProc; /* cache for the equally-named global setting, pulled at time of queue creation */
pthread_t thrdID; /* thread ID */
qWrkCmd_t tCurrCmd; /* current command to be carried out by worker */
wtp_t *pWtp; /* my worker thread pool (important if only the work thread instance is passed! */
pthread_cond_t condExitDone; /* signaled when the thread exit is done (once per thread existance) */
pthread_mutex_t mut;
- int bShutdownRqtd; /* shutdown for this thread requested? 0 - no , 1 - yes */
batch_t batch; /* pointer to an object array meaningful for current user pointer (e.g. queue pUsr data elemt) */
+ bool bShutdownRqtd; /* shutdown for this thread requested? 0 - no , 1 - yes */
uchar *pszDbgHdr; /* header string for debug messages */
};
diff --git a/runtime/wtp.c b/runtime/wtp.c
index 6b39793b..267555cd 100644
--- a/runtime/wtp.c
+++ b/runtime/wtp.c
@@ -82,7 +82,6 @@ static rsRetVal NotImplementedDummy() { return RS_RET_NOT_IMPLEMENTED; }
/* Standard-Constructor for the wtp object
*/
BEGINobjConstruct(wtp) /* be sure to specify the object type also in END macro! */
- pThis->bOptimizeUniProc = glbl.GetOptimizeUniProc();
pthread_mutex_init(&pThis->mut, NULL);
pthread_mutex_init(&pThis->mutThrdShutdwn, NULL);
pthread_cond_init(&pThis->condThrdTrm, NULL);
diff --git a/runtime/wtp.h b/runtime/wtp.h
index e1180177..ef61d7e6 100644
--- a/runtime/wtp.h
+++ b/runtime/wtp.h
@@ -52,13 +52,12 @@ typedef enum {
/* the worker thread pool (wtp) object */
struct wtp_s {
BEGINobjInstance;
- int bOptimizeUniProc; /* cache for the equally-named global setting, pulled at time of queue creation */
wtpState_t wtpState;
int iNumWorkerThreads;/* number of worker threads to use */
int iCurNumWrkThrd;/* current number of active worker threads */
struct wti_s **pWrkr;/* array with control structure for the worker thread(s) associated with this wtp */
int toWrkShutdown; /* timeout for idle workers in ms, -1 means indefinite (0 is immediate) */
- int bInactivityGuard;/* prevents inactivity due to race condition */
+ bool bInactivityGuard;/* prevents inactivity due to race condition */
rsRetVal (*pConsumer)(void *); /* user-supplied consumer function for dewtpd messages */
/* synchronization variables */
pthread_mutex_t mutThrdShutdwn; /* mutex to guard thread shutdown processing */