From a7eb97b930bbbd3133f336a6f2ccbfb55eebbcfb Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 29 Feb 2008 16:02:07 +0000 Subject: - added "debug" command to debug environment settings - changed the object/interface system to use a new way of calling, giving up the numerical object ID. This was necessary as we needed more extensibility for third-party modules (which don't play at all with the previous fixed object ID). This is stage work for the object loader. Please note that I needed to change the object (de)serializer, I can't outrule that I have introduced bugs there. --- conf.c | 13 ++- ctok.c | 6 +- ctok_token.c | 4 +- debug.c | 9 ++- expr.c | 10 +-- msg.c | 5 +- obj-types.h | 67 +++++++--------- obj.c | 255 ++++++++++++++++++++++++++++++++++++++++++++++------------- obj.h | 12 +-- queue.c | 12 ++- rsyslog.h | 2 + stream.c | 20 +++++ stream.h | 6 ++ syslogd.c | 15 ++-- sysvar.c | 4 +- var.c | 2 +- vm.c | 8 +- vmop.c | 4 +- vmprg.c | 4 +- vmstk.c | 4 +- wti.c | 4 + wtp.c | 3 + 22 files changed, 330 insertions(+), 139 deletions(-) diff --git a/conf.c b/conf.c index 1229f1c4..9ac85d34 100644 --- a/conf.c +++ b/conf.c @@ -55,6 +55,7 @@ #include "srUtils.h" /* static data */ +DEFobjCurrIf(obj) DEFobjCurrIf(expr) DEFobjCurrIf(ctok) #include "vm.h" @@ -1174,15 +1175,19 @@ cfline(uchar *line, selector_t **pfCurr) } +/* dummy */ +//static rsRetVal confQueryInterface(void) { return RS_RET_NOT_IMPLEMENTED; } + /* "mimic" a real object - we are currently not one... */ rsRetVal confClassInit(void) { DEFiRet; /* request objects we use */ - CHKiRet(objUse(expr)); - CHKiRet(objUse(ctok)); - CHKiRet(objUse(vm)); // TODO: remove, testing aid! rgerhards, 2008-02-25 - CHKiRet(objUse(var)); // TODO: remove, testing aid! rgerhards, 2008-02-25 + CHKiRet(objGetObjInterface(&obj)); /* this provides the root pointer for all other queries */ + CHKiRet(objUse(expr, CORE_COMPONENT)); + CHKiRet(objUse(ctok, CORE_COMPONENT)); + CHKiRet(objUse(vm, CORE_COMPONENT)); // TODO: remove, testing aid! rgerhards, 2008-02-25 + CHKiRet(objUse(var, CORE_COMPONENT)); // TODO: remove, testing aid! rgerhards, 2008-02-25 finalize_it: RETiRet; diff --git a/ctok.c b/ctok.c index 867a448f..aaffed3b 100644 --- a/ctok.c +++ b/ctok.c @@ -573,7 +573,7 @@ CODESTARTobjQueryInterface(ctok) * work here (if we can support an older interface version - that, * of course, also affects the "if" above). */ - pIf->oID = OBJctok; + //xxxpIf->oID = OBJctok; pIf->Construct = ctokConstruct; pIf->ConstructFinalize = ctokConstructFinalize; @@ -589,8 +589,8 @@ ENDobjQueryInterface(ctok) BEGINObjClassInit(ctok, 1, OBJ_IS_CORE_MODULE) /* class, version */ /* request objects we use */ - CHKiRet(objUse(ctok_token)); - CHKiRet(objUse(var)); + CHKiRet(objUse(ctok_token, CORE_COMPONENT)); + CHKiRet(objUse(var, CORE_COMPONENT)); OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, ctokConstructFinalize); ENDObjClassInit(ctok) diff --git a/ctok_token.c b/ctok_token.c index fa21d12c..09200c0f 100644 --- a/ctok_token.c +++ b/ctok_token.c @@ -108,7 +108,7 @@ CODESTARTobjQueryInterface(ctok_token) * work here (if we can support an older interface version - that, * of course, also affects the "if" above). */ - pIf->oID = OBJctok_token; + //xxxpIf->oID = OBJctok_token; pIf->Construct = ctok_tokenConstruct; pIf->ConstructFinalize = ctok_tokenConstructFinalize; @@ -121,7 +121,7 @@ ENDobjQueryInterface(ctok_token) BEGINObjClassInit(ctok_token, 1, OBJ_IS_CORE_MODULE) /* class, version */ /* request objects we use */ - CHKiRet(objUse(var)); + CHKiRet(objUse(var, CORE_COMPONENT)); OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, ctok_tokenConstructFinalize); ENDObjClassInit(ctok_token) diff --git a/debug.c b/debug.c index a13f7e61..d1e037f0 100644 --- a/debug.c +++ b/debug.c @@ -1152,6 +1152,12 @@ dbgGetRuntimeOptions(void) "filetrace=file (may be provided multiple times)\n" "\nSee debug.html in your doc set or http://www.rsyslog.com for details\n"); exit(1); + } else if(!strcasecmp((char*)optname, "debug")) { + /* this is earlier in the process than the -d option, as such it + * allows us to spit out debug messages from the very beginning. + */ + Debug = 1; + debugging_on = 1; } else if(!strcasecmp((char*)optname, "logfuncflow")) { bLogFuncFlow = 1; } else if(!strcasecmp((char*)optname, "logallocfree")) { @@ -1176,9 +1182,8 @@ dbgGetRuntimeOptions(void) dbgPrintNameAdd(optval, &printNameFileRoot); } } else { - fprintf(stderr, "Error: invalid debug option '%s', value '%s'\n", + fprintf(stderr, "Error: invalid debug option '%s', value '%s' - ignored\n", optval, optname); - exit(1); } } } diff --git a/expr.c b/expr.c index a6b24c88..e6f4ef23 100644 --- a/expr.c +++ b/expr.c @@ -392,7 +392,7 @@ CODESTARTobjQueryInterface(expr) * work here (if we can support an older interface version - that, * of course, also affects the "if" above). */ - pIf->oID = OBJexpr; + //xxxpIf->oID = OBJexpr; pIf->Construct = exprConstruct; pIf->ConstructFinalize = exprConstructFinalize; @@ -408,10 +408,10 @@ ENDobjQueryInterface(expr) */ BEGINObjClassInit(expr, 1, OBJ_IS_CORE_MODULE) /* class, version */ /* request objects we use */ - CHKiRet(objUse(vmprg)); - CHKiRet(objUse(var)); - CHKiRet(objUse(ctok_token)); - CHKiRet(objUse(ctok)); + CHKiRet(objUse(vmprg, CORE_COMPONENT)); + CHKiRet(objUse(var, CORE_COMPONENT)); + CHKiRet(objUse(ctok_token, CORE_COMPONENT)); + CHKiRet(objUse(ctok, CORE_COMPONENT)); OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, exprConstructFinalize); ENDObjClassInit(expr) diff --git a/msg.c b/msg.c index 029dc70c..7fa8234c 100644 --- a/msg.c +++ b/msg.c @@ -2196,13 +2196,16 @@ MsgGetSeverity(obj_t *pThis, int *piSeverity) } +/* dummy */ +rsRetVal msgQueryInterface(void) { return RS_RET_NOT_IMPLEMENTED; } + /* Initialize the message class. Must be called as the very first method * before anything else is called inside this class. * rgerhards, 2008-01-04 */ BEGINObjClassInit(msg, 1, OBJ_IS_CORE_MODULE) /* request objects we use */ - CHKiRet(objUse(var)); + CHKiRet(objUse(var, CORE_COMPONENT)); /* set our own handlers */ OBJSetMethodHandler(objMethod_SERIALIZE, MsgSerialize); diff --git a/obj-types.h b/obj-types.h index 23c2d761..ad8c555c 100644 --- a/obj-types.h +++ b/obj-types.h @@ -43,30 +43,10 @@ typedef enum { PROPTYPE_SYSLOGTIME = 7 } propType_t; - -/* object Types/IDs */ -typedef enum { /* IDs of known object "types/classes" */ - OBJNull = 0, /* no valid object (we do not start at zero so we can detect calloc()) */ - OBJmsg = 1, - OBJstrm = 2, - OBJwtp = 3, - OBJwti = 4, - OBJqueue = 5, - OBJctok = 6, - OBJctok_token = 7, - OBJvar = 8, - OBJvmop = 9, - OBJvmprg = 10, - OBJvm = 11, - OBJsysvar = 12, - OBJvmstk = 13, - OBJobj = 14, /* the base object itself - somewhat tricky, but required... */ - OBJexpr = 15 /* remeber to UPDATE OBJ_NUM_IDS (below) if you add one! */ -} objID_t; -#define OBJ_NUM_IDS 16 +typedef unsigned objID_t; typedef enum { /* IDs of base methods supported by all objects - used for jump table, so - * they must start at zero and be incremented. -- rgerahrds, 2008-01-04 + * they must start at zero and be incremented. -- rgerhards, 2008-01-04 */ objMethod_CONSTRUCT = 0, objMethod_DESTRUCT = 1, @@ -79,11 +59,25 @@ typedef enum { /* IDs of base methods supported by all objects - used for jump t } objMethod_t; #define OBJ_NUM_METHODS 8 /* must be updated to contain the max number of methods supported */ + +/* the base data type for interfaces + * This MUST be in sync with the ifBEGIN macro + */ +typedef struct interface_s { + int ifVersion; /* must be set to version requested */ + //xxxobjID_t oID; /* our object ID (later dynamically assigned) */ +} interface_t; + + typedef struct objInfo_s { - objID_t objID; +objID_t objID; + uchar *pszID; /* the object ID as a string */ + size_t lenID; /* length of the ID string */ int iObjVers; uchar *pszName; rsRetVal (*objMethods[OBJ_NUM_METHODS])(); + // TODO: the queryInterface pointer should probably be added here + rsRetVal (*QueryIF)(interface_t*); } objInfo_t; @@ -100,6 +94,7 @@ typedef struct obj { /* the dummy struct that each derived class can be casted t * other objects. */ #ifndef NDEBUG /* this means if debug... */ +#include # define BEGINobjInstance \ obj_t objData # define ISOBJ_assert(pObj) \ @@ -111,7 +106,7 @@ typedef struct obj { /* the dummy struct that each derived class can be casted t do { \ ASSERT(pObj != NULL); \ ASSERT((unsigned) ((obj_t*) (pObj))->iObjCooCKiE == (unsigned) 0xBADEFEE); \ - ASSERT(objGetObjID(pObj) == OBJ##objType); \ + ASSERT(!strcmp((char*)(((obj_t*)pObj)->pObjInfo->pszID), #objType)); \ } while(0); #else /* non-debug mode, no checks but much faster */ # define BEGINobjInstance obj_t objData @@ -170,11 +165,12 @@ rsRetVal objName##ClassInit(void) \ if(objType == OBJ_IS_CORE_MODULE) { \ CHKiRet(objGetObjInterface(&obj)); /* this provides the root pointer for all other queries */ \ } \ - CHKiRet(obj.InfoConstruct(&pObjInfoOBJ, OBJ##objName, (uchar*) #objName, objVers, \ - (rsRetVal (*)(void*))objName##Construct, (rsRetVal (*)(void*))objName##Destruct)); + CHKiRet(obj.InfoConstruct(&pObjInfoOBJ, (uchar*) #objName, objVers, \ + (rsRetVal (*)(void*))objName##Construct, (rsRetVal (*)(void*))objName##Destruct,\ + (rsRetVal (*)(interface_t*))objName##QueryInterface)); #define ENDObjClassInit(objName) \ - obj.RegisterObj(OBJ##objName, pObjInfoOBJ); \ + iRet = obj.RegisterObj((uchar*)#objName, pObjInfoOBJ); \ finalize_it: \ RETiRet; \ } @@ -302,7 +298,7 @@ finalize_it: \ /* this defines the QueryInterface print entry point. Over time, it should be * present in all objects. */ -#define PROTOTYPEObjQueryInterface(obj) rsRetVal obj##QueryInterface(obj##_if_t *pThis) +//#define PROTOTYPEObjQueryInterface(obj) rsRetVal obj##QueryInterface(obj##_if_t *pThis) #define BEGINobjQueryInterface(obj) \ rsRetVal obj##QueryInterface(obj##_if_t *pIf) \ { \ @@ -315,14 +311,6 @@ finalize_it: \ RETiRet; \ } -/* the base data type for interfaces - * This MUST be in sync with the ifBEGIN macro - */ -typedef struct interface_s { - int ifVersion; /* must be set to version requested */ - objID_t oID; /* our object ID (later dynamically assigned) */ -} interface_t; - /* the following macros should be used to define interfaces inside the * header files. @@ -337,8 +325,9 @@ typedef struct interface_s { * just the class itself!). It must be called before any of the object's * methods can be accessed. */ -#define objUse(obj) \ - obj##QueryInterface(&obj) +#define CORE_COMPONENT NULL /* use this to indicate this is a core component */ +#define objUse(objName, FILENAME) \ + obj.UseObj((uchar*)#objName, (uchar*)FILENAME, (void*) &objName) /* defines data that must always be present at the very begin of the interface structure */ #define ifBEGIN \ @@ -357,7 +346,7 @@ typedef struct interface_s { */ #define PROTOTYPEObj(obj) \ PROTOTYPEObjClassInit(obj); \ - PROTOTYPEObjQueryInterface(obj) \ + //PROTOTYPEObjQueryInterface(obj) /* ------------------------------ end object loader system ------------------------------ */ diff --git a/obj.c b/obj.c index 01694d41..cd28a3e2 100644 --- a/obj.c +++ b/obj.c @@ -39,6 +39,13 @@ * I agree, technically this is much the same, but from an architecture * point of view it looks cleaner (at least to me). * + * Please note that there is another egg-hen problem: we use a linked list, + * which is provided by the linkedList object. However, we need to + * initialize the linked list before we can provide the UseObj() + * functionality. That, in turn, would probably be required by the + * linkedList object. So the solution is to use a backdoor just to + * init the linked list and from then on use the usual interfaces. + * * File begun on 2008-01-04 by RGerhards * * Copyright 2008 Rainer Gerhards and Adiscon GmbH. @@ -68,6 +75,9 @@ #include #include +/* how many objects are supported by rsyslogd? */ +#define OBJ_NUM_IDS 100 //TODO 16 were currently in use 2008-02-29 + #include "rsyslog.h" #include "syslogd-types.h" #include "srUtils.h" @@ -75,10 +85,10 @@ #include "stream.h" /* static data */ +DEFobjCurrIf(obj) /* we define our own interface, as this is expected by some macros! */ DEFobjCurrIf(var) static objInfo_t *arrObjInfo[OBJ_NUM_IDS]; /* array with object information pointers */ -/* some defines */ /* cookies for serialized lines */ #define COOKIE_OBJLINE '<' @@ -86,6 +96,9 @@ static objInfo_t *arrObjInfo[OBJ_NUM_IDS]; /* array with object information poin #define COOKIE_ENDLINE '>' #define COOKIE_BLANKLINE '.' +/* forward definitions */ +static rsRetVal FindObjInfo(cstr_t *pszObjName, objInfo_t **ppInfo); + /* methods */ /* This is a dummy method to be used when a standard method has not been @@ -108,11 +121,12 @@ static rsRetVal objInfoNotImplementedDummy(void __attribute__((unused)) *pThis) * resulting object shall be cached during the lifetime of the class and each * object shall receive a reference. A constructor and destructor MUST be provided for all * objects, thus they are in the parameter list. - * pszName must point to constant pool memory. It is never freed. + * pszID is the identifying object name and must point to constant pool memory. It is never freed. */ static rsRetVal -InfoConstruct(objInfo_t **ppThis, objID_t objID, uchar *pszName, int iObjVers, - rsRetVal (*pConstruct)(void *), rsRetVal (*pDestruct)(void *)) +InfoConstruct(objInfo_t **ppThis, uchar *pszID, int iObjVers, + rsRetVal (*pConstruct)(void *), rsRetVal (*pDestruct)(void *), + rsRetVal (*pQueryIF)(interface_t*)) { DEFiRet; int i; @@ -124,9 +138,12 @@ InfoConstruct(objInfo_t **ppThis, objID_t objID, uchar *pszName, int iObjVers, if((pThis = calloc(1, sizeof(objInfo_t))) == NULL) ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY); - pThis->pszName = pszName; + pThis->pszID = pszID; + pThis->lenID = strlen((char*)pszID); + pThis->pszName = (uchar*)strdup((char*)pszID); /* it's OK if we have NULL ptr, GetName() will deal with that! */ pThis->iObjVers = iObjVers; - pThis->objID = objID; + pThis->QueryIF = pQueryIF; + //xxxpThis->objID = objID; pThis->objMethods[0] = pConstruct; pThis->objMethods[1] = pDestruct; @@ -190,16 +207,10 @@ static rsRetVal objSerializeHeader(strm_t *pStrm, obj_t *pObj, uchar *pszRecType /* object type, version and string length */ CHKiRet(strmWriteChar(pStrm, ':')); - CHKiRet(strmWriteLong(pStrm, objGetObjID(pObj))); + CHKiRet(strmWrite(pStrm, pObj->pObjInfo->pszID, pObj->pObjInfo->lenID)); CHKiRet(strmWriteChar(pStrm, ':')); CHKiRet(strmWriteLong(pStrm, objGetVersion(pObj))); - /* and finally we write the object name - this is primarily meant for - * human readers. The idea is that it can be easily skipped when reading - * the object back in - */ - CHKiRet(strmWriteChar(pStrm, ':')); - CHKiRet(strmWrite(pStrm, objGetClassName(pObj), strlen((char*)objGetClassName(pObj)))); /* record trailer */ CHKiRet(strmWriteChar(pStrm, ':')); CHKiRet(strmWriteChar(pStrm, '\n')); @@ -386,6 +397,40 @@ finalize_it: /* define a helper to make code below a bit cleaner (and quicker to write) */ #define NEXTC CHKiRet(strmReadChar(pStrm, &c))//;dbgprintf("c: %c\n", c); + +/* de-serialize an embedded, non-octect-counted string. This is useful + * for deserializing the object name inside the header. The string is + * terminated by the first occurence of the ':' character. + * rgerhards, 2008-02-29 + */ +static rsRetVal +objDeserializeEmbedStr(cstr_t **ppStr, strm_t *pStrm) +{ + DEFiRet; + uchar c; + cstr_t *pStr = NULL; + + assert(ppStr != NULL); + + CHKiRet(rsCStrConstruct(&pStr)); + + NEXTC; + while(c != ':') { + CHKiRet(rsCStrAppendChar(pStr, c)); + NEXTC; + } + CHKiRet(rsCStrFinish(pStr)); + + *ppStr = pStr; + +finalize_it: + if(iRet != RS_RET_OK && pStr != NULL) + rsCStrDestruct(&pStr); + + RETiRet; +} + + /* de-serialize a number */ static rsRetVal objDeserializeNumber(number_t *pNum, strm_t *pStrm) { @@ -492,14 +537,13 @@ finalize_it: /* de-serialize an object header * rgerhards, 2008-01-07 */ -static rsRetVal objDeserializeHeader(uchar *pszRecType, objID_t *poID, int* poVers, strm_t *pStrm) +static rsRetVal objDeserializeHeader(uchar *pszRecType, cstr_t **ppstrID, int* poVers, strm_t *pStrm) { DEFiRet; - number_t ioID; number_t oVers; uchar c; - assert(poID != NULL); + assert(ppstrID != NULL); assert(poVers != NULL); assert(!strcmp((char*) pszRecType, "Obj") || !strcmp((char*) pszRecType, "OPB")); @@ -513,19 +557,15 @@ static rsRetVal objDeserializeHeader(uchar *pszRecType, objID_t *poID, int* poVe NEXTC; if(c != ':') ABORT_FINALIZE(RS_RET_INVALID_HEADER_VERS); /* object type and version */ - CHKiRet(objDeserializeNumber(&ioID, pStrm)); + CHKiRet(objDeserializeEmbedStr(ppstrID, pStrm)); CHKiRet(objDeserializeNumber(&oVers, pStrm)); - if(ioID < 1 || ioID >= OBJ_NUM_IDS) - ABORT_FINALIZE(RS_RET_INVALID_OID); - /* and now we skip over the rest until the delemiting \n */ NEXTC; while(c != '\n') { NEXTC; } - *poID = (objID_t) ioID; *poVers = oVers; finalize_it: @@ -662,21 +702,21 @@ finalize_it: * of the trailer. Header must already have been processed. * rgerhards, 2008-01-11 */ -static rsRetVal objDeserializeProperties(obj_t *pObj, objID_t oID, strm_t *pStrm) +static rsRetVal objDeserializeProperties(obj_t *pObj, objInfo_t *pObjInfo, strm_t *pStrm) { DEFiRet; var_t *pVar; ISOBJ_assert(pObj); ISOBJ_TYPE_assert(pStrm, strm); - ASSERT(oID > 0 && oID < OBJ_NUM_IDS); + ASSERT(pObjInfo != NULL); CHKiRet(var.Construct(&pVar)); CHKiRet(var.ConstructFinalize(pVar)); iRet = objDeserializeProperty(pVar, pStrm); while(iRet == RS_RET_OK) { - CHKiRet(arrObjInfo[oID]->objMethods[objMethod_SETPROPERTY](pObj, pVar)); + CHKiRet(pObjInfo->objMethods[objMethod_SETPROPERTY](pObj, pVar)); iRet = objDeserializeProperty(pVar, pStrm); } var.Destruct(&pVar); @@ -699,16 +739,17 @@ finalize_it: * rgerhards, 2008-01-07 */ static rsRetVal -Deserialize(void *ppObj, objID_t objTypeExpected, strm_t *pStrm, rsRetVal (*fFixup)(obj_t*,void*), void *pUsr) +Deserialize(void *ppObj, uchar *pszTypeExpected, strm_t *pStrm, rsRetVal (*fFixup)(obj_t*,void*), void *pUsr) { DEFiRet; rsRetVal iRetLocal; obj_t *pObj = NULL; - objID_t oID = 0; /* this assignment is just to supress a compiler warning - this saddens me */ int oVers = 0; /* after all, it is totally useless but takes up some execution time... */ + cstr_t *pstrID = NULL; + objInfo_t *pObjInfo; assert(ppObj != NULL); - assert(objTypeExpected > 0 && objTypeExpected < OBJ_NUM_IDS); + assert(pszTypeExpected != NULL); ISOBJ_TYPE_assert(pStrm, strm); /* we de-serialize the header. if all goes well, we are happy. However, if @@ -719,20 +760,22 @@ Deserialize(void *ppObj, objID_t objTypeExpected, strm_t *pStrm, rsRetVal (*fFix * rgerhards, 2008-07-08 */ do { - iRetLocal = objDeserializeHeader((uchar*) "Obj", &oID, &oVers, pStrm); + iRetLocal = objDeserializeHeader((uchar*) "Obj", &pstrID, &oVers, pStrm); if(iRetLocal != RS_RET_OK) { dbgprintf("objDeserialize error %d during header processing - trying to recover\n", iRetLocal); -abort(); CHKiRet(objDeserializeTryRecover(pStrm)); } } while(iRetLocal != RS_RET_OK); - if(oID != objTypeExpected) + if(rsCStrSzStrCmp(pstrID, pszTypeExpected, strlen((char*)pszTypeExpected))) // TODO: optimize strlen() - caller shall provide ABORT_FINALIZE(RS_RET_INVALID_OID); - CHKiRet(arrObjInfo[oID]->objMethods[objMethod_CONSTRUCT](&pObj)); + + CHKiRet(FindObjInfo(pstrID, &pObjInfo)); + + CHKiRet(pObjInfo->objMethods[objMethod_CONSTRUCT](&pObj)); /* we got the object, now we need to fill the properties */ - CHKiRet(objDeserializeProperties(pObj, oID, pStrm)); + CHKiRet(objDeserializeProperties(pObj, pObjInfo, pStrm)); /* check if we need to call a fixup function that modifies the object * before it is finalized. -- rgerhards, 2008-01-13 @@ -741,8 +784,8 @@ abort(); CHKiRet(fFixup(pObj, pUsr)); /* we have a valid object, let's finalize our work and return */ - if(objInfoIsImplemented(arrObjInfo[oID], objMethod_CONSTRUCTION_FINALIZER)) - CHKiRet(arrObjInfo[oID]->objMethods[objMethod_CONSTRUCTION_FINALIZER](pObj)); + if(objInfoIsImplemented(pObjInfo, objMethod_CONSTRUCTION_FINALIZER)) + CHKiRet(pObjInfo->objMethods[objMethod_CONSTRUCTION_FINALIZER](pObj)); *((obj_t**) ppObj) = pObj; @@ -750,6 +793,9 @@ finalize_it: if(iRet != RS_RET_OK && pObj != NULL) free(pObj); // TODO: check if we can call destructor 2008-01-13 rger + if(pstrID != NULL) + rsCStrDestruct(&pstrID); + RETiRet; } @@ -762,8 +808,9 @@ objDeserializeObjAsPropBag(obj_t *pObj, strm_t *pStrm) { DEFiRet; rsRetVal iRetLocal; - objID_t oID = 0; /* this assignment is just to supress a compiler warning - this saddens me */ + cstr_t *pstrID = NULL; int oVers = 0; /* after all, it is totally useless but takes up some execution time... */ + objInfo_t *pObjInfo; ISOBJ_assert(pObj); ISOBJ_TYPE_assert(pStrm, strm); @@ -776,20 +823,25 @@ objDeserializeObjAsPropBag(obj_t *pObj, strm_t *pStrm) * rgerhards, 2008-07-08 */ do { - iRetLocal = objDeserializeHeader((uchar*) "Obj", &oID, &oVers, pStrm); + iRetLocal = objDeserializeHeader((uchar*) "Obj", &pstrID, &oVers, pStrm); if(iRetLocal != RS_RET_OK) { dbgprintf("objDeserializeObjAsPropBag error %d during header - trying to recover\n", iRetLocal); CHKiRet(objDeserializeTryRecover(pStrm)); } } while(iRetLocal != RS_RET_OK); - if(oID != objGetObjID(pObj)) + if(rsCStrSzStrCmp(pstrID, pObj->pObjInfo->pszID, pObj->pObjInfo->lenID)) ABORT_FINALIZE(RS_RET_INVALID_OID); + CHKiRet(FindObjInfo(pstrID, &pObjInfo)); + /* we got the object, now we need to fill the properties */ - CHKiRet(objDeserializeProperties(pObj, oID, pStrm)); + CHKiRet(objDeserializeProperties(pObj, pObjInfo, pStrm)); finalize_it: + if(pstrID != NULL) + rsCStrDestruct(&pstrID); + RETiRet; } @@ -808,8 +860,9 @@ DeserializePropBag(obj_t *pObj, strm_t *pStrm) { DEFiRet; rsRetVal iRetLocal; - objID_t oID = 0; /* this assignment is just to supress a compiler warning - this saddens me */ - int oVers = 0; /* after all, it is totally useless but takes up some execution time... */ + cstr_t *pstrID = NULL; + int oVers; + objInfo_t *pObjInfo; ISOBJ_assert(pObj); ISOBJ_TYPE_assert(pStrm, strm); @@ -822,20 +875,25 @@ DeserializePropBag(obj_t *pObj, strm_t *pStrm) * rgerhards, 2008-07-08 */ do { - iRetLocal = objDeserializeHeader((uchar*) "OPB", &oID, &oVers, pStrm); + iRetLocal = objDeserializeHeader((uchar*) "OPB", &pstrID, &oVers, pStrm); if(iRetLocal != RS_RET_OK) { dbgprintf("objDeserializePropBag error %d during header - trying to recover\n", iRetLocal); CHKiRet(objDeserializeTryRecover(pStrm)); } } while(iRetLocal != RS_RET_OK); - if(oID != objGetObjID(pObj)) + if(rsCStrSzStrCmp(pstrID, pObj->pObjInfo->pszID, pObj->pObjInfo->lenID)) ABORT_FINALIZE(RS_RET_INVALID_OID); + CHKiRet(FindObjInfo(pstrID, &pObjInfo)); + /* we got the object, now we need to fill the properties */ - CHKiRet(objDeserializeProperties(pObj, oID, pStrm)); + CHKiRet(objDeserializeProperties(pObj, pObjInfo, pStrm)); finalize_it: + if(pstrID != NULL) + rsCStrDestruct(&pstrID); + RETiRet; } @@ -902,27 +960,116 @@ GetName(obj_t *pThis) } -/* register a classe's info pointer, so that we can reference it later, if needed to +/* Find the objInfo object for the current object + * rgerhards, 2008-02-29 + */ +static rsRetVal +FindObjInfo(cstr_t *pstrOID, objInfo_t **ppInfo) +{ + DEFiRet; + int bFound; + int i; + + assert(pstrOID != NULL); + assert(ppInfo != NULL); + + bFound = 0; + i = 0; + while(!bFound && i < OBJ_NUM_IDS && arrObjInfo[i] != NULL) { + if(!rsCStrSzStrCmp(pstrOID, arrObjInfo[i]->pszID, arrObjInfo[i]->lenID)) { + bFound = 1; + break; + } + ++i; + } + + if(!bFound) + ABORT_FINALIZE(RS_RET_NOT_FOUND); + + *ppInfo = arrObjInfo[i]; + +finalize_it: + if(iRet == RS_RET_OK) { + dbgprintf("caller requested object '%s', found at index %d\n", (*ppInfo)->pszID, i); + } else { + dbgprintf("caller requested object '%s', not found (iRet %d)\n", rsCStrGetSzStr(pstrOID), iRet); + } + + RETiRet; +} + + +/* register a classes' info pointer, so that we can reference it later, if needed to * (e.g. for de-serialization support). * rgerhards, 2008-01-07 + * In this function, we look for a free space in the object table. While we do so, we + * also detect if the same object has already been registered, which is not valid. + * rgerhards, 2008-02-29 */ static rsRetVal -RegisterObj(objID_t oID, objInfo_t *pInfo) +RegisterObj(uchar *pszObjName, objInfo_t *pInfo) { DEFiRet; + int bFound; + int i; + assert(pszObjName != NULL); assert(pInfo != NULL); - assert(arrObjInfo[oID] == NULL); - if(oID < 1 || oID > OBJ_NUM_IDS) - ABORT_FINALIZE(RS_RET_INVALID_OID); - arrObjInfo[oID] = pInfo; + bFound = 0; + i = 0; + while(!bFound && i < OBJ_NUM_IDS && arrObjInfo[i] != NULL) { + if( arrObjInfo[i] != NULL + && !strcmp((char*)arrObjInfo[i]->pszID, (char*)pszObjName)) { + bFound = 1; + break; + } + ++i; + } + + if(bFound) ABORT_FINALIZE(RS_RET_OBJ_ALREADY_REGISTERED); + if(i >= OBJ_NUM_IDS) ABORT_FINALIZE(RS_RET_OBJ_REGISTRY_OUT_OF_SPACE); + + arrObjInfo[i] = pInfo; + dbgprintf("object '%s' successfully registered with index %d, qIF %p\n", pszObjName, i, pInfo->QueryIF); finalize_it: RETiRet; } +/* This function shall be called by anyone who would like to use an object. It will + * try to locate the object, load it into memory if not already present and return + * a pointer to the objects interface. + * rgerhards, 2008-02-29 + */ +static rsRetVal +UseObj(uchar *pObjName, uchar *pObjFile, interface_t **ppIf) +{ + DEFiRet; + cstr_t *pStr = NULL; + objInfo_t *pObjInfo; + + CHKiRet(rsCStrConstructFromszStr(&pStr, pObjName)); + iRet =FindObjInfo(pStr, &pObjInfo); + + if(iRet == RS_RET_NOT_FOUND) { + /* in this case, we need to see if we can dynamically load the object */ + FINALIZE; /* TODO: implement */ + } else if(iRet != RS_RET_OK) { + FINALIZE; /* give up */ + } + + pObjInfo->QueryIF(ppIf); + +finalize_it: + if(pStr != NULL) + rsCStrDestruct(&pStr); + + RETiRet; +} + + /* queryInterface function * rgerhards, 2008-02-29 */ @@ -937,8 +1084,9 @@ CODESTARTobjQueryInterface(obj) * work here (if we can support an older interface version - that, * of course, also affects the "if" above). */ - pIf->oID = OBJobj; + //xxxpIf->oID = OBJobj; + pIf->UseObj = UseObj; pIf->InfoConstruct = InfoConstruct; pIf->DestructObjSelf = DestructObjSelf; pIf->BeginSerializePropBag = BeginSerializePropBag; @@ -987,12 +1135,13 @@ objClassInit(void) } /* request objects we use */ - CHKiRet(objUse(var)); + CHKiRet(objGetObjInterface(&obj)); /* get ourselves ;) */ +CHKiRet(varClassInit()); + CHKiRet(objUse(var, CORE_COMPONENT)); finalize_it: RETiRet; } -/* - * vi:set ai: +/* vi:set ai: */ diff --git a/obj.h b/obj.h index cf5aed6a..4cce9d02 100644 --- a/obj.h +++ b/obj.h @@ -71,8 +71,7 @@ DEFobjCurrIf(obj) -#define objGetClassName(pThis) (((obj_t*) (pThis))->pObjInfo->pszName) -#define objGetObjID(pThis) (((obj_t*) (pThis))->pObjInfo->objID) +#define objGetClassName(pThis) (((obj_t*) (pThis))->pObjInfo->pszID) #define objGetVersion(pThis) (((obj_t*) (pThis))->pObjInfo->iObjVers) /* the next macro MUST be called in Constructors: */ #ifndef NDEBUG /* this means if debug... */ @@ -94,16 +93,17 @@ /* interfaces */ BEGINinterface(obj) /* name must also be changed in ENDinterface macro! */ rsRetVal (*UseObj)(uchar *pObjName, uchar *pObjFile, interface_t **ppIf); - rsRetVal (*InfoConstruct)(objInfo_t **ppThis, objID_t objID, uchar *pszName, int iObjVers, - rsRetVal (*pConstruct)(void *), rsRetVal (*pDestruct)(void *)); + rsRetVal (*InfoConstruct)(objInfo_t **ppThis, uchar *pszID, int iObjVers, + rsRetVal (*pConstruct)(void *), rsRetVal (*pDestruct)(void *), + rsRetVal (*pQueryIF)(interface_t*)); rsRetVal (*DestructObjSelf)(obj_t *pThis); rsRetVal (*BeginSerializePropBag)(strm_t *pStrm, obj_t *pObj); rsRetVal (*InfoSetMethod)(objInfo_t *pThis, objMethod_t objMethod, rsRetVal (*pHandler)(void*)); rsRetVal (*BeginSerialize)(strm_t *pStrm, obj_t *pObj); rsRetVal (*SerializeProp)(strm_t *pStrm, uchar *pszPropName, propType_t propType, void *pUsr); rsRetVal (*EndSerialize)(strm_t *pStrm); - rsRetVal (*RegisterObj)(objID_t oID, objInfo_t *pInfo); - rsRetVal (*Deserialize)(void *ppObj, objID_t objTypeExpected, strm_t *pStrm, rsRetVal (*fFixup)(obj_t*,void*), void *pUsr); + rsRetVal (*RegisterObj)(uchar *pszObjName, objInfo_t *pInfo); + rsRetVal (*Deserialize)(void *ppObj, uchar *pszTypeExpected, strm_t *pStrm, rsRetVal (*fFixup)(obj_t*,void*), void *pUsr); rsRetVal (*DeserializePropBag)(obj_t *pObj, strm_t *pStrm); rsRetVal (*SetName)(obj_t *pThis, uchar *pszName); uchar * (*GetName)(obj_t *pThis); diff --git a/queue.c b/queue.c index a6bcff9f..58b4d618 100644 --- a/queue.c +++ b/queue.c @@ -728,15 +728,15 @@ queueTryLoadPersistedInfo(queue_t *pThis) while(iUngottenObjs > 0) { /* fill the queue from disk */ - CHKiRet(obj.Deserialize((void*) &pUsr, OBJmsg, psQIF, NULL, NULL)); + CHKiRet(obj.Deserialize((void*) &pUsr, (uchar*)"msg", psQIF, NULL, NULL)); queueUngetObj(pThis, pUsr, MUTEX_ALREADY_LOCKED); --iUngottenObjs; /* one less */ } /* and now the stream objects (some order as when persisted!) */ - CHKiRet(obj.Deserialize(&pThis->tVars.disk.pWrite, OBJstrm, psQIF, + CHKiRet(obj.Deserialize(&pThis->tVars.disk.pWrite, (uchar*) "strm", psQIF, (rsRetVal(*)(obj_t*,void*))queueLoadPersStrmInfoFixup, pThis)); - CHKiRet(obj.Deserialize(&pThis->tVars.disk.pRead, OBJstrm, psQIF, + CHKiRet(obj.Deserialize(&pThis->tVars.disk.pRead, (uchar*) "strm", psQIF, (rsRetVal(*)(obj_t*,void*))queueLoadPersStrmInfoFixup, pThis)); CHKiRet(strmSeekCurrOffs(pThis->tVars.disk.pWrite)); @@ -861,7 +861,7 @@ static rsRetVal qDelDisk(queue_t *pThis, void **ppUsr) int64 offsOut; CHKiRet(strmGetCurrOffset(pThis->tVars.disk.pRead, &offsIn)); - CHKiRet(obj.Deserialize(ppUsr, OBJmsg, pThis->tVars.disk.pRead, NULL, NULL)); + CHKiRet(obj.Deserialize(ppUsr, (uchar*) "msg", pThis->tVars.disk.pRead, NULL, NULL)); CHKiRet(strmGetCurrOffset(pThis->tVars.disk.pRead, &offsOut)); /* This time it is a bit tricky: we free disk space only upon file deletion. So we need @@ -2106,6 +2106,10 @@ finalize_it: RETiRet; } #undef isProp + +/* dummy */ +rsRetVal queueQueryInterface(void) { return RS_RET_NOT_IMPLEMENTED; } + /* Initialize the stream class. Must be called as the very first method * before anything else is called inside this class. * rgerhards, 2008-01-09 diff --git a/rsyslog.h b/rsyslog.h index c44e73cc..5f8a22a1 100644 --- a/rsyslog.h +++ b/rsyslog.h @@ -135,6 +135,8 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth RS_RET_INVALID_VAR = -2058, /**< a var_t or its content is unsuitable, eg. VARTYPE_NONE */ RS_RET_INVALID_NUMBER = -2059, /**< number invalid during parsing */ RS_RET_NOT_A_NUMBER = -2060, /**< e.g. conversion impossible because the string is not a number */ + RS_RET_OBJ_ALREADY_REGISTERED = -2061, /**< object (name) is already registered */ + RS_RET_OBJ_REGISTRY_OUT_OF_SPACE = -2062, /**< the object registry has run out of space */ /* RainerScript error messages (range 1000.. 1999) */ RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */ diff --git a/stream.c b/stream.c index 35b38c5e..bc345f93 100644 --- a/stream.c +++ b/stream.c @@ -884,6 +884,26 @@ strmGetCurrOffset(strm_t *pThis, int64 *pOffs) } +/* queryInterface function + * rgerhards, 2008-02-29 + */ +BEGINobjQueryInterface(strm) +CODESTARTobjQueryInterface(strm) + if(pIf->ifVersion != strmCURR_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). + */ + //xxxpIf->oID = OBJvm; + +finalize_it: +ENDobjQueryInterface(strm) + + /* Initialize the stream class. Must be called as the very first method * before anything else is called inside this class. * rgerhards, 2008-01-09 diff --git a/stream.h b/stream.h index 903bb284..0dc5e646 100644 --- a/stream.h +++ b/stream.h @@ -90,6 +90,12 @@ typedef struct strm_s { int bInRecord; /* if 1, indicates that we are currently writing a not-yet complete record */ } strm_t; +/* interfaces */ +BEGINinterface(strm) /* name must also be changed in ENDinterface macro! */ +ENDinterface(strm) +#define strmCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */ + + /* prototypes */ rsRetVal strmConstruct(strm_t **ppThis); rsRetVal strmConstructFinalize(strm_t __attribute__((unused)) *pThis); diff --git a/syslogd.c b/syslogd.c index 2f7ba0f2..cf2b85e7 100644 --- a/syslogd.c +++ b/syslogd.c @@ -3576,9 +3576,6 @@ static rsRetVal InitGlobalClasses(void) DEFiRet; CHKiRet(objClassInit()); /* *THIS* *MUST* always be the first class initilizer being called! */ - /* dummy "classes" */ - CHKiRet(confClassInit()); - CHKiRet(actionClassInit()); /* real ones */ CHKiRet(msgClassInit()); @@ -3587,19 +3584,23 @@ static rsRetVal InitGlobalClasses(void) CHKiRet(wtpClassInit()); CHKiRet(queueClassInit()); CHKiRet(vmstkClassInit()); + //TODO: currently done in objClassInit CHKiRet(varClassInit()); + CHKiRet(sysvarClassInit()); CHKiRet(vmClassInit()); CHKiRet(vmopClassInit()); CHKiRet(vmprgClassInit()); - CHKiRet(sysvarClassInit()); - CHKiRet(varClassInit()); CHKiRet(ctok_tokenClassInit()); CHKiRet(ctokClassInit()); CHKiRet(exprClassInit()); + /* dummy "classes" */ + CHKiRet(confClassInit()); + CHKiRet(actionClassInit()); + /* request objects we use */ CHKiRet(objGetObjInterface(&obj)); /* this provides the root pointer for all other queries */ - CHKiRet(objUse(expr)); - CHKiRet(objUse(vm)); + CHKiRet(obj.UseObj((uchar*)"expr", NULL, (void*) &expr)); + CHKiRet(obj.UseObj((uchar*)"vm", NULL, (void*) &vm)); finalize_it: RETiRet; diff --git a/sysvar.c b/sysvar.c index aafcb688..6fb2aab3 100644 --- a/sysvar.c +++ b/sysvar.c @@ -172,7 +172,7 @@ CODESTARTobjQueryInterface(sysvar) * work here (if we can support an older interface version - that, * of course, also affects the "if" above). */ - pIf->oID = OBJsysvar; + //xxxpIf->oID = "sysvar";//OBJsysvar; pIf->Construct = sysvarConstruct; pIf->ConstructFinalize = sysvarConstructFinalize; @@ -188,7 +188,7 @@ ENDobjQueryInterface(sysvar) */ BEGINObjClassInit(sysvar, 1, OBJ_IS_CORE_MODULE) /* class, version */ /* request objects we use */ - CHKiRet(objUse(var)); + CHKiRet(objUse(var, CORE_COMPONENT)); /* set our own handlers */ OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, sysvarConstructFinalize); diff --git a/var.c b/var.c index aa2100b4..c1d66643 100644 --- a/var.c +++ b/var.c @@ -366,7 +366,7 @@ CODESTARTobjQueryInterface(var) * work here (if we can support an older interface version - that, * of course, also affects the "if" above). */ - pIf->oID = OBJvar; + //xxxpIf->oID = OBJvar; pIf->Construct = varConstruct; pIf->ConstructFinalize = varConstructFinalize; diff --git a/vm.c b/vm.c index 5c0eccba..37048a9b 100644 --- a/vm.c +++ b/vm.c @@ -504,7 +504,7 @@ CODESTARTobjQueryInterface(vm) * work here (if we can support an older interface version - that, * of course, also affects the "if" above). */ - pIf->oID = OBJvm; + //xxxpIf->oID = OBJvm; pIf->Construct = vmConstruct; pIf->ConstructFinalize = vmConstructFinalize; @@ -524,9 +524,9 @@ ENDobjQueryInterface(vm) */ BEGINObjClassInit(vm, 1, OBJ_IS_CORE_MODULE) /* class, version */ /* request objects we use */ - CHKiRet(objUse(vmstk)); - CHKiRet(objUse(var)); - CHKiRet(objUse(sysvar)); + CHKiRet(objUse(vmstk, CORE_COMPONENT)); + CHKiRet(objUse(var, CORE_COMPONENT)); + CHKiRet(objUse(sysvar, CORE_COMPONENT)); /* set our own handlers */ OBJSetMethodHandler(objMethod_DEBUGPRINT, vmDebugPrint); diff --git a/vmop.c b/vmop.c index 199ec4cd..affa83e7 100644 --- a/vmop.c +++ b/vmop.c @@ -199,7 +199,7 @@ CODESTARTobjQueryInterface(vmop) * work here (if we can support an older interface version - that, * of course, also affects the "if" above). */ - pIf->oID = OBJvmop; + //xxxpIf->oID = OBJvmop; pIf->Construct = vmopConstruct; pIf->ConstructFinalize = vmopConstructFinalize; @@ -218,7 +218,7 @@ ENDobjQueryInterface(vmop) */ BEGINObjClassInit(vmop, 1, OBJ_IS_CORE_MODULE) /* class, version */ /* request objects we use */ - CHKiRet(objUse(var)); + CHKiRet(objUse(var, CORE_COMPONENT)); OBJSetMethodHandler(objMethod_DEBUGPRINT, vmopDebugPrint); OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, vmopConstructFinalize); diff --git a/vmprg.c b/vmprg.c index dde899ad..a1b41ad8 100644 --- a/vmprg.c +++ b/vmprg.c @@ -145,7 +145,7 @@ CODESTARTobjQueryInterface(vmprg) * work here (if we can support an older interface version - that, * of course, also affects the "if" above). */ - pIf->oID = OBJvmprg; + //xxxpIf->oID = OBJvmprg; pIf->Construct = vmprgConstruct; pIf->ConstructFinalize = vmprgConstructFinalize; @@ -163,7 +163,7 @@ ENDobjQueryInterface(vmprg) */ BEGINObjClassInit(vmprg, 1, OBJ_IS_CORE_MODULE) /* class, version */ /* request objects we use */ - CHKiRet(objUse(vmop)); + CHKiRet(objUse(vmop, CORE_COMPONENT)); /* set our own handlers */ OBJSetMethodHandler(objMethod_DEBUGPRINT, vmprgDebugPrint); diff --git a/vmstk.c b/vmstk.c index 3f07a8f4..9ca815ff 100644 --- a/vmstk.c +++ b/vmstk.c @@ -201,7 +201,7 @@ CODESTARTobjQueryInterface(vmstk) * work here (if we can support an older interface version - that, * of course, also affects the "if" above). */ - pIf->oID = OBJvmstk; + //xxxpIf->oID = OBJvmstk; pIf->Construct = vmstkConstruct; pIf->ConstructFinalize = vmstkConstructFinalize; @@ -224,7 +224,7 @@ ENDobjQueryInterface(vmstk) */ BEGINObjClassInit(vmstk, 1, OBJ_IS_CORE_MODULE) /* class, version */ /* request objects we use */ - CHKiRet(objUse(var)); + CHKiRet(objUse(var, CORE_COMPONENT)); /* set our own handlers */ OBJSetMethodHandler(objMethod_DEBUGPRINT, vmstkDebugPrint); diff --git a/wti.c b/wti.c index fab52327..9fadfdf3 100644 --- a/wti.c +++ b/wti.c @@ -453,6 +453,10 @@ finalize_it: } +/* dummy */ +rsRetVal wtiQueryInterface(void) { return RS_RET_NOT_IMPLEMENTED; } + + /* Initialize the wti class. Must be called as the very first method * before anything else is called inside this class. * rgerhards, 2008-01-09 diff --git a/wtp.c b/wtp.c index 6094d469..83cb5d5e 100644 --- a/wtp.c +++ b/wtp.c @@ -604,6 +604,9 @@ finalize_it: RETiRet; } +/* dummy */ +rsRetVal wtpQueryInterface(void) { return RS_RET_NOT_IMPLEMENTED; } + /* Initialize the stream class. Must be called as the very first method * before anything else is called inside this class. * rgerhards, 2008-01-09 -- cgit