summaryrefslogtreecommitdiff
path: root/runtime/msg.c
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/msg.c')
-rw-r--r--runtime/msg.c1060
1 files changed, 759 insertions, 301 deletions
diff --git a/runtime/msg.c b/runtime/msg.c
index a5c5281..d911b8b 100644
--- a/runtime/msg.c
+++ b/runtime/msg.c
@@ -7,7 +7,7 @@
* of the "old" message code without any modifications. However, it
* helps to have things at the right place one we go to the meat of it.
*
- * Copyright 2007-2013 Rainer Gerhards and Adiscon GmbH.
+ * Copyright 2007-2014 Rainer Gerhards and Adiscon GmbH.
*
* This file is part of the rsyslog runtime library.
*
@@ -41,9 +41,9 @@
#endif
#include <netdb.h>
#include <libestr.h>
-#include <json/json.h>
+#include <json.h>
/* For struct json_object_iter, should not be necessary in future versions */
-#include <json/json_object_private.h>
+#include <json_object_private.h>
#if HAVE_MALLOC_H
# include <malloc.h>
#endif
@@ -65,6 +65,13 @@
#include "net.h"
#include "var.h"
#include "rsconf.h"
+#include "parserif.h"
+
+/* TODO: move the global variable root to the config object - had no time to to it
+ * right now before vacation -- rgerhards, 2013-07-22
+ */
+static pthread_rwlock_t glblVars_rwlock;
+struct json_object *global_var_root = NULL;
/* static data */
DEFobjStaticHelpers
@@ -75,6 +82,8 @@ DEFobjCurrIf(prop)
DEFobjCurrIf(net)
DEFobjCurrIf(var)
+static char *one_digit[10] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
+
static char *two_digits[100] = {
"00", "01", "02", "03", "04", "05", "06", "07", "08", "09",
"10", "11", "12", "13", "14", "15", "16", "17", "18", "19",
@@ -87,10 +96,36 @@ static char *two_digits[100] = {
"80", "81", "82", "83", "84", "85", "86", "87", "88", "89",
"90", "91", "92", "93", "94", "95", "96", "97", "98", "99"};
+static char *wdayNames[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
+
+/* The following is a table of supported years. This permits us
+ * to avoid dynamic memory allocation. Note that the time-based
+ * algos need to be upgraded after the year 2099 in any case.
+ * Quite honestly, I don't expect that this is a real problem ;)
+ */
+static char *years[] = {
+ "1967", "1968", "1969", "1970", "1971", "1972", "1973", "1974",
+ "1975", "1976", "1977", "1978", "1979", "1980", "1981", "1982",
+ "1983", "1984", "1985", "1986", "1987", "1988", "1989", "1990",
+ "1991", "1992", "1993", "1994", "1995", "1996", "1997", "1998",
+ "1999", "2000", "2001", "2002", "2003", "2004", "2005", "2006",
+ "2007", "2008", "2009", "2010", "2011", "2012", "2013", "2014",
+ "2015", "2016", "2017", "2018", "2019", "2020", "2021", "2022",
+ "2023", "2024", "2025", "2026", "2027", "2028", "2029", "2030",
+ "2031", "2032", "2033", "2034", "2035", "2036", "2037", "2038",
+ "2039", "2040", "2041", "2042", "2043", "2044", "2045", "2046",
+ "2047", "2048", "2049", "2050", "2051", "2052", "2053", "2054",
+ "2055", "2056", "2057", "2058", "2059", "2060", "2061", "2062",
+ "2063", "2064", "2065", "2066", "2067", "2068", "2069", "2070",
+ "2071", "2072", "2073", "2074", "2075", "2076", "2077", "2078",
+ "2079", "2080", "2081", "2082", "2083", "2084", "2085", "2086",
+ "2087", "2088", "2089", "2090", "2091", "2092", "2093", "2094",
+ "2095", "2096", "2097", "2098", "2099" };
+
static struct {
uchar *pszName;
short lenName;
-} syslog_pri_names[192] = {
+} syslog_pri_names[200] = {
{ UCHAR_CONSTANT("0"), 3},
{ UCHAR_CONSTANT("1"), 3},
{ UCHAR_CONSTANT("2"), 3},
@@ -282,22 +317,30 @@ static struct {
{ UCHAR_CONSTANT("188"), 5},
{ UCHAR_CONSTANT("189"), 5},
{ UCHAR_CONSTANT("190"), 5},
- { UCHAR_CONSTANT("191"), 5}
+ { UCHAR_CONSTANT("191"), 5},
+ { UCHAR_CONSTANT("192"), 5},
+ { UCHAR_CONSTANT("193"), 5},
+ { UCHAR_CONSTANT("194"), 5},
+ { UCHAR_CONSTANT("195"), 5},
+ { UCHAR_CONSTANT("196"), 5},
+ { UCHAR_CONSTANT("197"), 5},
+ { UCHAR_CONSTANT("198"), 5},
+ { UCHAR_CONSTANT("199"), 5}
};
static char hexdigit[16] =
{'0', '1', '2', '3', '4', '5', '6', '7', '8',
'9', 'A', 'B', 'C', 'D', 'E', 'F' };
/*syslog facility names (as of RFC5424) */
-static char *syslog_fac_names[24] = { "kern", "user", "mail", "daemon", "auth", "syslog", "lpr",
+static char *syslog_fac_names[LOG_NFACILITIES] = { "kern", "user", "mail", "daemon", "auth", "syslog", "lpr",
"news", "uucp", "cron", "authpriv", "ftp", "ntp", "audit",
"alert", "clock", "local0", "local1", "local2", "local3",
- "local4", "local5", "local6", "local7" };
+ "local4", "local5", "local6", "local7", "invld" };
/* length of the facility names string (for optimizatiions) */
-static short len_syslog_fac_names[24] = { 4, 4, 4, 6, 4, 6, 3,
+static short len_syslog_fac_names[LOG_NFACILITIES] = { 4, 4, 4, 6, 4, 6, 3,
4, 4, 4, 8, 3, 3, 5,
5, 5, 6, 6, 6, 6,
- 6, 6, 6, 6 };
+ 6, 6, 6, 6, 5 };
/* table of severity names (in numerical order)*/
static char *syslog_severity_names[8] = { "emerg", "alert", "crit", "err", "warning", "notice", "info", "debug" };
@@ -307,8 +350,8 @@ static short len_syslog_severity_names[8] = { 5, 5, 4, 3, 7, 6, 4, 5 };
* 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" };
+static char *syslog_number_names[LOG_NFACILITIES] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14",
+ "15", "16", "17", "18", "19", "20", "21", "22", "23", "24" };
/* global variables */
#if defined(HAVE_MALLOC_TRIM) && !defined(HAVE_ATOMIC_BUILTINS)
@@ -316,8 +359,8 @@ static pthread_mutex_t mutTrimCtr; /* mutex to handle malloc trim */
#endif
/* some forward declarations */
-static int getAPPNAMELen(msg_t *pM, sbool bLockMutex);
-static rsRetVal jsonPathFindParent(msg_t *pM, uchar *name, uchar *leaf, struct json_object **parent, int bCreate);
+static int getAPPNAMELen(msg_t * const pM, sbool bLockMutex);
+static rsRetVal jsonPathFindParent(struct json_object *jroot, uchar *name, uchar *leaf, struct json_object **parent, int bCreate);
static uchar * jsonPathGetLeaf(uchar *name, int lenName);
static struct json_object *jsonDeepCopy(struct json_object *src);
@@ -372,23 +415,16 @@ void MsgSetRcvFromWithoutAddRef(msg_t *pThis, prop_t *new)
* If ruleset cannot be found, no update is done.
*/
static void
-MsgSetRulesetByName(msg_t *pMsg, cstr_t *rulesetName)
+MsgSetRulesetByName(msg_t * const pMsg, cstr_t *rulesetName)
{
rulesetGetRuleset(runConf, &(pMsg->pRuleset), rsCStrGetSzStrNoNULL(rulesetName));
}
-
-static inline int getProtocolVersion(msg_t *pM)
-{
- return(pM->iProtocolVersion);
-}
-
-
/* do a DNS reverse resolution, if not already done, reflect status
* rgerhards, 2009-11-16
*/
static inline rsRetVal
-resolveDNS(msg_t *pMsg) {
+resolveDNS(msg_t * const pMsg) {
rsRetVal localRet;
prop_t *propFromHost = NULL;
prop_t *ip;
@@ -419,7 +455,7 @@ finalize_it:
static inline void
-getInputName(msg_t *pM, uchar **ppsz, int *plen)
+getInputName(msg_t * const pM, uchar **ppsz, int *plen)
{
BEGINfunc
if(pM == NULL || pM->pInputName == NULL) {
@@ -433,7 +469,7 @@ getInputName(msg_t *pM, uchar **ppsz, int *plen)
static inline uchar*
-getRcvFromIP(msg_t *pM)
+getRcvFromIP(msg_t * const pM)
{
uchar *psz;
int len;
@@ -452,14 +488,12 @@ getRcvFromIP(msg_t *pM)
}
-/* map a property name (C string) to a property ID */
+/* map a property name (string) to a property ID */
rsRetVal
-propNameStrToID(uchar *pName, propid_t *pPropID)
+propNameToID(uchar *pName, propid_t *pPropID)
{
DEFiRet;
- assert(pName != NULL);
-
/* sometimes there are aliases to the original MonitoWare
* property names. These come after || in the ifs below. */
if(!strcmp((char*) pName, "msg")) {
@@ -507,6 +541,8 @@ propNameStrToID(uchar *pName, propid_t *pPropID)
*pPropID = PROP_PROCID;
} else if(!strcmp((char*) pName, "msgid")) {
*pPropID = PROP_MSGID;
+ } else if(!strcmp((char*) pName, "jsonmesg")) {
+ *pPropID = PROP_JSONMESG;
} else if(!strcmp((char*) pName, "parsesuccess")) {
*pPropID = PROP_PARSESUCCESS;
#ifdef USE_LIBUUID
@@ -534,13 +570,18 @@ propNameStrToID(uchar *pName, propid_t *pPropID)
*pPropID = PROP_SYS_MYHOSTNAME;
} else if(!strcmp((char*) pName, "$!all-json")) {
*pPropID = PROP_CEE_ALL_JSON;
- } else if(!strncmp((char*) pName, "$!", 2)) {
- *pPropID = PROP_CEE;
} else if(!strcmp((char*) pName, "$bom")) {
*pPropID = PROP_SYS_BOM;
} else if(!strcmp((char*) pName, "$uptime")) {
*pPropID = PROP_SYS_UPTIME;
+ } else if(!strncmp((char*) pName, "$!", 2) || pName[0] == '!') {
+ *pPropID = PROP_CEE;
+ } else if(!strncmp((char*) pName, "$.", 2) || pName[0] == '.') {
+ *pPropID = PROP_LOCAL_VAR;
+ } else if(!strncmp((char*) pName, "$/", 2) || pName[0] == '/') {
+ *pPropID = PROP_GLOBAL_VAR;
} else {
+ DBGPRINTF("PROP_INVALID for name '%s'\n", pName);
*pPropID = PROP_INVALID;
iRet = RS_RET_VAR_NOT_FOUND;
}
@@ -549,21 +590,6 @@ propNameStrToID(uchar *pName, propid_t *pPropID)
}
-/* map a property name (string) to a property ID */
-rsRetVal
-propNameToID(cstr_t *pCSPropName, propid_t *pPropID)
-{
- uchar *pName;
- DEFiRet;
-
- assert(pCSPropName != NULL);
- assert(pPropID != NULL);
- pName = rsCStrGetSzStrNoNULL(pCSPropName);
- iRet = propNameStrToID(pName, pPropID);
- RETiRet;
-}
-
-
/* map a property ID to a name string (useful for displaying) */
uchar *propIDToName(propid_t propID)
{
@@ -612,6 +638,8 @@ uchar *propIDToName(propid_t propID)
return UCHAR_CONSTANT("procid");
case PROP_MSGID:
return UCHAR_CONSTANT("msgid");
+ case PROP_JSONMESG:
+ return UCHAR_CONSTANT("jsonmesg");
case PROP_PARSESUCCESS:
return UCHAR_CONSTANT("parsesuccess");
case PROP_SYS_NOW:
@@ -634,6 +662,8 @@ uchar *propIDToName(propid_t propID)
return UCHAR_CONSTANT("$MYHOSTNAME");
case PROP_CEE:
return UCHAR_CONSTANT("*CEE-based property*");
+ case PROP_LOCAL_VAR:
+ return UCHAR_CONSTANT("*LOCAL_VARIABLE*");
case PROP_CEE_ALL_JSON:
return UCHAR_CONSTANT("$!all-json");
case PROP_SYS_BOM:
@@ -678,8 +708,8 @@ static inline rsRetVal msgBaseConstruct(msg_t **ppThis)
pM->flowCtlType = 0;
pM->bParseSuccess = 0;
pM->iRefCount = 1;
- pM->iSeverity = -1;
- pM->iFacility = -1;
+ pM->iSeverity = LOG_DEBUG;
+ pM->iFacility = LOG_INVLD;
pM->iLenPROGNAME = -1;
pM->offAfterPRI = 0;
pM->offMSG = -1;
@@ -699,7 +729,7 @@ static inline rsRetVal msgBaseConstruct(msg_t **ppThis)
pM->pszTIMESTAMP3339 = NULL;
pM->pszTIMESTAMP_MySQL = NULL;
pM->pszTIMESTAMP_PgSQL = NULL;
- pM->pCSStrucData = NULL;
+ pM->pszStrucData = NULL;
pM->pCSAPPNAME = NULL;
pM->pCSPROCID = NULL;
pM->pCSMSGID = NULL;
@@ -708,6 +738,8 @@ static inline rsRetVal msgBaseConstruct(msg_t **ppThis)
pM->rcvFrom.pRcvFrom = NULL;
pM->pRuleset = NULL;
pM->json = NULL;
+ pM->localvars = NULL;
+ pM->dfltTZ[0] = '\0';
memset(&pM->tRcvdAt, 0, sizeof(pM->tRcvdAt));
memset(&pM->tTIMESTAMP, 0, sizeof(pM->tTIMESTAMP));
pM->TAG.pszTAG = NULL;
@@ -841,10 +873,9 @@ CODESTARTobjDestruct(msg)
free(pThis->pszRcvdAt_PgSQL);
free(pThis->pszTIMESTAMP_MySQL);
free(pThis->pszTIMESTAMP_PgSQL);
+ free(pThis->pszStrucData);
if(pThis->iLenPROGNAME >= CONF_PROGNAME_BUFSIZE)
free(pThis->PROGNAME.ptr);
- if(pThis->pCSStrucData != NULL)
- rsCStrDestruct(&pThis->pCSStrucData);
if(pThis->pCSAPPNAME != NULL)
rsCStrDestruct(&pThis->pCSAPPNAME);
if(pThis->pCSPROCID != NULL)
@@ -853,6 +884,8 @@ CODESTARTobjDestruct(msg)
rsCStrDestruct(&pThis->pCSMSGID);
if(pThis->json != NULL)
json_object_put(pThis->json);
+ if(pThis->localvars != NULL)
+ json_object_put(pThis->localvars);
if(pThis->pszUUID != NULL)
free(pThis->pszUUID);
# ifndef HAVE_ATOMIC_BUILTINS
@@ -994,14 +1027,21 @@ msg_t* MsgDup(msg_t* pOld)
tmpCOPYSZ(HOSTNAME);
}
}
+ if(pOld->pszStrucData == NULL) {
+ pNew->pszStrucData = NULL;
+ } else {
+ pNew->pszStrucData = (uchar*)strdup((char*)pOld->pszStrucData);
+ pNew->lenStrucData = pOld->lenStrucData;
+ }
- tmpCOPYCSTR(StrucData);
tmpCOPYCSTR(APPNAME);
tmpCOPYCSTR(PROCID);
tmpCOPYCSTR(MSGID);
if(pOld->json != NULL)
pNew->json = jsonDeepCopy(pOld->json);
+ if(pOld->localvars != NULL)
+ pNew->localvars = jsonDeepCopy(pOld->localvars);
/* we do not copy all other cache properties, as we do not even know
* if they are needed once again. So we let them re-create if needed.
@@ -1056,12 +1096,17 @@ static rsRetVal MsgSerialize(msg_t *pThis, strm_t *pStrm)
CHKiRet(obj.SerializeProp(pStrm, UCHAR_CONSTANT("pszRcvFrom"), PROPTYPE_PSZ, (void*) psz));
psz = getRcvFromIP(pThis);
CHKiRet(obj.SerializeProp(pStrm, UCHAR_CONSTANT("pszRcvFromIP"), PROPTYPE_PSZ, (void*) psz));
+ psz = pThis->pszStrucData;
+ CHKiRet(obj.SerializeProp(pStrm, UCHAR_CONSTANT("pszRcvStrucData"), PROPTYPE_PSZ, (void*) psz));
if(pThis->json != NULL) {
psz = (uchar*) json_object_get_string(pThis->json);
CHKiRet(obj.SerializeProp(pStrm, UCHAR_CONSTANT("json"), PROPTYPE_PSZ, (void*) psz));
}
+ if(pThis->localvars != NULL) {
+ psz = (uchar*) json_object_get_string(pThis->localvars);
+ CHKiRet(obj.SerializeProp(pStrm, UCHAR_CONSTANT("localvars"), PROPTYPE_PSZ, (void*) psz));
+ }
- objSerializePTR(pStrm, pCSStrucData, CSTR);
objSerializePTR(pStrm, pCSAPPNAME, CSTR);
objSerializePTR(pStrm, pCSPROCID, CSTR);
objSerializePTR(pStrm, pCSMSGID, CSTR);
@@ -1107,13 +1152,12 @@ reinitVar(var_t *pVar)
*/
#define isProp(name) !rsCStrSzStrCmp(pVar->pcsName, (uchar*) name, sizeof(name) - 1)
rsRetVal
-MsgDeserialize(msg_t *pMsg, strm_t *pStrm)
+MsgDeserialize(msg_t * const pMsg, strm_t *pStrm)
{
prop_t *myProp;
prop_t *propRcvFrom = NULL;
prop_t *propRcvFromIP = NULL;
struct json_tokener *tokener;
- struct json_object *json;
var_t *pVar = NULL;
DEFiRet;
@@ -1197,12 +1241,21 @@ MsgDeserialize(msg_t *pMsg, strm_t *pStrm)
}
if(isProp("json")) {
tokener = json_tokener_new();
- json = json_tokener_parse_ex(tokener, (char*)rsCStrGetSzStrNoNULL(pVar->val.pStr),
+ pMsg->json = json_tokener_parse_ex(tokener, (char*)rsCStrGetSzStrNoNULL(pVar->val.pStr),
cstrLen(pVar->val.pStr));
+ json_tokener_free(tokener);
reinitVar(pVar);
CHKiRet(objDeserializeProperty(pVar, pStrm));
}
- if(isProp("pCSStrucData")) {
+ if(isProp("localvars")) {
+ tokener = json_tokener_new();
+ pMsg->localvars = json_tokener_parse_ex(tokener, (char*)rsCStrGetSzStrNoNULL(pVar->val.pStr),
+ cstrLen(pVar->val.pStr));
+ json_tokener_free(tokener);
+ reinitVar(pVar);
+ CHKiRet(objDeserializeProperty(pVar, pStrm));
+ }
+ if(isProp("pszStrucData")) {
MsgSetStructuredData(pMsg, (char*) rsCStrGetSzStrNoNULL(pVar->val.pStr));
reinitVar(pVar);
CHKiRet(objDeserializeProperty(pVar, pStrm));
@@ -1255,7 +1308,7 @@ finalize_it:
*
* pSecondMsgPointer = MsgAddRef(pOrgMsgPointer);
*/
-msg_t *MsgAddRef(msg_t *pM)
+msg_t *MsgAddRef(msg_t * const pM)
{
assert(pM != NULL);
# ifdef HAVE_ATOMIC_BUILTINS
@@ -1281,7 +1334,7 @@ msg_t *MsgAddRef(msg_t *pM)
* rgerhards, 2005-11-24
* THIS MUST be called with the message lock locked.
*/
-static rsRetVal aquirePROCIDFromTAG(msg_t *pM)
+static rsRetVal aquirePROCIDFromTAG(msg_t * const pM)
{
register int i;
uchar *pszTag;
@@ -1292,7 +1345,7 @@ static rsRetVal aquirePROCIDFromTAG(msg_t *pM)
if(pM->pCSPROCID != NULL)
return RS_RET_OK; /* we are already done ;) */
- if(getProtocolVersion(pM) != 0)
+ if(msgGetProtocolVersion(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);
@@ -1346,7 +1399,7 @@ finalize_it:
* rgerhards, 2005-10-19
*/
static inline rsRetVal
-aquireProgramName(msg_t *pM)
+aquireProgramName(msg_t * const pM)
{
int i;
uchar *pszTag, *pszProgName;
@@ -1376,7 +1429,7 @@ finalize_it:
/* Access methods - dumb & easy, not a comment for each ;)
*/
-void setProtocolVersion(msg_t *pM, int iNewVersion)
+void setProtocolVersion(msg_t * const pM, int iNewVersion)
{
assert(pM != NULL);
if(iNewVersion != 0 && iNewVersion != 1) {
@@ -1387,7 +1440,7 @@ void setProtocolVersion(msg_t *pM, int iNewVersion)
}
/* note: string is taken from constant pool, do NOT free */
-char *getProtocolVersionString(msg_t *pM)
+char *getProtocolVersionString(msg_t * const pM)
{
assert(pM != NULL);
return(pM->iProtocolVersion ? "1" : "0");
@@ -1397,7 +1450,7 @@ char *getProtocolVersionString(msg_t *pM)
/* note: libuuid seems not to be thread-safe, so we need
* to get some safeguards in place.
*/
-static void msgSetUUID(msg_t *pM)
+static void msgSetUUID(msg_t * const pM)
{
size_t lenRes = sizeof(uuid_t) * 2 + 1;
char hex_char [] = "0123456789ABCDEF";
@@ -1405,7 +1458,7 @@ static void msgSetUUID(msg_t *pM)
uuid_t uuid;
static pthread_mutex_t mutUUID = PTHREAD_MUTEX_INITIALIZER;
- dbgprintf("[MsgSetUUID] START\n");
+ dbgprintf("[MsgSetUUID] START, lenRes %llu\n", (long long unsigned) lenRes);
assert(pM != NULL);
if((pM->pszUUID = (uchar*) MALLOC(lenRes)) == NULL) {
@@ -1419,13 +1472,13 @@ static void msgSetUUID(msg_t *pM)
pM->pszUUID[byte_nbr * 2 + 1] = hex_char[uuid [byte_nbr] & 15];
}
+ pM->pszUUID[lenRes-1] = '\0';
dbgprintf("[MsgSetUUID] UUID : %s LEN: %d \n", pM->pszUUID, (int)lenRes);
- pM->pszUUID[lenRes] = '\0';
}
dbgprintf("[MsgSetUUID] END\n");
}
-void getUUID(msg_t *pM, uchar **pBuf, int *piLen)
+void getUUID(msg_t * const pM, uchar **pBuf, int *piLen)
{
dbgprintf("[getUUID] START\n");
if(pM == NULL) {
@@ -1451,7 +1504,7 @@ void getUUID(msg_t *pM, uchar **pBuf, int *piLen)
#endif
void
-getRawMsg(msg_t *pM, uchar **pBuf, int *piLen)
+getRawMsg(msg_t * const pM, uchar **pBuf, int *piLen)
{
if(pM == NULL) {
*pBuf= UCHAR_CONSTANT("");
@@ -1471,17 +1524,17 @@ getRawMsg(msg_t *pM, uchar **pBuf, int *piLen)
/* note: setMSGLen() is only for friends who really know what they
* do. Setting an invalid length can be desasterous!
*/
-void setMSGLen(msg_t *pM, int lenMsg)
+void setMSGLen(msg_t * const pM, int lenMsg)
{
pM->iLenMSG = lenMsg;
}
-int getMSGLen(msg_t *pM)
+int getMSGLen(msg_t * const pM)
{
return((pM == NULL) ? 0 : pM->iLenMSG);
}
-uchar *getMSG(msg_t *pM)
+uchar *getMSG(msg_t * const pM)
{
uchar *ret;
if(pM == NULL)
@@ -1497,16 +1550,19 @@ uchar *getMSG(msg_t *pM)
/* Get PRI value as integer */
-static int getPRIi(msg_t *pM)
+static int getPRIi(msg_t * const pM)
{
- return (pM->iFacility << 3) + (pM->iSeverity);
+ int pri = (pM->iFacility << 3) + (pM->iSeverity);
+ if(pri > 191)
+ pri = LOG_PRI_INVLD;
+ return pri;
}
/* Get PRI value in text form
*/
char *
-getPRI(msg_t *pM)
+getPRI(msg_t * const 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 ;)
@@ -1522,7 +1578,7 @@ getPRI(msg_t *pM)
char *
-getTimeReported(msg_t *pM, enum tplFormatTypes eFmt)
+getTimeReported(msg_t * const pM, enum tplFormatTypes eFmt)
{
BEGINfunc
if(pM == NULL)
@@ -1587,12 +1643,37 @@ getTimeReported(msg_t *pM, enum tplFormatTypes eFmt)
MsgUnlock(pM);
}
return(pM->pszTIMESTAMP_SecFrac);
+ case tplFmtWDayName:
+ return wdayNames[getWeekdayNbr(&pM->tTIMESTAMP)];
+ case tplFmtWDay:
+ return one_digit[getWeekdayNbr(&pM->tTIMESTAMP)];
+ case tplFmtMonth:
+ return two_digits[(int)pM->tTIMESTAMP.month];
+ case tplFmtYear:
+ if(pM->tTIMESTAMP.year >= 1967 && pM->tTIMESTAMP.year <= 2099)
+ return years[pM->tTIMESTAMP.year - 1967];
+ else
+ return "YEAR OUT OF RANGE(1967-2099)";
+ case tplFmtDay:
+ return two_digits[(int)pM->tTIMESTAMP.day];
+ case tplFmtHour:
+ return two_digits[(int)pM->tTIMESTAMP.hour];
+ case tplFmtMinute:
+ return two_digits[(int)pM->tTIMESTAMP.minute];
+ case tplFmtSecond:
+ return two_digits[(int)pM->tTIMESTAMP.second];
+ case tplFmtTZOffsHour:
+ return two_digits[(int)pM->tTIMESTAMP.OffsetHour];
+ case tplFmtTZOffsMin:
+ return two_digits[(int)pM->tTIMESTAMP.OffsetMinute];
+ case tplFmtTZOffsDirection:
+ return (pM->tTIMESTAMP.OffsetMode == '+')? "+" : "-";
}
ENDfunc
return "INVALID eFmt OPTION!";
}
-static inline char *getTimeGenerated(msg_t *pM, enum tplFormatTypes eFmt)
+static char *getTimeGenerated(msg_t * const pM, enum tplFormatTypes eFmt)
{
BEGINfunc
if(pM == NULL)
@@ -1673,13 +1754,38 @@ static inline char *getTimeGenerated(msg_t *pM, enum tplFormatTypes eFmt)
MsgUnlock(pM);
}
return(pM->pszRcvdAt_SecFrac);
+ case tplFmtWDayName:
+ return wdayNames[getWeekdayNbr(&pM->tRcvdAt)];
+ case tplFmtWDay:
+ return one_digit[getWeekdayNbr(&pM->tRcvdAt)];
+ case tplFmtMonth:
+ return two_digits[(int)pM->tRcvdAt.month];
+ case tplFmtYear:
+ if(pM->tRcvdAt.year >= 1967 && pM->tRcvdAt.year <= 2099)
+ return years[pM->tRcvdAt.year - 1967];
+ else
+ return "YEAR OUT OF RANGE(1967-2099)";
+ case tplFmtDay:
+ return two_digits[(int)pM->tRcvdAt.day];
+ case tplFmtHour:
+ return two_digits[(int)pM->tRcvdAt.hour];
+ case tplFmtMinute:
+ return two_digits[(int)pM->tRcvdAt.minute];
+ case tplFmtSecond:
+ return two_digits[(int)pM->tRcvdAt.second];
+ case tplFmtTZOffsHour:
+ return two_digits[(int)pM->tRcvdAt.OffsetHour];
+ case tplFmtTZOffsMin:
+ return two_digits[(int)pM->tRcvdAt.OffsetMinute];
+ case tplFmtTZOffsDirection:
+ return (pM->tRcvdAt.OffsetMode == '+')? "+" : "-";
}
ENDfunc
return "INVALID eFmt OPTION!";
}
-static inline char *getSeverity(msg_t *pM)
+static inline char *getSeverity(msg_t * const pM)
{
char *name = NULL;
@@ -1696,7 +1802,7 @@ static inline char *getSeverity(msg_t *pM)
}
-static inline char *getSeverityStr(msg_t *pM)
+static inline char *getSeverityStr(msg_t * const pM)
{
char *name = NULL;
@@ -1712,7 +1818,7 @@ static inline char *getSeverityStr(msg_t *pM)
return name;
}
-static inline char *getFacility(msg_t *pM)
+static inline char *getFacility(msg_t * const pM)
{
char *name = NULL;
@@ -1728,7 +1834,7 @@ static inline char *getFacility(msg_t *pM)
return name;
}
-static inline char *getFacilityStr(msg_t *pM)
+static inline char *getFacilityStr(msg_t * const pM)
{
char *name = NULL;
@@ -1752,7 +1858,7 @@ static inline char *getFacilityStr(msg_t *pM)
* rgerhards, 2008-03-14
*/
rsRetVal
-MsgSetFlowControlType(msg_t *pMsg, flowControl_t eFlowCtl)
+MsgSetFlowControlType(msg_t * const pMsg, flowControl_t eFlowCtl)
{
DEFiRet;
assert(pMsg != NULL);
@@ -1767,7 +1873,7 @@ MsgSetFlowControlType(msg_t *pMsg, flowControl_t eFlowCtl)
* rgerhards, 2009-06-16
*/
rsRetVal
-MsgSetAfterPRIOffs(msg_t *pMsg, short offs)
+MsgSetAfterPRIOffs(msg_t * const pMsg, short offs)
{
assert(pMsg != NULL);
pMsg->offAfterPRI = offs;
@@ -1781,7 +1887,7 @@ MsgSetAfterPRIOffs(msg_t *pMsg, short offs)
* which already obtained the lock. So in general, this function here must
* only be called when it it safe to do so without it aquiring a lock.
*/
-rsRetVal MsgSetAPPNAME(msg_t *pMsg, char* pszAPPNAME)
+rsRetVal MsgSetAPPNAME(msg_t *__restrict__ const pMsg, const char* pszAPPNAME)
{
DEFiRet;
assert(pMsg != NULL);
@@ -1799,7 +1905,7 @@ finalize_it:
/* rgerhards 2004-11-24: set PROCID in msg object
*/
-rsRetVal MsgSetPROCID(msg_t *pMsg, char* pszPROCID)
+rsRetVal MsgSetPROCID(msg_t *__restrict__ const pMsg, const char* pszPROCID)
{
DEFiRet;
ISOBJ_TYPE_assert(pMsg, msg);
@@ -1820,7 +1926,7 @@ finalize_it:
* This must be called WITHOUT the message lock being held.
* rgerhards, 2009-06-26
*/
-static inline void preparePROCID(msg_t *pM, sbool bLockMutex)
+static inline void preparePROCID(msg_t * const pM, sbool bLockMutex)
{
if(pM->pCSPROCID == NULL) {
if(bLockMutex == LOCK_MUTEX)
@@ -1848,7 +1954,7 @@ static inline int getPROCIDLen(msg_t *pM, sbool bLockMutex)
/* rgerhards, 2005-11-24
*/
-char *getPROCID(msg_t *pM, sbool bLockMutex)
+char *getPROCID(msg_t * const pM, sbool bLockMutex)
{
uchar *pszRet;
@@ -1868,7 +1974,7 @@ char *getPROCID(msg_t *pM, sbool bLockMutex)
/* rgerhards 2004-11-24: set MSGID in msg object
*/
-rsRetVal MsgSetMSGID(msg_t *pMsg, char* pszMSGID)
+rsRetVal MsgSetMSGID(msg_t * const pMsg, const char* pszMSGID)
{
DEFiRet;
ISOBJ_TYPE_assert(pMsg, msg);
@@ -1887,7 +1993,7 @@ finalize_it:
/* Return state of last parser. If it had success, "OK" is returned, else
* "FAIL". All from the constant pool.
*/
-static inline char *getParseSuccess(msg_t *pM)
+static inline char *getParseSuccess(msg_t * const pM)
{
return (pM->bParseSuccess) ? "OK" : "FAIL";
}
@@ -1895,7 +2001,7 @@ static inline char *getParseSuccess(msg_t *pM)
/* al, 2011-07-26: LockMsg to avoid race conditions
*/
-static inline char *getMSGID(msg_t *pM)
+static inline char *getMSGID(msg_t * const pM)
{
if (pM->pCSMSGID == NULL) {
return "-";
@@ -1910,15 +2016,104 @@ static inline char *getMSGID(msg_t *pM)
/* rgerhards 2012-03-15: set parser success (an integer, acutally bool)
*/
-void MsgSetParseSuccess(msg_t *pMsg, int bSuccess)
+void MsgSetParseSuccess(msg_t * const pMsg, int bSuccess)
{
assert(pMsg != NULL);
pMsg->bParseSuccess = bSuccess;
}
+
+/* return full message as a json string */
+const uchar*
+msgGetJSONMESG(msg_t *__restrict__ const pMsg)
+{
+ struct json_object *json;
+ struct json_object *jval;
+ uchar *pRes; /* result pointer */
+ rs_size_t bufLen = -1; /* length of string or -1, if not known */
+
+ json = json_object_new_object();
+
+ jval = json_object_new_string((char*)getMSG(pMsg));
+ json_object_object_add(json, "msg", jval);
+
+ getRawMsg(pMsg, &pRes, &bufLen);
+ jval = json_object_new_string((char*)pRes);
+ json_object_object_add(json, "rawmsg", jval);
+
+ pRes = (uchar*)getTimeReported(pMsg, tplFmtRFC3339Date);
+ jval = json_object_new_string((char*)pRes);
+ json_object_object_add(json, "timereported", jval);
+
+ jval = json_object_new_string(getHOSTNAME(pMsg));
+ json_object_object_add(json, "hostname", jval);
+
+ getTAG(pMsg, &pRes, &bufLen);
+ jval = json_object_new_string((char*)pRes);
+ json_object_object_add(json, "syslogtag", jval);
+
+ getInputName(pMsg, &pRes, &bufLen);
+ jval = json_object_new_string((char*)pRes);
+ json_object_object_add(json, "inputname", jval);
+
+ jval = json_object_new_string((char*)getRcvFrom(pMsg));
+ json_object_object_add(json, "fromhost", jval);
+
+ jval = json_object_new_string((char*)getRcvFromIP(pMsg));
+ json_object_object_add(json, "fromhost-ip", jval);
+
+ jval = json_object_new_string(getPRI(pMsg));
+ json_object_object_add(json, "pri", jval);
+
+ jval = json_object_new_string(getFacility(pMsg));
+ json_object_object_add(json, "syslogfacility", jval);
+
+ jval = json_object_new_string(getSeverity(pMsg));
+ json_object_object_add(json, "syslogseverity", jval);
+
+ pRes = (uchar*)getTimeGenerated(pMsg, tplFmtRFC3339Date);
+ jval = json_object_new_string((char*)pRes);
+ json_object_object_add(json, "timegenerated", jval);
+
+ jval = json_object_new_string((char*)getProgramName(pMsg, LOCK_MUTEX));
+ json_object_object_add(json, "programname", jval);
+
+ jval = json_object_new_string(getProtocolVersionString(pMsg));
+ json_object_object_add(json, "protocol-version", jval);
+
+ MsgGetStructuredData(pMsg, &pRes, &bufLen);
+ jval = json_object_new_string((char*)pRes);
+ json_object_object_add(json, "structured-data", jval);
+
+ jval = json_object_new_string(getAPPNAME(pMsg, LOCK_MUTEX));
+ json_object_object_add(json, "app-name", jval);
+
+ jval = json_object_new_string(getPROCID(pMsg, LOCK_MUTEX));
+ json_object_object_add(json, "procid", jval);
+
+ jval = json_object_new_string(getMSGID(pMsg));
+ json_object_object_add(json, "msgid", jval);
+
+#ifdef USE_LIBUUID
+ if(pMsg->pszUUID == NULL) {
+ jval = NULL;
+ } else {
+ getUUID(pMsg, &pRes, &bufLen);
+ jval = json_object_new_string((char*)pRes);
+ }
+ json_object_object_add(json, "uuid", jval);
+#endif
+
+ json_object_object_add(json, "$!", pMsg->json);
+
+ pRes = (uchar*) strdup(json_object_get_string(json));
+ json_object_put(json);
+ return pRes;
+}
+
/* rgerhards 2009-06-12: set associated ruleset
*/
-void MsgSetRuleset(msg_t *pMsg, ruleset_t *pRuleset)
+void MsgSetRuleset(msg_t * const pMsg, ruleset_t *pRuleset)
{
assert(pMsg != NULL);
pMsg->pRuleset = pRuleset;
@@ -1928,7 +2123,7 @@ void MsgSetRuleset(msg_t *pMsg, ruleset_t *pRuleset)
/* set TAG in msg object
* (rewritten 2009-06-18 rgerhards)
*/
-void MsgSetTAG(msg_t *pMsg, uchar* pszBuf, size_t lenBuf)
+void MsgSetTAG(msg_t *__restrict__ const pMsg, const uchar* pszBuf, const size_t lenBuf)
{
uchar *pBuf;
assert(pMsg != NULL);
@@ -1961,7 +2156,7 @@ void MsgSetTAG(msg_t *pMsg, uchar* pszBuf, size_t lenBuf)
* if there is a TAG and, if not, if it can emulate it.
* rgerhards, 2005-11-24
*/
-static inline void tryEmulateTAG(msg_t *pM, sbool bLockMutex)
+static inline void tryEmulateTAG(msg_t * const pM, sbool bLockMutex)
{
size_t lenTAG;
uchar bufTAG[CONF_TAG_MAXSIZE];
@@ -1975,7 +2170,7 @@ static inline void tryEmulateTAG(msg_t *pM, sbool bLockMutex)
return; /* done, no need to emulate */
}
- if(getProtocolVersion(pM) == 1) {
+ if(msgGetProtocolVersion(pM) == 1) {
if(!strcmp(getPROCID(pM, MUTEX_ALREADY_LOCKED), "-")) {
/* no process ID, use APP-NAME only */
MsgSetTAG(pM, (uchar*) getAPPNAME(pM, MUTEX_ALREADY_LOCKED), getAPPNAMELen(pM, MUTEX_ALREADY_LOCKED));
@@ -1993,7 +2188,7 @@ static inline void tryEmulateTAG(msg_t *pM, sbool bLockMutex)
void
-getTAG(msg_t *pM, uchar **ppBuf, int *piLen)
+getTAG(msg_t * const pM, uchar **ppBuf, int *piLen)
{
if(pM == NULL) {
*ppBuf = UCHAR_CONSTANT("");
@@ -2012,7 +2207,7 @@ getTAG(msg_t *pM, uchar **ppBuf, int *piLen)
}
-int getHOSTNAMELen(msg_t *pM)
+int getHOSTNAMELen(msg_t * const pM)
{
if(pM == NULL)
return 0;
@@ -2028,7 +2223,7 @@ int getHOSTNAMELen(msg_t *pM)
}
-char *getHOSTNAME(msg_t *pM)
+char *getHOSTNAME(msg_t * const pM)
{
if(pM == NULL)
return "";
@@ -2049,7 +2244,7 @@ char *getHOSTNAME(msg_t *pM)
}
-uchar *getRcvFrom(msg_t *pM)
+uchar *getRcvFrom(msg_t * const pM)
{
uchar *psz;
int len;
@@ -2071,52 +2266,37 @@ uchar *getRcvFrom(msg_t *pM)
/* rgerhards 2004-11-24: set STRUCTURED DATA in msg object
*/
-rsRetVal MsgSetStructuredData(msg_t *pMsg, char* pszStrucData)
+rsRetVal MsgSetStructuredData(msg_t * const pMsg, const char* pszStrucData)
{
DEFiRet;
ISOBJ_TYPE_assert(pMsg, msg);
- if(pMsg->pCSStrucData == NULL) {
- /* we need to obtain the object first */
- CHKiRet(rsCStrConstruct(&pMsg->pCSStrucData));
- }
- /* if we reach this point, we have the object */
- iRet = rsCStrSetSzStr(pMsg->pCSStrucData, (uchar*) pszStrucData);
-
+ free(pMsg->pszStrucData);
+ CHKmalloc(pMsg->pszStrucData = (uchar*)strdup(pszStrucData));
+ pMsg->lenStrucData = strlen(pszStrucData);
finalize_it:
RETiRet;
}
-/* get the length of the "STRUCTURED-DATA" sz string
- * rgerhards, 2005-11-24
- */
-#if 0 /* This method is currently not called, be we like to preserve it */
-static int getStructuredDataLen(msg_t *pM)
-{
- return (pM->pCSStrucData == NULL) ? 1 : rsCStrLen(pM->pCSStrucData);
-}
-#endif
-
-/* get the "STRUCTURED-DATA" as sz string
- * rgerhards, 2005-11-24
- */
-static inline char *getStructuredData(msg_t *pM)
+/* get the "STRUCTURED-DATA" as sz string, including length */
+void
+MsgGetStructuredData(msg_t * const pM, uchar **pBuf, rs_size_t *len)
{
- uchar *pszRet;
-
MsgLock(pM);
- if(pM->pCSStrucData == NULL)
- pszRet = UCHAR_CONSTANT("-");
- else
- pszRet = rsCStrGetSzStrNoNULL(pM->pCSStrucData);
+ if(pM->pszStrucData == NULL) {
+ *pBuf = UCHAR_CONSTANT("-"),
+ *len = 1;
+ } else {
+ *pBuf = pM->pszStrucData,
+ *len = pM->lenStrucData;
+ }
MsgUnlock(pM);
- return (char*) pszRet;
}
/* get the "programname" as sz string
* rgerhards, 2005-10-19
*/
-uchar *getProgramName(msg_t *pM, sbool bLockMutex)
+uchar *getProgramName(msg_t * const pM, sbool bLockMutex)
{
if(pM->iLenPROGNAME == -1) {
if(bLockMutex == LOCK_MUTEX) {
@@ -2139,13 +2319,13 @@ uchar *getProgramName(msg_t *pM, sbool bLockMutex)
* now would like to send out the same one via syslog-protocol.
* MUST be called with the Msg Lock locked!
*/
-static void tryEmulateAPPNAME(msg_t *pM)
+static void tryEmulateAPPNAME(msg_t * const pM)
{
assert(pM != NULL);
if(pM->pCSAPPNAME != NULL)
return; /* we are already done */
- if(getProtocolVersion(pM) == 0) {
+ if(msgGetProtocolVersion(pM) == 0) {
/* only then it makes sense to emulate */
MsgSetAPPNAME(pM, (char*)getProgramName(pM, MUTEX_ALREADY_LOCKED));
}
@@ -2157,7 +2337,7 @@ static void tryEmulateAPPNAME(msg_t *pM)
* This must be called WITHOUT the message lock being held.
* rgerhards, 2009-06-26
*/
-static inline void prepareAPPNAME(msg_t *pM, sbool bLockMutex)
+static inline void prepareAPPNAME(msg_t * const pM, sbool bLockMutex)
{
if(pM->pCSAPPNAME == NULL) {
if(bLockMutex == LOCK_MUTEX)
@@ -2174,7 +2354,7 @@ static inline void prepareAPPNAME(msg_t *pM, sbool bLockMutex)
/* rgerhards, 2005-11-24
*/
-char *getAPPNAME(msg_t *pM, sbool bLockMutex)
+char *getAPPNAME(msg_t * const pM, sbool bLockMutex)
{
uchar *pszRet;
@@ -2193,7 +2373,7 @@ char *getAPPNAME(msg_t *pM, sbool bLockMutex)
/* rgerhards, 2005-11-24
*/
-static int getAPPNAMELen(msg_t *pM, sbool bLockMutex)
+static int getAPPNAMELen(msg_t * const pM, sbool bLockMutex)
{
assert(pM != NULL);
prepareAPPNAME(pM, bLockMutex);
@@ -2215,6 +2395,15 @@ void MsgSetInputName(msg_t *pThis, prop_t *inputName)
pThis->pInputName = inputName;
}
+/* Set default TZ. Note that at most 7 chars are set, as we would
+ * otherwise overrun our buffer!
+ */
+void MsgSetDfltTZ(msg_t *pThis, char *tz)
+{
+ strncpy(pThis->dfltTZ, tz, 7);
+ pThis->dfltTZ[7] = '\0'; /* ensure 0-Term in case of overflow! */
+}
+
/* Set the pfrominet socket store, so that we can obtain the peer at some
* later time. Note that we do not check if pRcvFrom is already set, so this
@@ -2237,7 +2426,6 @@ finalize_it:
RETiRet;
}
-
/* rgerhards 2008-09-10: set RcvFrom name in msg object. This calls AddRef()
* on the property, because this must be done in all current cases and there
* is no case expected where this may not be necessary.
@@ -2258,7 +2446,7 @@ void MsgSetRcvFrom(msg_t *pThis, prop_t *new)
* name (but it works only for the immediate previous).
* rgerhards, 2009-06-31
*/
-void MsgSetRcvFromStr(msg_t *pThis, uchar *psz, int len, prop_t **ppProp)
+void MsgSetRcvFromStr(msg_t * const pThis, const uchar *psz, const int len, prop_t **ppProp)
{
assert(pThis != NULL);
assert(ppProp != NULL);
@@ -2293,7 +2481,7 @@ rsRetVal MsgSetRcvFromIP(msg_t *pThis, prop_t *new)
* name (but it works only for the immediate previous).
* rgerhards, 2009-06-31
*/
-rsRetVal MsgSetRcvFromIPStr(msg_t *pThis, uchar *psz, int len, prop_t **ppProp)
+rsRetVal MsgSetRcvFromIPStr(msg_t *const pThis, const uchar *psz, const int len, prop_t **ppProp)
{
DEFiRet;
assert(pThis != NULL);
@@ -2316,7 +2504,7 @@ finalize_it:
* we need it. The rest of the code already knows how to handle an
* unset HOSTNAME.
*/
-void MsgSetHOSTNAME(msg_t *pThis, uchar* pszHOSTNAME, int lenHOSTNAME)
+void MsgSetHOSTNAME(msg_t *pThis, const uchar* pszHOSTNAME, const int lenHOSTNAME)
{
assert(pThis != NULL);
@@ -2342,7 +2530,7 @@ void MsgSetHOSTNAME(msg_t *pThis, uchar* pszHOSTNAME, int lenHOSTNAME)
* (exactly by one). This can happen if we have a message that does not
* contain any MSG part.
*/
-void MsgSetMSGoffs(msg_t *pMsg, short offs)
+void MsgSetMSGoffs(msg_t * const pMsg, short offs)
{
ISOBJ_TYPE_assert(pMsg, msg);
pMsg->offMSG = offs;
@@ -2367,7 +2555,7 @@ void MsgSetMSGoffs(msg_t *pMsg, short offs)
* the caller is responsible for freeing it.
* rgerhards, 2009-06-23
*/
-rsRetVal MsgReplaceMSG(msg_t *pThis, uchar* pszMSG, int lenMSG)
+rsRetVal MsgReplaceMSG(msg_t *pThis, const uchar* pszMSG, int lenMSG)
{
int lenNew;
uchar *bufNew;
@@ -2400,12 +2588,14 @@ finalize_it:
* terminated by '\0'.
* rgerhards, 2009-06-16
*/
-void MsgSetRawMsg(msg_t *pThis, char* pszRawMsg, size_t lenMsg)
+void MsgSetRawMsg(msg_t *pThis, const char* pszRawMsg, size_t lenMsg)
{
+ int deltaSize;
assert(pThis != NULL);
if(pThis->pszRawMsg != pThis->szRawMsg)
free(pThis->pszRawMsg);
+ deltaSize = lenMsg - pThis->iLenRawMsg;
pThis->iLenRawMsg = lenMsg;
if(pThis->iLenRawMsg < CONF_RAWMSG_BUFSIZE) {
/* small enough: use fixed buffer (faster!) */
@@ -2418,6 +2608,11 @@ void MsgSetRawMsg(msg_t *pThis, char* pszRawMsg, size_t lenMsg)
memcpy(pThis->pszRawMsg, pszRawMsg, pThis->iLenRawMsg);
pThis->pszRawMsg[pThis->iLenRawMsg] = '\0'; /* this also works with truncation! */
+ /* correct other information */
+ if(pThis->iLenRawMsg > pThis->offMSG)
+ pThis->iLenMSG += deltaSize;
+ else
+ pThis->iLenMSG = 0;
}
@@ -2426,7 +2621,7 @@ void MsgSetRawMsg(msg_t *pThis, char* pszRawMsg, size_t lenMsg)
* try to remove it altogether).
* rgerhards, 2009-06-16
*/
-void MsgSetRawMsgWOSize(msg_t *pMsg, char* pszRawMsg)
+void MsgSetRawMsgWOSize(msg_t * const pMsg, char* pszRawMsg)
{
MsgSetRawMsg(pMsg, pszRawMsg, strlen(pszRawMsg));
}
@@ -2442,11 +2637,11 @@ void MsgSetRawMsgWOSize(msg_t *pMsg, char* pszRawMsg)
char *textpri(char *pRes, int pri)
{
assert(pRes != NULL);
- memcpy(pRes, syslog_fac_names[LOG_FAC(pri)], len_syslog_fac_names[LOG_FAC(pri)]);
- pRes[len_syslog_fac_names[LOG_FAC(pri)]] = '.';
- memcpy(pRes+len_syslog_fac_names[LOG_FAC(pri)]+1,
- syslog_severity_names[LOG_PRI(pri)],
- len_syslog_severity_names[LOG_PRI(pri)]+1 /* for \0! */);
+ memcpy(pRes, syslog_fac_names[pri2fac(pri)], len_syslog_fac_names[pri2fac(pri)]);
+ pRes[len_syslog_fac_names[pri2fac(pri)]] = '.';
+ memcpy(pRes+len_syslog_fac_names[pri2fac(pri)]+1,
+ syslog_severity_names[pri2sev(pri)],
+ len_syslog_severity_names[pri2sev(pri)]+1 /* for \0! */);
return pRes;
}
@@ -2463,11 +2658,17 @@ typedef enum ENOWType { NOW_NOW, NOW_YEAR, NOW_MONTH, NOW_DAY, NOW_HOUR, NOW_HHO
static uchar *getNOW(eNOWType eNow, struct syslogTime *t)
{
uchar *pBuf;
+ struct syslogTime tt;
if((pBuf = (uchar*) MALLOC(sizeof(uchar) * tmpBUFSIZE)) == NULL) {
return NULL;
}
+ if(t == NULL) { /* can happen if called via script engine */
+ datetime.getCurrTime(&tt, NULL);
+ t = &tt;
+ }
+
if(t->year == 0) { /* not yet set! */
datetime.getCurrTime(t, NULL);
}
@@ -2495,10 +2696,10 @@ static uchar *getNOW(eNOWType eNow, struct syslogTime *t)
memcpy(pBuf, two_digits[(int)t->hour], 3);
break;
case NOW_HHOUR:
- memcpy(pBuf, two_digits[t->hour/30], 3);
+ memcpy(pBuf, two_digits[t->minute/30], 3);
break;
case NOW_QHOUR:
- memcpy(pBuf, two_digits[t->hour/15], 3);
+ memcpy(pBuf, two_digits[t->minute/15], 3);
break;
case NOW_MINUTE:
memcpy(pBuf, two_digits[(int)t->minute], 3);
@@ -2510,12 +2711,12 @@ static uchar *getNOW(eNOWType eNow, struct syslogTime *t)
#undef tmpBUFSIZE /* clean up */
-/* Get a CEE-Property as string value*/
+/* Get a JSON-Property as string value (used for various types of JSON-based vars) */
rsRetVal
-getCEEPropVal(msg_t *pM, es_str_t *propName, uchar **pRes, rs_size_t *buflen, unsigned short *pbMustBeFreed)
+getJSONPropVal(msg_t * const pMsg, msgPropDescr_t *pProp, uchar **pRes, rs_size_t *buflen, unsigned short *pbMustBeFreed)
{
- uchar *name = NULL;
uchar *leaf;
+ struct json_object *jroot;
struct json_object *parent;
struct json_object *field;
DEFiRet;
@@ -2523,15 +2724,26 @@ getCEEPropVal(msg_t *pM, es_str_t *propName, uchar **pRes, rs_size_t *buflen, un
if(*pbMustBeFreed)
free(*pRes);
*pRes = NULL;
- // TODO: mutex?
- if(pM->json == NULL) goto finalize_it;
- if(!es_strbufcmp(propName, (uchar*)"!", 1)) {
- field = pM->json;
+ if(pProp->id == PROP_CEE) {
+ jroot = pMsg->json;
+ } else if(pProp->id == PROP_LOCAL_VAR) {
+ jroot = pMsg->localvars;
+ } else if(pProp->id == PROP_GLOBAL_VAR) {
+ pthread_rwlock_rdlock(&glblVars_rwlock);
+ jroot = global_var_root;
} else {
- name = (uchar*)es_str2cstr(propName, NULL);
- leaf = jsonPathGetLeaf(name, ustrlen(name));
- CHKiRet(jsonPathFindParent(pM, name, leaf, &parent, 1));
+ DBGPRINTF("msgGetJSONPropVal; invalid property id %d\n",
+ pProp->id);
+ ABORT_FINALIZE(RS_RET_NOT_FOUND);
+ }
+ if(jroot == NULL) goto finalize_it;
+
+ if(!strcmp((char*)pProp->name, "!")) {
+ field = jroot;
+ } else {
+ leaf = jsonPathGetLeaf(pProp->name, pProp->nameLen);
+ CHKiRet(jsonPathFindParent(jroot, pProp->name, leaf, &parent, 1));
field = json_object_object_get(parent, (char*)leaf);
}
if(field != NULL) {
@@ -2541,7 +2753,8 @@ getCEEPropVal(msg_t *pM, es_str_t *propName, uchar **pRes, rs_size_t *buflen, un
}
finalize_it:
- free(name);
+ if(pProp->id == PROP_GLOBAL_VAR)
+ pthread_rwlock_unlock(&glblVars_rwlock);
if(*pRes == NULL) {
/* could not find any value, so set it to empty */
*pRes = (unsigned char*)"";
@@ -2551,55 +2764,71 @@ finalize_it:
}
-/* Get a CEE-Property as native json object
- */
+/* Get a JSON-based-variable as native json object */
rsRetVal
-msgGetCEEPropJSON(msg_t *pM, es_str_t *propName, struct json_object **pjson)
+msgGetJSONPropJSON(msg_t * const pMsg, msgPropDescr_t *pProp, struct json_object **pjson)
{
- uchar *name = NULL;
+ struct json_object *jroot;
uchar *leaf;
struct json_object *parent;
DEFiRet;
- // TODO: mutex?
- if(pM->json == NULL) {
+ if(pProp->id == PROP_CEE) {
+ jroot = pMsg->json;
+ } else if(pProp->id == PROP_LOCAL_VAR) {
+ jroot = pMsg->localvars;
+ } else if(pProp->id == PROP_GLOBAL_VAR) {
+ pthread_rwlock_rdlock(&glblVars_rwlock);
+ jroot = global_var_root;
+ } else {
+ DBGPRINTF("msgGetJSONPropJSON; invalid property id %d\n",
+ pProp->id);
+ ABORT_FINALIZE(RS_RET_NOT_FOUND);
+ }
+ if(jroot == NULL) {
+ DBGPRINTF("msgGetJSONPropJSON; jroot empty for property %s\n",
+ pProp->name);
ABORT_FINALIZE(RS_RET_NOT_FOUND);
}
- if(!es_strbufcmp(propName, (uchar*)"!", 1)) {
- *pjson = pM->json;
+ if(!strcmp((char*)pProp->name, "!")) {
+ *pjson = jroot;
FINALIZE;
}
- name = (uchar*)es_str2cstr(propName, NULL);
- leaf = jsonPathGetLeaf(name, ustrlen(name));
- CHKiRet(jsonPathFindParent(pM, name, leaf, &parent, 1));
+ leaf = jsonPathGetLeaf(pProp->name, pProp->nameLen);
+ CHKiRet(jsonPathFindParent(jroot, pProp->name, leaf, &parent, 1));
*pjson = json_object_object_get(parent, (char*)leaf);
if(*pjson == NULL) {
ABORT_FINALIZE(RS_RET_NOT_FOUND);
}
finalize_it:
- free(name);
+ if(pProp->id == PROP_GLOBAL_VAR)
+ pthread_rwlock_unlock(&glblVars_rwlock);
RETiRet;
}
/* Encode a JSON value and add it to provided string. Note that
* the string object may be NULL. In this case, it is created
- * if and only if escaping is needed.
+ * if and only if escaping is needed. if escapeAll is false, previously
+ * escaped strings are left as is
*/
static rsRetVal
-jsonAddVal(uchar *pSrc, unsigned buflen, es_str_t **dst)
+jsonAddVal(uchar *pSrc, unsigned buflen, es_str_t **dst, int escapeAll)
{
unsigned char c;
es_size_t i;
char numbuf[4];
+ unsigned ni;
+ unsigned char nc;
int j;
DEFiRet;
for(i = 0 ; i < buflen ; ++i) {
c = pSrc[i];
- if( (c >= 0x23 && c <= 0x5b)
+ if( (c >= 0x23 && c <= 0x2e)
+ || (c >= 0x30 && c <= 0x5b)
|| (c >= 0x5d /* && c <= 0x10FFFF*/)
|| c == 0x20 || c == 0x21) {
/* no need to escape */
@@ -2629,6 +2858,23 @@ jsonAddVal(uchar *pSrc, unsigned buflen, es_str_t **dst)
es_addBuf(dst, "\\/", 2);
break;
case '\\':
+ if (escapeAll == RSFALSE) {
+ ni = i + 1;
+ if (ni <= buflen) {
+ nc = pSrc[ni];
+
+ /* Attempt to not double encode */
+ if ( nc == '"' || nc == '/' || nc == '\\' || nc == 'b' || nc == 'f'
+ || nc == 'n' || nc == 'r' || nc == 't' || nc == 'u') {
+
+ es_addChar(dst, c);
+ es_addChar(dst, nc);
+ i = ni;
+ break;
+ }
+ }
+ }
+
es_addBuf(dst, "\\\\", 2);
break;
case '\010':
@@ -2674,7 +2920,7 @@ finalize_it:
* rgerhards, 2012-03-16
*/
static rsRetVal
-jsonEncode(uchar **ppRes, unsigned short *pbMustBeFreed, int *pBufLen)
+jsonEncode(uchar **ppRes, unsigned short *pbMustBeFreed, int *pBufLen, int escapeAll)
{
unsigned buflen;
uchar *pSrc;
@@ -2683,7 +2929,7 @@ jsonEncode(uchar **ppRes, unsigned short *pbMustBeFreed, int *pBufLen)
pSrc = *ppRes;
buflen = (*pBufLen == -1) ? ustrlen(pSrc) : *pBufLen;
- CHKiRet(jsonAddVal(pSrc, buflen, &dst));
+ CHKiRet(jsonAddVal(pSrc, buflen, &dst, escapeAll));
if(dst != NULL) {
/* we updated the string and need to replace the
@@ -2712,7 +2958,7 @@ finalize_it:
* something to consider at a later stage. rgerhards, 2012-04-19
*/
static rsRetVal
-jsonField(struct templateEntry *pTpe, uchar **ppRes, unsigned short *pbMustBeFreed, int *pBufLen)
+jsonField(struct templateEntry *pTpe, uchar **ppRes, unsigned short *pbMustBeFreed, int *pBufLen, int escapeAll)
{
unsigned buflen;
uchar *pSrc;
@@ -2726,7 +2972,7 @@ jsonField(struct templateEntry *pTpe, uchar **ppRes, unsigned short *pbMustBeFre
es_addChar(&dst, '"');
es_addBuf(&dst, (char*)pTpe->fieldName, pTpe->lenFieldName);
es_addBufConstcstr(&dst, "\":\"");
- CHKiRet(jsonAddVal(pSrc, buflen, &dst));
+ CHKiRet(jsonAddVal(pSrc, buflen, &dst, escapeAll));
es_addChar(&dst, '"');
if(*pbMustBeFreed)
@@ -2783,9 +3029,9 @@ finalize_it:
#define RET_OUT_OF_MEMORY { *pbMustBeFreed = 0;\
*pPropLen = sizeof("**OUT OF MEMORY**") - 1; \
return(UCHAR_CONSTANT("**OUT OF MEMORY**"));}
-uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
- propid_t propid, es_str_t *propName, rs_size_t *pPropLen,
- unsigned short *pbMustBeFreed, struct syslogTime *ttNow)
+uchar *MsgGetProp(msg_t *__restrict__ const pMsg, struct templateEntry *__restrict__ const pTpe,
+ msgPropDescr_t *pProp, rs_size_t *__restrict__ const pPropLen,
+ unsigned short *__restrict__ const pbMustBeFreed, struct syslogTime * const ttNow)
{
uchar *pRes; /* result pointer */
rs_size_t bufLen = -1; /* length of string or -1, if not known */
@@ -2807,7 +3053,7 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
*pbMustBeFreed = 0;
- switch(propid) {
+ switch(pProp->id) {
case PROP_MSG:
pRes = getMSG(pMsg);
bufLen = getMSGLen(pMsg);
@@ -2880,7 +3126,7 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
pRes = (uchar*)getProtocolVersionString(pMsg);
break;
case PROP_STRUCTURED_DATA:
- pRes = (uchar*)getStructuredData(pMsg);
+ MsgGetStructuredData(pMsg, &pRes, &bufLen);
break;
case PROP_APP_NAME:
pRes = (uchar*)getAPPNAME(pMsg, LOCK_MUTEX);
@@ -2891,6 +3137,10 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
case PROP_MSGID:
pRes = (uchar*)getMSGID(pMsg);
break;
+ case PROP_JSONMESG:
+ pRes = (uchar*)msgGetJSONMESG(pMsg);
+ *pbMustBeFreed = 1;
+ break;
#ifdef USE_LIBUUID
case PROP_UUID:
getUUID(pMsg, &pRes, &bufLen);
@@ -2968,8 +3218,6 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
break;
case PROP_CEE_ALL_JSON:
if(pMsg->json == NULL) {
- if(*pbMustBeFreed == 1)
- free(pRes);
pRes = (uchar*) "{}";
bufLen = 2;
*pbMustBeFreed = 0;
@@ -2979,35 +3227,59 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
}
break;
case PROP_CEE:
- getCEEPropVal(pMsg, propName, &pRes, &bufLen, pbMustBeFreed);
+ case PROP_LOCAL_VAR:
+ case PROP_GLOBAL_VAR:
+ getJSONPropVal(pMsg, pProp, &pRes, &bufLen, pbMustBeFreed);
break;
case PROP_SYS_BOM:
- if(*pbMustBeFreed == 1)
- free(pRes);
pRes = (uchar*) "\xEF\xBB\xBF";
*pbMustBeFreed = 0;
break;
case PROP_SYS_UPTIME:
# ifndef HAVE_SYSINFO_UPTIME
- /* An alternative on some systems (eg Solaris) is to scan
- * /var/adm/utmpx for last boot time.
- */
+ /* An alternative on some systems (eg Solaris) is to scan
+ * /var/adm/utmpx for last boot time.
+ */
pRes = (uchar*) "UPTIME NOT available on this system";
*pbMustBeFreed = 0;
+
+# elif defined(__FreeBSD__)
+
+ {
+ struct timespec tp;
+
+ if((pRes = (uchar*) MALLOC(sizeof(uchar) * 32)) == NULL) {
+ RET_OUT_OF_MEMORY;
+ }
+
+ if(clock_gettime(CLOCK_UPTIME, &tp) == -1) {
+ free(pRes);
+ *pPropLen = sizeof("**SYSCALL FAILED**") - 1;
+ return(UCHAR_CONSTANT("**SYSCALL FAILED**"));
+ }
+
+ *pbMustBeFreed = 1;
+
+ snprintf((char*) pRes, sizeof(uchar) * 32, "%ld", tp.tv_sec);
+ }
+
# else
+
{
struct sysinfo s_info;
if((pRes = (uchar*) MALLOC(sizeof(uchar) * 32)) == NULL) {
RET_OUT_OF_MEMORY;
}
- *pbMustBeFreed = 1;
if(sysinfo(&s_info) < 0) {
+ free(pRes);
*pPropLen = sizeof("**SYSCALL FAILED**") - 1;
return(UCHAR_CONSTANT("**SYSCALL FAILED**"));
}
+ *pbMustBeFreed = 1;
+
snprintf((char*) pRes, sizeof(uchar) * 32, "%ld", s_info.uptime);
}
# endif
@@ -3016,7 +3288,7 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
/* there is no point in continuing, we may even otherwise render the
* error message unreadable. rgerhards, 2007-07-10
*/
- dbgprintf("invalid property id: '%d'\n", propid);
+ dbgprintf("invalid property id: '%d'\n", pProp->id);
*pbMustBeFreed = 0;
*pPropLen = sizeof("**INVALID PROPERTY NAME**") - 1;
return UCHAR_CONSTANT("**INVALID PROPERTY NAME**");
@@ -3075,7 +3347,7 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
/* we got our end pointer, now do the copy */
/* TODO: code copied from below, this is a candidate for a separate function */
iLen = pFldEnd - pFld + 1; /* the +1 is for an actual char, NOT \0! */
- pBufStart = pBuf = MALLOC((iLen + 1) * sizeof(char));
+ pBufStart = pBuf = MALLOC((iLen + 1) * sizeof(uchar));
if(pBuf == NULL) {
if(*pbMustBeFreed == 1)
free(pRes);
@@ -3253,7 +3525,7 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
if(iTo > bufLen) /* iTo is very large, if no to-position is set in the template! */
iTo = bufLen;
iLen = iTo - iFrom + 1; /* the +1 is for an actual char, NOT \0! */
- pBufStart = pBuf = MALLOC((iLen + 1) * sizeof(char));
+ pBufStart = pBuf = MALLOC((iLen + 1) * sizeof(uchar));
if(pBuf == NULL) {
if(*pbMustBeFreed == 1)
free(pRes);
@@ -3307,7 +3579,7 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
uchar *pBStart;
uchar *pB;
uchar *pSrc;
- pBStart = pB = MALLOC((bufLen + 1) * sizeof(char));
+ pBStart = pB = MALLOC((bufLen + 1) * sizeof(uchar));
if(pB == NULL) {
if(*pbMustBeFreed == 1)
free(pRes);
@@ -3612,9 +3884,13 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
bufLen = -1;
*pbMustBeFreed = 1;
} else if(pTpe->data.field.options.bJSON) {
- jsonEncode(&pRes, pbMustBeFreed, &bufLen);
+ jsonEncode(&pRes, pbMustBeFreed, &bufLen, RSTRUE);
} else if(pTpe->data.field.options.bJSONf) {
- jsonField(pTpe, &pRes, pbMustBeFreed, &bufLen);
+ jsonField(pTpe, &pRes, pbMustBeFreed, &bufLen, RSTRUE);
+ } else if(pTpe->data.field.options.bJSONr) {
+ jsonEncode(&pRes, pbMustBeFreed, &bufLen, RSFALSE);
+ } else if(pTpe->data.field.options.bJSONfr) {
+ jsonField(pTpe, &pRes, pbMustBeFreed, &bufLen, RSFALSE);
}
*pPropLen = (bufLen == -1) ? ustrlen(pRes) : bufLen;
@@ -3624,66 +3900,6 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
}
-/* The function returns a cee variable suitable for use with RainerScript.
- * Note: caller must free the returned string.
- * Note that we need to do a lot of conversions between es_str_t and cstr -- this will go away once
- * we have moved larger parts of rsyslog to es_str_t. Acceptable for the moment, especially as we intend
- * to rewrite the script engine as well!
- * rgerhards, 2010-12-03
- */
-es_str_t*
-msgGetCEEVarNew(msg_t *pMsg, char *name)
-{
- uchar *leaf;
- char *val;
- es_str_t *estr = NULL;
- struct json_object *json, *parent;
-
- ISOBJ_TYPE_assert(pMsg, msg);
-
- if(pMsg->json == NULL) {
- estr = es_newStr(1);
- goto done;
- }
- leaf = jsonPathGetLeaf((uchar*)name, strlen(name));
- if(jsonPathFindParent(pMsg, (uchar*)name, leaf, &parent, 1) != RS_RET_OK) {
- estr = es_newStr(1);
- goto done;
- }
- json = json_object_object_get(parent, (char*)leaf);
- val = (char*)json_object_get_string(json);
- estr = es_newStrFromCStr(val, strlen(val));
-done:
- return estr;
-}
-
-
-/* Return an es_str_t for given message property.
- */
-es_str_t*
-msgGetMsgVarNew(msg_t *pThis, uchar *name)
-{
- rs_size_t propLen;
- uchar *pszProp = NULL;
- propid_t propid;
- unsigned short bMustBeFreed = 0;
- es_str_t *estr;
-
- ISOBJ_TYPE_assert(pThis, msg);
-
- /* always call MsgGetProp() without a template specifier */
- /* TODO: optimize propNameToID() call -- rgerhards, 2009-06-26 */
- propNameStrToID(name, &propid);
- pszProp = (uchar*) MsgGetProp(pThis, NULL, propid, NULL, &propLen, &bMustBeFreed, NULL);
-
- estr = es_newStrFromCStr((char*)pszProp, propLen);
- if(bMustBeFreed)
- free(pszProp);
-
- return estr;
-}
-
-
/* This function can be used as a generic way to set properties.
* We have to handle a lot of legacy, so our return value is not always
* 100% correct (called functions do not always provide one, should
@@ -3734,7 +3950,7 @@ rsRetVal MsgSetProperty(msg_t *pThis, var_t *pProp)
prop.Destruct(&propRcvFrom);
} else if(isProp("pszHOSTNAME")) {
MsgSetHOSTNAME(pThis, rsCStrGetSzStrNoNULL(pProp->val.pStr), rsCStrLen(pProp->val.pStr));
- } else if(isProp("pCSStrucData")) {
+ } else if(isProp("pszStrucData")) {
MsgSetStructuredData(pThis, (char*) rsCStrGetSzStrNoNULL(pProp->val.pStr));
} else if(isProp("pCSAPPNAME")) {
MsgSetAPPNAME(pThis, (char*) rsCStrGetSzStrNoNULL(pProp->val.pStr));
@@ -3769,12 +3985,142 @@ finalize_it:
#undef isProp
+/* Set a single property based on the JSON object provided. The
+ * property name is extracted from the JSON object.
+ */
+static rsRetVal
+msgSetPropViaJSON(msg_t *__restrict__ const pMsg, const char *name, struct json_object *json)
+{
+ const char *psz;
+ int val;
+ prop_t *propFromHost = NULL;
+ prop_t *propRcvFromIP = NULL;
+ DEFiRet;
+
+ // TODO: think if we need to lock the message mutex. For some updates
+ // we probably need to!
+
+ /* note: json_object_get_string() manages the memory of the returned
+ * string. So we MUST NOT free it!
+ */
+ dbgprintf("DDDD: msgSetPropViaJSON key: '%s'\n", name);
+ if(!strcmp(name, "rawmsg")) {
+ psz = json_object_get_string(json);
+ MsgSetRawMsg(pMsg, psz, strlen(psz));
+ } else if(!strcmp(name, "msg")) {
+ psz = json_object_get_string(json);
+ MsgReplaceMSG(pMsg, (const uchar*)psz, strlen(psz));
+ } else if(!strcmp(name, "syslogtag")) {
+ psz = json_object_get_string(json);
+ MsgSetTAG(pMsg, (const uchar*)psz, strlen(psz));
+ } else if(!strcmp(name, "syslogfacility")) {
+ val = json_object_get_int(json);
+ if(val >= 0 && val <= 24)
+ pMsg->iFacility = val;
+ else
+ DBGPRINTF("mmexternal: invalid fac %d requested -- ignored\n", val);
+ } else if(!strcmp(name, "syslogseverity")) {
+ val = json_object_get_int(json);
+ if(val >= 0 && val <= 7)
+ pMsg->iSeverity = val;
+ else
+ DBGPRINTF("mmexternal: invalid fac %d requested -- ignored\n", val);
+ } else if(!strcmp(name, "procid")) {
+ psz = json_object_get_string(json);
+ MsgSetPROCID(pMsg, psz);
+ } else if(!strcmp(name, "msgid")) {
+ psz = json_object_get_string(json);
+ MsgSetMSGID(pMsg, psz);
+ } else if(!strcmp(name, "structured-data")) {
+ psz = json_object_get_string(json);
+ MsgSetStructuredData(pMsg, psz);
+ } else if(!strcmp(name, "hostname") || !strcmp(name, "source")) {
+ psz = json_object_get_string(json);
+ MsgSetHOSTNAME(pMsg, (const uchar*)psz, strlen(psz));
+ } else if(!strcmp(name, "fromhost")) {
+ psz = json_object_get_string(json);
+ MsgSetRcvFromStr(pMsg, (const uchar*) psz, 0, &propFromHost);
+ } else if(!strcmp(name, "fromhost-ip")) {
+ psz = json_object_get_string(json);
+ MsgSetRcvFromIPStr(pMsg, (const uchar*)psz, strlen(psz), &propRcvFromIP);
+ } else if(!strcmp(name, "$!")) {
+ msgAddJSON(pMsg, (uchar*)"!", json);
+ } else {
+ /* we ignore unknown properties */
+ DBGPRINTF("msgSetPropViaJSON: unkonwn property ignored: %s\n",
+ name);
+ }
+ RETiRet;
+}
+
+
+/* set message properties based on JSON string. This function does it all,
+ * including parsing the JSON string. If an error is detected, the operation
+ * is aborted at the time of error. Any modifications made before the
+ * error ocurs are still PERSISTED.
+ * This function is meant to support the external message modifiction module
+ * interface. As such, replacing properties is expressively permited. Note that
+ * properties which were derived from the message during parsing are NOT
+ * updated if the underlying (raw)msg property is changed.
+ */
+rsRetVal
+MsgSetPropsViaJSON(msg_t *__restrict__ const pMsg, const uchar *__restrict__ const jsonstr)
+{
+ struct json_tokener *tokener = NULL;
+ struct json_object *json;
+ const char *errMsg;
+ DEFiRet;
+
+ DBGPRINTF("DDDDDD: JSON string for message mod: '%s'\n", jsonstr);
+ if(!strcmp((char*)jsonstr, "{}")) /* shortcut for a common case */
+ FINALIZE;
+
+ tokener = json_tokener_new();
+
+ json = json_tokener_parse_ex(tokener, (char*)jsonstr, ustrlen(jsonstr));
+ if(Debug) {
+ errMsg = NULL;
+ if(json == NULL) {
+ enum json_tokener_error err;
+
+ err = tokener->err;
+ if(err != json_tokener_continue)
+# if HAVE_JSON_TOKENER_ERROR_DESC
+ errMsg = json_tokener_error_desc(err);
+# else
+ errMsg = json_tokener_errors[err];
+# endif
+ else
+ errMsg = "Unterminated input";
+ } else if(!json_object_is_type(json, json_type_object))
+ errMsg = "JSON value is not an object";
+ if(errMsg != NULL) {
+ DBGPRINTF("MsgSetPropsViaJSON: Error parsing JSON '%s': %s\n",
+ jsonstr, errMsg);
+ }
+ }
+ if(json == NULL || !json_object_is_type(json, json_type_object)) {
+ ABORT_FINALIZE(RS_RET_JSON_PARSE_ERR);
+ }
+
+ json_object_object_foreach(json, name, val) {
+ msgSetPropViaJSON(pMsg, name, val);
+ }
+ json_object_put(json);
+
+finalize_it:
+ if(tokener != NULL)
+ json_tokener_free(tokener);
+ RETiRet;
+}
+
+
/* get the severity - this is an entry point that
* satisfies the base object class getSeverity semantics.
* rgerhards, 2008-01-14
*/
rsRetVal
-MsgGetSeverity(msg_t *pMsg, int *piSeverity)
+MsgGetSeverity(msg_t * const pMsg, int *piSeverity)
{
*piSeverity = pMsg->iSeverity;
return RS_RET_OK;
@@ -3785,16 +4131,22 @@ static uchar *
jsonPathGetLeaf(uchar *name, int lenName)
{
int i;
- for(i = lenName ; name[i] != '!' && i >= 0 ; --i)
- /* just skip */;
- if(name[i] == '!')
+ for(i = lenName ; i >= 0 ; --i)
+ if(i == 0) {
+ if(name[0] == '!' || name[0] == '.' || name[0] == '/')
+ break;
+ } else {
+ if(name[i] == '!')
+ break;
+ }
+ if(name[i] == '!' || name[i] == '.' || name[i] == '/')
++i;
return name + i;
}
static rsRetVal
-jsonPathFindNext(struct json_object *root, uchar **name, uchar *leaf,
+jsonPathFindNext(struct json_object *root, uchar *namestart, uchar **name, uchar *leaf,
struct json_object **found, int bCreate)
{
uchar namebuf[1024];
@@ -3803,13 +4155,12 @@ jsonPathFindNext(struct json_object *root, uchar **name, uchar *leaf,
uchar *p = *name;
DEFiRet;
- if(*p == '!')
+ if(*p == '!' || (*name == namestart && (*p == '.' || *p == '/')))
++p;
- for(i = 0 ; *p && *p != '!' && p != leaf && i < sizeof(namebuf)-1 ; ++i, ++p)
+ for(i = 0 ; *p && !(p == namestart && (*p == '.' || *p == '/')) && *p != '!' && p != leaf && i < sizeof(namebuf)-1 ; ++i, ++p)
namebuf[i] = *p;
if(i > 0) {
namebuf[i] = '\0';
- dbgprintf("AAAA: next JSONPath elt: '%s'\n", namebuf);
json = json_object_object_get(root, (char*)namebuf);
} else
json = root;
@@ -3829,12 +4180,14 @@ finalize_it:
}
static rsRetVal
-jsonPathFindParent(msg_t *pM, uchar *name, uchar *leaf, struct json_object **parent, int bCreate)
+jsonPathFindParent(struct json_object *jroot, uchar *name, uchar *leaf, struct json_object **parent, int bCreate)
{
+ uchar *namestart;
DEFiRet;
- *parent = pM->json;
+ namestart = name;
+ *parent = jroot;
while(name < leaf-1) {
- jsonPathFindNext(*parent, &name, leaf, parent, bCreate);
+ jsonPathFindNext(*parent, namestart, &name, leaf, parent, bCreate);
}
RETiRet;
}
@@ -3847,7 +4200,6 @@ jsonMerge(struct json_object *existing, struct json_object *json)
struct json_object_iter it;
json_object_object_foreachC(json, it) {
-DBGPRINTF("AAAA jsonMerge adds '%s'\n", it.key);
json_object_object_add(existing, it.key,
json_object_get(it.val));
}
@@ -3861,63 +4213,75 @@ DBGPRINTF("AAAA jsonMerge adds '%s'\n", it.key);
/* find a JSON structure element (field or container doesn't matter). */
rsRetVal
-jsonFind(msg_t *pM, es_str_t *propName, struct json_object **jsonres)
+jsonFind(struct json_object *jroot, msgPropDescr_t *pProp, struct json_object **jsonres)
{
- uchar *name = NULL;
uchar *leaf;
struct json_object *parent;
struct json_object *field;
DEFiRet;
- if(pM->json == NULL) {
+ if(jroot == NULL) {
field = NULL;
goto finalize_it;
}
- if(!es_strbufcmp(propName, (uchar*)"!", 1)) {
- field = pM->json;
+ if(!strcmp((char*)pProp->name, "!")) {
+ field = jroot;
} else {
- name = (uchar*)es_str2cstr(propName, NULL);
- leaf = jsonPathGetLeaf(name, ustrlen(name));
- CHKiRet(jsonPathFindParent(pM, name, leaf, &parent, 0));
+ leaf = jsonPathGetLeaf(pProp->name, pProp->nameLen);
+ CHKiRet(jsonPathFindParent(jroot, pProp->name, leaf, &parent, 0));
field = json_object_object_get(parent, (char*)leaf);
}
*jsonres = field;
finalize_it:
- free(name);
RETiRet;
}
rsRetVal
-msgAddJSON(msg_t *pM, uchar *name, struct json_object *json)
+msgAddJSON(msg_t * const pM, uchar *name, struct json_object *json)
{
/* TODO: error checks! This is a quick&dirty PoC! */
+ struct json_object **pjroot;
struct json_object *parent, *leafnode;
uchar *leaf;
DEFiRet;
MsgLock(pM);
- if(name[0] == '!' && name[1] == '\0') {
- if(pM->json == NULL)
- pM->json = json;
+ if(name[0] == '!') {
+ pjroot = &pM->json;
+ } else if(name[0] == '.') {
+ pjroot = &pM->localvars;
+ } else { /* globl var */
+ pthread_rwlock_wrlock(&glblVars_rwlock);
+ pjroot = &global_var_root;
+ }
+
+ if(name[1] == '\0') { /* full tree? */
+ if(*pjroot == NULL)
+ *pjroot = json;
else
- CHKiRet(jsonMerge(pM->json, json));
+ CHKiRet(jsonMerge(*pjroot, json));
} else {
- if(pM->json == NULL) {
+ if(*pjroot == NULL) {
/* now we need a root obj */
- pM->json = json_object_new_object();
+ *pjroot = json_object_new_object();
}
leaf = jsonPathGetLeaf(name, ustrlen(name));
- CHKiRet(jsonPathFindParent(pM, name, leaf, &parent, 1));
+ CHKiRet(jsonPathFindParent(*pjroot, name, leaf, &parent, 1));
+ if (json_object_get_type(parent) != json_type_object) {
+ DBGPRINTF("msgAddJSON: not a container in json path,"
+ "name is '%s'\n", name);
+ json_object_put(json);
+ ABORT_FINALIZE(RS_RET_INVLD_SETOP);
+ }
leafnode = json_object_object_get(parent, (char*)leaf);
if(leafnode == NULL) {
json_object_object_add(parent, (char*)leaf, json);
} else {
if(json_object_get_type(json) == json_type_object) {
- CHKiRet(jsonMerge(pM->json, json));
+ CHKiRet(jsonMerge(*pjroot, json));
} else {
-//dbgprintf("AAAA: leafnode already exists, type is %d, update with %d\n", (int)json_object_get_type(leafnode), (int)json_object_get_type(json));
/* TODO: improve the code below, however, the current
* state is not really bad */
if(json_object_get_type(leafnode) == json_type_object) {
@@ -3941,35 +4305,52 @@ msgAddJSON(msg_t *pM, uchar *name, struct json_object *json)
}
finalize_it:
+ if(name[0] == '/')
+ pthread_rwlock_unlock(&glblVars_rwlock);
MsgUnlock(pM);
RETiRet;
}
+
rsRetVal
-msgDelJSON(msg_t *pM, uchar *name)
+msgDelJSON(msg_t * const pM, uchar *name)
{
+ struct json_object **jroot;
struct json_object *parent, *leafnode;
uchar *leaf;
DEFiRet;
-dbgprintf("AAAA: unset variable '%s'\n", name);
MsgLock(pM);
- if(name[0] == '!' && name[1] == '\0') {
- /* strange, but I think we should permit this. After all,
+
+ if(name[0] == '!') {
+ jroot = &pM->json;
+ } else if(name[0] == '.') {
+ jroot = &pM->localvars;
+ } else { /* globl var */
+ pthread_rwlock_wrlock(&glblVars_rwlock);
+ jroot = &global_var_root;
+ }
+ if(jroot == NULL) {
+ DBGPRINTF("msgDelJSONVar; jroot empty in unset for property %s\n",
+ name);
+ FINALIZE;
+ }
+
+ if(name[1] == '\0') {
+ /* full tree! Strange, but I think we should permit this. After all,
* we trust rsyslog.conf to be written by the admin.
*/
DBGPRINTF("unsetting JSON root object\n");
- json_object_put(pM->json);
- pM->json = NULL;
+ json_object_put(*jroot);
+ *jroot = NULL;
} else {
- if(pM->json == NULL) {
+ if(*jroot == NULL) {
/* now we need a root obj */
- pM->json = json_object_new_object();
+ *jroot = json_object_new_object();
}
leaf = jsonPathGetLeaf(name, ustrlen(name));
- CHKiRet(jsonPathFindParent(pM, name, leaf, &parent, 1));
+ CHKiRet(jsonPathFindParent(*jroot, name, leaf, &parent, 1));
leafnode = json_object_object_get(parent, (char*)leaf);
-DBGPRINTF("AAAA: unset found JSON value path '%s', " "leaf '%s', leafnode %p\n", name, leaf, leafnode);
if(leafnode == NULL) {
DBGPRINTF("unset JSON: could not find '%s'\n", name);
ABORT_FINALIZE(RS_RET_JNAME_NOTFOUND);
@@ -3982,6 +4363,8 @@ DBGPRINTF("AAAA: unset found JSON value path '%s', " "leaf '%s', leafnode %p\n",
}
finalize_it:
+ if(name[0] == '/')
+ pthread_rwlock_unlock(&glblVars_rwlock);
MsgUnlock(pM);
RETiRet;
}
@@ -4003,7 +4386,11 @@ jsonDeepCopy(struct json_object *src)
dst = json_object_new_double(json_object_get_double(src));
break;
case json_type_int:
+#ifdef HAVE_JSON_OBJECT_NEW_INT64
+ dst = json_object_new_int64(json_object_get_int64(src));
+#else /* HAVE_JSON_OBJECT_NEW_INT64 */
dst = json_object_new_int(json_object_get_int(src));
+#endif /* HAVE_JSON_OBJECT_NEW_INT64 */
break;
case json_type_string:
dst = json_object_new_string(json_object_get_string(src));
@@ -4034,7 +4421,7 @@ done: return dst;
rsRetVal
-msgSetJSONFromVar(msg_t *pMsg, uchar *varname, struct var *v)
+msgSetJSONFromVar(msg_t * const pMsg, uchar *varname, struct var *v)
{
struct json_object *json = NULL;
char *cstr;
@@ -4046,7 +4433,11 @@ msgSetJSONFromVar(msg_t *pMsg, uchar *varname, struct var *v)
free(cstr);
break;
case 'N':/* number (integer) */
+#ifdef HAVE_JSON_OBJECT_NEW_INT64
+ json = json_object_new_int64(v->d.n);
+#else /* HAVE_JSON_OBJECT_NEW_INT64 */
json = json_object_new_int((int) v->d.n);
+#endif /* HAVE_JSON_OBJECT_NEW_INT64 */
break;
case 'J':/* native JSON */
json = jsonDeepCopy(v->d.json);
@@ -4055,11 +4446,76 @@ msgSetJSONFromVar(msg_t *pMsg, uchar *varname, struct var *v)
v->datatype);
ABORT_FINALIZE(RS_RET_ERR);
}
- msgAddJSON(pMsg, varname+1, json);
+
+ msgAddJSON(pMsg, varname, json);
finalize_it:
RETiRet;
}
+rsRetVal
+MsgAddToStructuredData(msg_t * const pMsg, uchar *toadd, rs_size_t len)
+{
+ uchar *newptr;
+ rs_size_t newlen;
+ DEFiRet;
+ newlen = (pMsg->pszStrucData[0] == '-') ? len : pMsg->lenStrucData + len;
+ CHKmalloc(newptr = (uchar*) realloc(pMsg->pszStrucData, newlen+1));
+ pMsg->pszStrucData = newptr;
+ if(pMsg->pszStrucData[0] == '-') { /* empty? */
+ memcpy(pMsg->pszStrucData, toadd, len);
+ } else {
+ memcpy(pMsg->pszStrucData+pMsg->lenStrucData, toadd, len);
+ }
+ pMsg->pszStrucData[newlen] = '\0';
+ pMsg->lenStrucData = newlen;
+finalize_it:
+ RETiRet;
+}
+
+
+/* Fill a message propert description. Space must already be alloced
+ * by the caller. This is for efficiency, as we expect this to happen
+ * as part of a larger structure alloc.
+ * Note that CEE/LOCAL_VAR properties can come in either as
+ * "$!xx"/"$.xx" or "!xx"/".xx" - we will unify them here.
+ */
+rsRetVal
+msgPropDescrFill(msgPropDescr_t *pProp, uchar *name, int nameLen)
+{
+ propid_t id;
+ int offs;
+ DEFiRet;
+ if(propNameToID(name, &id) != RS_RET_OK) {
+ parser_errmsg("invalid property '%s'", name);
+ ABORT_FINALIZE(RS_RET_INVLD_PROP);
+ }
+ if(id == PROP_CEE || id == PROP_LOCAL_VAR || id == PROP_GLOBAL_VAR) {
+ /* in these cases, we need the field name for later processing */
+ /* normalize name: remove $ if present */
+ offs = (name[0] == '$') ? 1 : 0;
+ pProp->name = ustrdup(name + offs);
+ pProp->nameLen = nameLen - offs;
+ /* we patch the root name, so that support functions do not need to
+ * check for different root chars. */
+ pProp->name[0] = '!';
+ }
+ pProp->id = id;
+finalize_it:
+ RETiRet;
+}
+
+void
+msgPropDescrDestruct(msgPropDescr_t *pProp)
+{
+ if(pProp != NULL) {
+ if(pProp->id == PROP_CEE ||
+ pProp->id == PROP_LOCAL_VAR ||
+ pProp->id == PROP_GLOBAL_VAR)
+ free(pProp->name);
+ }
+}
+
+
/* dummy */
rsRetVal msgQueryInterface(void) { return RS_RET_NOT_IMPLEMENTED; }
@@ -4068,6 +4524,8 @@ rsRetVal msgQueryInterface(void) { return RS_RET_NOT_IMPLEMENTED; }
* rgerhards, 2008-01-04
*/
BEGINObjClassInit(msg, 1, OBJ_IS_CORE_MODULE)
+ pthread_rwlock_init(&glblVars_rwlock, NULL);
+
/* request objects we use */
CHKiRet(objUse(datetime, CORE_COMPONENT));
CHKiRet(objUse(glbl, CORE_COMPONENT));