diff options
Diffstat (limited to 'runtime/msg.c')
-rw-r--r-- | runtime/msg.c | 225 |
1 files changed, 175 insertions, 50 deletions
diff --git a/runtime/msg.c b/runtime/msg.c index 67d957d1..c7cd9406 100644 --- a/runtime/msg.c +++ b/runtime/msg.c @@ -66,6 +66,12 @@ #include "var.h" #include "rsconf.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 DEFobjCurrIf(datetime) @@ -317,9 +323,10 @@ static pthread_mutex_t mutTrimCtr; /* mutex to handle malloc trim */ /* 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 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); +static rsRetVal msgAddJSONObj(msg_t *pM, uchar *name, struct json_object *json, struct json_object **pjroot); /* the locking and unlocking implementations: */ @@ -536,11 +543,16 @@ propNameStrToID(uchar *pName, propid_t *pPropID) *pPropID = PROP_CEE_ALL_JSON; } else if(!strncmp((char*) pName, "$!", 2)) { *pPropID = PROP_CEE; + } else if(!strncmp((char*) pName, "$.", 2)) { + *pPropID = PROP_LOCAL_VAR; + } else if(!strncmp((char*) pName, "$/", 2)) { + *pPropID = PROP_GLOBAL_VAR; } else if(!strcmp((char*) pName, "$bom")) { *pPropID = PROP_SYS_BOM; } else if(!strcmp((char*) pName, "$uptime")) { *pPropID = PROP_SYS_UPTIME; } else { + DBGPRINTF("PROP_INVALID for name '%s'\n", pName); *pPropID = PROP_INVALID; iRet = RS_RET_VAR_NOT_FOUND; } @@ -634,6 +646,10 @@ 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_GLOBAL_VAR: + return UCHAR_CONSTANT("*GLOBAL_VARIABLE*"); case PROP_CEE_ALL_JSON: return UCHAR_CONSTANT("$!all-json"); case PROP_SYS_BOM: @@ -708,6 +724,7 @@ static inline rsRetVal msgBaseConstruct(msg_t **ppThis) pM->rcvFrom.pRcvFrom = NULL; pM->pRuleset = NULL; pM->json = NULL; + pM->localvars = NULL; memset(&pM->tRcvdAt, 0, sizeof(pM->tRcvdAt)); memset(&pM->tTIMESTAMP, 0, sizeof(pM->tTIMESTAMP)); pM->TAG.pszTAG = NULL; @@ -853,6 +870,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 @@ -1002,6 +1021,8 @@ msg_t* MsgDup(msg_t* pOld) 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. @@ -1060,6 +1081,10 @@ static rsRetVal MsgSerialize(msg_t *pThis, strm_t *pStrm) 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); @@ -1202,6 +1227,14 @@ MsgDeserialize(msg_t *pMsg, strm_t *pStrm) reinitVar(pVar); CHKiRet(objDeserializeProperty(pVar, pStrm)); } + 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("pCSStrucData")) { MsgSetStructuredData(pMsg, (char*) rsCStrGetSzStrNoNULL(pVar->val.pStr)); reinitVar(pVar); @@ -2510,9 +2543,9 @@ static uchar *getNOW(eNOWType eNow, struct syslogTime *t) #undef tmpBUFSIZE /* clean up */ -/* Get a CEE-Property as string value*/ -rsRetVal -getCEEPropVal(msg_t *pM, es_str_t *propName, uchar **pRes, rs_size_t *buflen, unsigned short *pbMustBeFreed) +/* Get a JSON-Property as string value (used for various types of JSON-based vars) */ +static rsRetVal +getJSONPropVal(struct json_object *jroot, es_str_t *propName, uchar **pRes, rs_size_t *buflen, unsigned short *pbMustBeFreed) { uchar *name = NULL; uchar *leaf; @@ -2524,14 +2557,14 @@ getCEEPropVal(msg_t *pM, es_str_t *propName, uchar **pRes, rs_size_t *buflen, un free(*pRes); *pRes = NULL; // TODO: mutex? - if(pM->json == NULL) goto finalize_it; + if(jroot == NULL) goto finalize_it; if(!es_strbufcmp(propName, (uchar*)"!", 1)) { - field = pM->json; + field = jroot; } else { name = (uchar*)es_str2cstr(propName, NULL); leaf = jsonPathGetLeaf(name, ustrlen(name)); - CHKiRet(jsonPathFindParent(pM, name, leaf, &parent, 1)); + CHKiRet(jsonPathFindParent(jroot, name, leaf, &parent, 1)); field = json_object_object_get(parent, (char*)leaf); } if(field != NULL) { @@ -2550,11 +2583,32 @@ finalize_it: RETiRet; } +rsRetVal +getCEEPropVal(msg_t *pM, es_str_t *propName, uchar **pRes, rs_size_t *buflen, unsigned short *pbMustBeFreed) +{ + return getJSONPropVal(pM->json, propName, pRes, buflen, pbMustBeFreed); +} -/* Get a CEE-Property as native json object - */ rsRetVal -msgGetCEEPropJSON(msg_t *pM, es_str_t *propName, struct json_object **pjson) +getLocalVarPropVal(msg_t *pM, es_str_t *propName, uchar **pRes, rs_size_t *buflen, unsigned short *pbMustBeFreed) +{ + return getJSONPropVal(pM->localvars, propName, pRes, buflen, pbMustBeFreed); +} + +rsRetVal +getGlobalVarPropVal( es_str_t *propName, uchar **pRes, rs_size_t *buflen, unsigned short *pbMustBeFreed) +{ + DEFiRet; + pthread_rwlock_rdlock(&glblVars_rwlock); + iRet = getJSONPropVal(global_var_root, propName, pRes, buflen, pbMustBeFreed); + pthread_rwlock_unlock(&glblVars_rwlock); + RETiRet; +} + + +/* Get a JSON-based-variable as native json object */ +rsRetVal +msgGetJSONPropJSON(struct json_object *jroot, es_str_t *propName, struct json_object **pjson) { uchar *name = NULL; uchar *leaf; @@ -2562,17 +2616,17 @@ msgGetCEEPropJSON(msg_t *pM, es_str_t *propName, struct json_object **pjson) DEFiRet; // TODO: mutex? - if(pM->json == NULL) { + if(jroot == NULL) { ABORT_FINALIZE(RS_RET_NOT_FOUND); } if(!es_strbufcmp(propName, (uchar*)"!", 1)) { - *pjson = pM->json; + *pjson = jroot; FINALIZE; } name = (uchar*)es_str2cstr(propName, NULL); leaf = jsonPathGetLeaf(name, ustrlen(name)); - CHKiRet(jsonPathFindParent(pM, name, leaf, &parent, 1)); + CHKiRet(jsonPathFindParent(jroot, name, leaf, &parent, 1)); *pjson = json_object_object_get(parent, (char*)leaf); if(*pjson == NULL) { ABORT_FINALIZE(RS_RET_NOT_FOUND); @@ -2583,6 +2637,27 @@ finalize_it: RETiRet; } +rsRetVal +msgGetCEEPropJSON(msg_t *pM, es_str_t *propName, struct json_object **pjson) +{ + return msgGetJSONPropJSON(pM->json, propName, pjson); +} + +rsRetVal +msgGetLocalVarJSON(msg_t *pM, es_str_t *propName, struct json_object **pjson) +{ + return msgGetJSONPropJSON(pM->localvars, propName, pjson); +} + +rsRetVal +msgGetGlobalVarJSON(es_str_t *propName, struct json_object **pjson) +{ + DEFiRet; + pthread_rwlock_rdlock(&glblVars_rwlock); + iRet = msgGetJSONPropJSON(global_var_root, propName, pjson); + 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 @@ -2981,6 +3056,12 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe, case PROP_CEE: getCEEPropVal(pMsg, propName, &pRes, &bufLen, pbMustBeFreed); break; + case PROP_LOCAL_VAR: + getLocalVarPropVal(pMsg, propName, &pRes, &bufLen, pbMustBeFreed); + break; + case PROP_GLOBAL_VAR: + getGlobalVarPropVal(propName, &pRes, &bufLen, pbMustBeFreed); + break; case PROP_SYS_BOM: if(*pbMustBeFreed == 1) free(pRes); @@ -3648,15 +3729,15 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe, } -/* The function returns a cee variable suitable for use with RainerScript. +/* The function returns a json 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) +static es_str_t* +msgGetJSONVarNew(msg_t *pMsg, struct json_object *jroot, char *name) { uchar *leaf; char *val; @@ -3665,12 +3746,12 @@ msgGetCEEVarNew(msg_t *pMsg, char *name) ISOBJ_TYPE_assert(pMsg, msg); - if(pMsg->json == NULL) { + if(jroot == NULL) { estr = es_newStr(1); goto done; } leaf = jsonPathGetLeaf((uchar*)name, strlen(name)); - if(jsonPathFindParent(pMsg, (uchar*)name, leaf, &parent, 1) != RS_RET_OK) { + if(jsonPathFindParent(jroot, (uchar*)name, leaf, &parent, 1) != RS_RET_OK) { estr = es_newStr(1); goto done; } @@ -3681,6 +3762,17 @@ done: return estr; } +es_str_t* +msgGetCEEVarNew(msg_t *pMsg, char *name) +{ + return msgGetJSONVarNew(pMsg, pMsg->json, name); +} + +es_str_t* +msgGetLocalVarNew(msg_t *pMsg, char *name) +{ + return msgGetJSONVarNew(pMsg, pMsg->localvars, name); +} /* Return an es_str_t for given message property. */ @@ -3692,13 +3784,16 @@ msgGetMsgVarNew(msg_t *pThis, uchar *name) propid_t propid; unsigned short bMustBeFreed = 0; es_str_t *estr; + es_str_t *propName; 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); + propName = es_newStrFromCStr((char*)name+1, ustrlen(name)-1); // TODO: optimize! + pszProp = (uchar*) MsgGetProp(pThis, NULL, propid, propName, &propLen, &bMustBeFreed, NULL); + es_deleteStr(propName); estr = es_newStrFromCStr((char*)pszProp, propLen); if(bMustBeFreed) @@ -3809,16 +3904,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]; @@ -3827,9 +3928,9 @@ 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'; @@ -3853,12 +3954,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; } @@ -3885,7 +3988,7 @@ 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, es_str_t *propName, struct json_object **jsonres) { uchar *name = NULL; uchar *leaf; @@ -3893,17 +3996,17 @@ jsonFind(msg_t *pM, es_str_t *propName, struct json_object **jsonres) 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; + field = jroot; } else { name = (uchar*)es_str2cstr(propName, NULL); leaf = jsonPathGetLeaf(name, ustrlen(name)); - CHKiRet(jsonPathFindParent(pM, name, leaf, &parent, 0)); + CHKiRet(jsonPathFindParent(jroot, name, leaf, &parent, 0)); field = json_object_object_get(parent, (char*)leaf); } *jsonres = field; @@ -3913,8 +4016,8 @@ finalize_it: RETiRet; } -rsRetVal -msgAddJSON(msg_t *pM, uchar *name, struct json_object *json) +static rsRetVal +msgAddJSONObj(msg_t *pM, uchar *name, struct json_object *json, struct json_object **pjroot) { /* TODO: error checks! This is a quick&dirty PoC! */ struct json_object *parent, *leafnode; @@ -3922,24 +4025,24 @@ msgAddJSON(msg_t *pM, uchar *name, struct json_object *json) DEFiRet; MsgLock(pM); - if(name[0] == '!' && name[1] == '\0') { - if(pM->json == NULL) - pM->json = json; + if((name[0] == '!' || name[0] == '.' || name[0] == '/') && name[1] == '\0') { + 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)); 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 @@ -3970,7 +4073,12 @@ finalize_it: } rsRetVal -msgDelJSON(msg_t *pM, uchar *name) +msgAddJSON(msg_t *pM, uchar *name, struct json_object *json) { + return msgAddJSONObj(pM, name, json, &pM->json); +} + +rsRetVal +msgDelJSONVar(msg_t *pM, struct json_object **jroot, uchar *name) { struct json_object *parent, *leafnode; uchar *leaf; @@ -3978,20 +4086,20 @@ msgDelJSON(msg_t *pM, uchar *name) dbgprintf("AAAA: unset variable '%s'\n", name); MsgLock(pM); - if(name[0] == '!' && name[1] == '\0') { + if((name[0] == '!' || name[0] == '.' || name[0] == '/') && name[1] == '\0') { /* 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) { @@ -4010,6 +4118,12 @@ finalize_it: RETiRet; } +rsRetVal +msgDelJSON(msg_t *pM, uchar *name) +{ + return msgDelJSONVar(pM, &pM->json, name); +} + static struct json_object * jsonDeepCopy(struct json_object *src) { @@ -4079,7 +4193,16 @@ msgSetJSONFromVar(msg_t *pMsg, uchar *varname, struct var *v) v->datatype); ABORT_FINALIZE(RS_RET_ERR); } - msgAddJSON(pMsg, varname+1, json); + /* we always know strlen(varname) > 2 */ + if(varname[1] == '!') + msgAddJSONObj(pMsg, varname+1, json, &pMsg->json); + else if(varname[1] == '.') + msgAddJSONObj(pMsg, varname+1, json, &pMsg->localvars); + else { /* global - '/' */ + pthread_rwlock_wrlock(&glblVars_rwlock); + msgAddJSONObj(pMsg, varname+1, json, &global_var_root); + pthread_rwlock_unlock(&glblVars_rwlock); + } finalize_it: RETiRet; } @@ -4092,6 +4215,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)); |