From 571d21a33a46707deabc80769b4c8cb7d0f7c161 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 7 Jan 2008 17:26:49 +0000 Subject: - MsgSetProperty() implemented - defined a property class - implemented deserializer (needs some more work) --- msg.c | 67 ++++++++++-- msg.h | 2 +- obj.c | 282 ++++++++++++++++++++++++++++++++++++++++++++++-- obj.h | 43 ++++++-- plugins/imklog/imklog.c | 10 +- queue.c | 50 +++++++-- queue.h | 2 +- rsyslog.h | 9 ++ syslogd.c | 42 +++----- syslogd.h | 3 +- 10 files changed, 435 insertions(+), 75 deletions(-) diff --git a/msg.c b/msg.c index 7c17f8ce..3e34ac1c 100644 --- a/msg.c +++ b/msg.c @@ -38,6 +38,7 @@ #include #include "syslogd.h" #include "srUtils.h" +#include "stringbuf.h" #include "template.h" #include "msg.h" @@ -203,22 +204,28 @@ rsRetVal MsgEnableThreadSafety(void) * An object constructed via this function should only be destroyed * via "MsgDestruct()". */ -msg_t* MsgConstruct(void) +rsRetVal MsgConstruct(msg_t **ppThis) { + DEFiRet; msg_t *pM; - if((pM = calloc(1, sizeof(msg_t))) != NULL) - { /* initialize members that are non-zero */ - pM->iRefCount = 1; - pM->iSeverity = -1; - pM->iFacility = -1; - getCurrTime(&(pM->tRcvdAt)); - objConstructSetObjInfo(pM); - } + assert(ppThis != NULL); + if((pM = calloc(1, sizeof(msg_t))) == NULL) + ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY); + + /* initialize members that are non-zero */ + pM->iRefCount = 1; + pM->iSeverity = -1; + pM->iFacility = -1; + getCurrTime(&(pM->tRcvdAt)); + objConstructSetObjInfo(pM); /* DEV debugging only! dbgprintf("MsgConstruct\t0x%x, ref 1\n", (int)pM);*/ - return(pM); + *ppThis = pM; + +finalize_it: + return iRet; } @@ -2076,12 +2083,52 @@ char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe, } +/* 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 + * change over time). + * rgerhards, 2008-01-07 + */ +#define isProp(name) !rsCStrSzStrCmp(pProp->pcsName, (uchar*) name, sizeof(name) - 1) +rsRetVal MsgSetProperty(msg_t *pThis, property_t *pProp) +{ + DEFiRet; + + assert(pThis != NULL); + assert(pProp != NULL); + + if(isProp("iProtocolVersion")) { + setProtocolVersion(pThis, pProp->val.vShort); + } else if(isProp("iSeverity")) { + pThis->iSeverity = pProp->val.vShort; + } else if(isProp("iFacility")) { + pThis->iFacility = pProp->val.vShort; + } else if(isProp("msgFlags")) { + pThis->msgFlags = pProp->val.vInt; + } else if(isProp("pszRawMsg")) { + MsgSetRawMsg(pThis, (char*) rsCStrGetSzStrNoNULL(pProp->val.vpCStr)); + } else if(isProp("pszMSG")) { + MsgSetMSG(pThis, (char*) rsCStrGetSzStrNoNULL(pProp->val.vpCStr)); + } else if(isProp("pszTAG")) { + MsgSetTAG(pThis, (char*) rsCStrGetSzStrNoNULL(pProp->val.vpCStr)); + } else if(isProp("pszHOSTNAME")) { + MsgSetHOSTNAME(pThis, (char*) rsCStrGetSzStrNoNULL(pProp->val.vpCStr)); + } else if(isProp("pszUxTradMsg")) { + MsgSetUxTradMsg(pThis, (char*) rsCStrGetSzStrNoNULL(pProp->val.vpCStr)); + } + + return iRet; +} +#undef isProp + + /* 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) OBJSetMethodHandler(objMethod_SERIALIZE, MsgSerialize); + OBJSetMethodHandler(objMethod_SETPROPERTY, MsgSetProperty); /* initially, we have no need to lock message objects */ funcLock = MsgLockingDummy; funcUnlock = MsgLockingDummy; diff --git a/msg.h b/msg.h index b904785b..bd8d4f89 100644 --- a/msg.h +++ b/msg.h @@ -108,7 +108,7 @@ typedef struct msg msg_t; /* new name */ */ PROTOTYPEObjClassInit(Msg); char* getProgramName(msg_t*); -msg_t* MsgConstruct(void); +rsRetVal MsgConstruct(msg_t **ppThis); rsRetVal MsgDestruct(msg_t * pM); msg_t* MsgDup(msg_t* pOld); msg_t *MsgAddRef(msg_t *pM); diff --git a/obj.c b/obj.c index 458f7856..356d38d9 100644 --- a/obj.c +++ b/obj.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include "rsyslog.h" @@ -40,6 +41,13 @@ /* static data */ static objInfo_t *arrObjInfo[OBJ_NUM_IDS]; /* array with object information pointers */ +/* some defines */ + +/* cookies for serialized lines */ +#define COOKIE_OBJLINE '<' +#define COOKIE_PROPLINE '+' +#define COOKIE_ENDLINE '>' + /* methods */ /* This is a dummy method to be used when a standard method has not been @@ -55,11 +63,12 @@ static rsRetVal objInfoNotImplementedDummy(void __attribute__((unused)) *pThis) /* construct an object Info object. Each class shall do this on init. The * resulting object shall be cached during the lifetime of the class and each - * object shall receive a reference. A constructor MUST be provided for all - * objects, thus it is in the parameter list. + * 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. */ -rsRetVal objInfoConstruct(objInfo_t **ppThis, objID_t objID, uchar *pszName, int iObjVers, rsRetVal (*pDestruct)(void *)) +rsRetVal objInfoConstruct(objInfo_t **ppThis, objID_t objID, uchar *pszName, int iObjVers, + rsRetVal (*pConstruct)(void *), rsRetVal (*pDestruct)(void *)) { DEFiRet; int i; @@ -75,8 +84,9 @@ rsRetVal objInfoConstruct(objInfo_t **ppThis, objID_t objID, uchar *pszName, int pThis->iObjVers = iObjVers; pThis->objID = objID; - pThis->objMethods[0] = pDestruct; - for(i = 1 ; i < OBJ_NUM_METHODS ; ++i) { + pThis->objMethods[0] = pConstruct; + pThis->objMethods[1] = pDestruct; + for(i = 2 ; i < OBJ_NUM_METHODS ; ++i) { pThis->objMethods[i] = objInfoNotImplementedDummy; } @@ -191,6 +201,8 @@ rsRetVal objSerializeProp(rsCStrObj *pCStr, uchar *pszPropName, propertyType_t p break; } + /* cookie */ + CHKiRet(rsCStrAppendChar(pCStr, COOKIE_PROPLINE)); /* name */ CHKiRet(rsCStrAppendStr(pCStr, pszPropName)); CHKiRet(rsCStrAppendChar(pCStr, ':')); @@ -205,6 +217,7 @@ rsRetVal objSerializeProp(rsCStrObj *pCStr, uchar *pszPropName, propertyType_t p CHKiRet(rsCStrAppendStrWithLen(pCStr, (uchar*) pszBuf, lenBuf)); /* trailer */ + CHKiRet(rsCStrAppendChar(pCStr, ':')); CHKiRet(rsCStrAppendChar(pCStr, '\n')); finalize_it: @@ -225,7 +238,8 @@ static rsRetVal objSerializeHeader(rsCStrObj **ppCStr, obj_t *pObj, rsCStrObj *p rsCStrSetAllocIncrement(pCStr, iAllocIncrement); /* object cookie and serializer version (so far always 1) */ - CHKiRet(rsCStrAppendStr(pCStr, (uchar*) "$Obj1")); + CHKiRet(rsCStrAppendChar(pCStr, COOKIE_OBJLINE)); + CHKiRet(rsCStrAppendStr(pCStr, (uchar*) "Obj1")); /* object type, version and string length */ CHKiRet(rsCStrAppendChar(pCStr, ':')); @@ -242,6 +256,7 @@ static rsRetVal objSerializeHeader(rsCStrObj **ppCStr, obj_t *pObj, rsCStrObj *p CHKiRet(rsCStrAppendChar(pCStr, ':')); CHKiRet(rsCStrAppendStr(pCStr, objGetName(pObj))); /* record trailer */ + CHKiRet(rsCStrAppendChar(pCStr, ':')); CHKiRet(rsCStrAppendChar(pCStr, '\n')); *ppCStr = pCStr; @@ -263,7 +278,8 @@ rsRetVal objEndSerialize(rsCStrObj **ppCStr, obj_t *pObj) CHKiRet(objSerializeHeader(&pCStr, pObj, *ppCStr, rsCStrGetAllocIncrement(*ppCStr))); CHKiRet(rsCStrAppendStrWithLen(pCStr, rsCStrGetBufBeg(*ppCStr), rsCStrLen(*ppCStr))); - CHKiRet(rsCStrAppendStr(pCStr, (uchar*) ".\n")); + CHKiRet(rsCStrAppendChar(pCStr, COOKIE_ENDLINE)); + CHKiRet(rsCStrAppendStr(pCStr, (uchar*) "EndObj\n\n")); CHKiRet(rsCStrFinish(pCStr)); rsCStrDestruct(*ppCStr); @@ -275,6 +291,258 @@ finalize_it: return iRet; } + +/* define a helper to make code below a bit cleaner (and quicker to write) */ +#define NEXTC CHKiRet(serialStoreGetChar(pSerStore, &c))//;dbgprintf("c: %c\n", c); + +/* de-serialize an (long) integer */ +static rsRetVal objDeserializeLong(long *pInt, serialStore_t *pSerStore) +{ + DEFiRet; + int i; + uchar c; + + assert(pInt != NULL); + + NEXTC; + i = 0; + while(isdigit(c)) { + i = i * 10 + c - '0'; + NEXTC; + } + + if(c != ':') ABORT_FINALIZE(RS_RET_INVALID_DELIMITER); + + *pInt = i; +finalize_it: + return iRet; +} + + +/* de-serialize a string, length must be provided */ +static rsRetVal objDeserializeStr(rsCStrObj **ppCStr, int iLen, serialStore_t *pSerStore) +{ + DEFiRet; + int i; + uchar c; + rsCStrObj *pCStr = NULL; + + assert(ppCStr != NULL); + assert(iLen > 0); + + if((pCStr = rsCStrConstruct()) == NULL) + ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY); + + NEXTC; +dbgprintf("deserializestring, c: %c (%x)\n", c, c); + for(i = 0 ; i < iLen ; ++i) { + CHKiRet(rsCStrAppendChar(pCStr, c)); + NEXTC; + } + CHKiRet(rsCStrFinish(pCStr)); + + /* check terminator */ + if(c != ':') ABORT_FINALIZE(RS_RET_INVALID_DELIMITER); + + *ppCStr = pCStr; + +finalize_it: + if(iRet != RS_RET_OK && pCStr != NULL) + rsCStrDestruct(pCStr); + + return iRet; +} + + +/* de-serialize an object header + * rgerhards, 2008-01-07 + */ +static rsRetVal objDeserializeHeader(objID_t *poID, int* poVers, serialStore_t *pSerStore) +{ + DEFiRet; + long ioID; + long oVers; + uchar c; + + assert(poID != NULL); + assert(poVers != NULL); + + /* check header cookie */ + NEXTC; if(c != COOKIE_OBJLINE) ABORT_FINALIZE(RS_RET_INVALID_HEADER); + NEXTC; if(c != 'O') ABORT_FINALIZE(RS_RET_INVALID_HEADER); + NEXTC; if(c != 'b') ABORT_FINALIZE(RS_RET_INVALID_HEADER); + NEXTC; if(c != 'j') ABORT_FINALIZE(RS_RET_INVALID_HEADER); + NEXTC; if(c != '1') ABORT_FINALIZE(RS_RET_INVALID_HEADER_VERS); + NEXTC; if(c != ':') ABORT_FINALIZE(RS_RET_INVALID_HEADER_VERS); + + /* object type and version and string length */ + CHKiRet(objDeserializeLong(&ioID, pSerStore)); + CHKiRet(objDeserializeLong(&oVers, pSerStore)); + + 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: +dbgprintf("DeserializeHeader oid: %ld, vers: %ld, iRet: %d\n", ioID, oVers, iRet); + return iRet; +} + + +/* Deserialize a single property. Pointer must be positioned at begin of line. Whole line + * up until the \n is read. + */ +static rsRetVal objDeserializeProperty(property_t *pProp, serialStore_t *pSerStore) +{ + DEFiRet; + long i; + long iLen; + uchar c; + + assert(pProp != NULL); + + /* check cookie */ + NEXTC; + if(c != COOKIE_PROPLINE) { + /* oops, we've read one char that does not belong to use - unget it first */ + CHKiRet(serialStoreUngetChar(pSerStore, c)); + ABORT_FINALIZE(RS_RET_NO_PROPLINE); + } + + /* get the property name first */ + if((pProp->pcsName = rsCStrConstruct()) == NULL) + ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY); + + NEXTC; + while(c != ':') { + CHKiRet(rsCStrAppendChar(pProp->pcsName, c)); + NEXTC; + } + CHKiRet(rsCStrFinish(pProp->pcsName)); + + /* property type */ + CHKiRet(objDeserializeLong(&i, pSerStore)); + pProp->propType = i; + + /* size (needed for strings) */ + CHKiRet(objDeserializeLong(&iLen, pSerStore)); + + /* we now need to deserialize the value */ +dbgprintf("deserialized property name '%s', type %d, size %ld, c: %c\n", rsCStrGetSzStrNoNULL(pProp->pcsName), pProp->propType, iLen, c); + switch(pProp->propType) { + case PROPTYPE_PSZ: + CHKiRet(objDeserializeStr(&pProp->val.vpCStr, iLen, pSerStore)); + break; + case PROPTYPE_SHORT: + CHKiRet(objDeserializeLong(&i, pSerStore)); + pProp->val.vShort = i; + break; + case PROPTYPE_INT: + CHKiRet(objDeserializeLong(&i, pSerStore)); + pProp->val.vInt = i; + break; + case PROPTYPE_LONG: + CHKiRet(objDeserializeLong(&pProp->val.vLong, pSerStore)); + break; + case PROPTYPE_CSTR: + CHKiRet(objDeserializeStr(&pProp->val.vpCStr, iLen, pSerStore)); + break; + case PROPTYPE_SYSLOGTIME: + /* dummy */ NEXTC; while(c != ':') NEXTC; + break; + } + + /* we should now be at the end of the line. So the next char must be \n */ + NEXTC; + if(c != '\n') ABORT_FINALIZE(RS_RET_INVALID_PROPFRAME); + +finalize_it: + return iRet; +} + + +/* de-serialize an object trailer. This does not get any data but checks if the + * format is ok. + * rgerhards, 2008-01-07 + */ +static rsRetVal objDeserializeTrailer(serialStore_t *pSerStore) +{ + DEFiRet; + uchar c; + + /* check header cookie */ + NEXTC; if(c != COOKIE_ENDLINE) ABORT_FINALIZE(RS_RET_INVALID_TRAILER); + NEXTC; if(c != 'E') ABORT_FINALIZE(RS_RET_INVALID_TRAILER); + NEXTC; if(c != 'n') ABORT_FINALIZE(RS_RET_INVALID_TRAILER); + NEXTC; if(c != 'd') ABORT_FINALIZE(RS_RET_INVALID_TRAILER); + NEXTC; if(c != 'O') ABORT_FINALIZE(RS_RET_INVALID_TRAILER); + NEXTC; if(c != 'b') ABORT_FINALIZE(RS_RET_INVALID_TRAILER); + NEXTC; if(c != 'j') ABORT_FINALIZE(RS_RET_INVALID_TRAILER); + NEXTC; if(c != '\n') ABORT_FINALIZE(RS_RET_INVALID_TRAILER); + NEXTC; if(c != '\n') ABORT_FINALIZE(RS_RET_INVALID_TRAILER); + +dbgprintf("obj trailer OK\n"); +finalize_it: + return iRet; +} + + +/* De-Serialize an object. + * Params: Pointer to object Pointer (pObj) (like a obj_t**, but can not do that due to compiler warning) + * expected object ID (to check against) + * Function that returns the next character from the serialized object (from file, memory, whatever) + * Pointer to be passed to the function + * The caller must destruct the created object. + * rgerhards, 2008-01-07 + */ +rsRetVal objDeserialize(void *ppObj, objID_t objTypeExpected, serialStore_t *pSerStore) +{ + DEFiRet; + obj_t *pObj = NULL; + property_t propBuf; + 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... */ + + assert(ppObj != NULL); + assert(objTypeExpected > 0 && objTypeExpected < OBJ_NUM_IDS); + assert(pSerStore != NULL); + + CHKiRet(objDeserializeHeader(&oID, &oVers, pSerStore)); + + if(oID != objTypeExpected) + ABORT_FINALIZE(RS_RET_INVALID_OID); + CHKiRet(arrObjInfo[oID]->objMethods[objMethod_CONSTRUCT](&pObj)); + + /* we got the object, now we need to fill the properties */ + iRet = objDeserializeProperty(&propBuf, pSerStore); + while(iRet == RS_RET_OK) { + CHKiRet(arrObjInfo[oID]->objMethods[objMethod_SETPROPERTY](pObj, &propBuf)); + iRet = objDeserializeProperty(&propBuf, pSerStore); + } + rsCStrDestruct(propBuf.pcsName); /* todo: a destructor would be nice here... -- rger, 2008-01-07 */ + + if(iRet != RS_RET_NO_PROPLINE) + FINALIZE; +dbgprintf("good propline loop exit\n"); + + CHKiRet(objDeserializeTrailer(pSerStore)); /* do trailer checks */ + + *((obj_t**) ppObj) = pObj; + +finalize_it: + return iRet; +} + +#undef NEXTC /* undef helper macro */ + + /* --------------- end object serializiation / deserialization support --------------- */ /* register a classe's info pointer, so that we can reference it later, if needed to diff --git a/obj.h b/obj.h index f4c9f6cd..74fe5b7c 100644 --- a/obj.h +++ b/obj.h @@ -38,6 +38,19 @@ typedef enum { /* do NOT start at 0 to detect uninitialized types after calloc( PROPTYPE_SYSLOGTIME = 6 } propertyType_t; +typedef struct { + rsCStrObj *pcsName; + propertyType_t propType; + union { + short vShort; + int vInt; + long vLong; + rsCStrObj *vpCStr; /* used for both rsCStr and psz */ + struct syslogTime vSyslogTime; + + } val; +} property_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()) */ @@ -48,12 +61,14 @@ typedef enum { /* IDs of known object "types/classes" */ 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 */ - objMethod_DESTRUCT = 0, - objMethod_SERIALIZE = 1, - objMethod_DESERIALIZE = 2, - objMethod_DEBUGPRINT = 3 + objMethod_CONSTRUCT = 0, + objMethod_DESTRUCT = 1, + objMethod_SERIALIZE = 2, + objMethod_DESERIALIZE = 3, + objMethod_SETPROPERTY = 4, + objMethod_DEBUGPRINT = 5 } objMethod_t; -#define OBJ_NUM_METHODS 4 /* must be updated to contain the max number of methods supported */ +#define OBJ_NUM_METHODS 6 /* must be updated to contain the max number of methods supported */ typedef struct objInfo_s { objID_t objID; @@ -66,6 +81,18 @@ typedef struct obj { /* the dummy struct that each derived class can be casted t objInfo_t *pObjInfo; } obj_t; +/* the following structure is used for deserialization. It defines a serial storage with a single + * ungetc() capability. This should probably become its own object some time. -- rgerhards, 2008-01-07 + */ +typedef struct serialStore_s { + void *pUsr; /* Pointer to some user data */ + /* methods */ + rsRetVal (*funcGetChar)(void*, uchar*); + rsRetVal (*funcUngetChar)(void*, uchar); +} serialStore_t; +#define serialStoreGetChar(pThis, c) (pThis->funcGetChar(pThis->pUsr, c)) +#define serialStoreUngetChar(pThis, c) (pThis->funcUngetChar(pThis->pUsr, c)) + /* macros */ #define objSerializeSCALAR(propName, propType) \ @@ -87,7 +114,8 @@ typedef struct obj { /* the dummy struct that each derived class can be casted t rsRetVal objName##ClassInit(void) \ { \ DEFiRet; \ - CHKiRet(objInfoConstruct(&pObjInfoOBJ, obj##objName, (uchar*) #objName, objVers, (rsRetVal (*)(void*))objName##Destruct)); + CHKiRet(objInfoConstruct(&pObjInfoOBJ, obj##objName, (uchar*) #objName, objVers, \ + (rsRetVal (*)(void*))objName##Construct, (rsRetVal (*)(void*))objName##Destruct)); #define ENDObjClassInit(objName) \ objRegisterObj(obj##objName, pObjInfoOBJ); \ @@ -100,13 +128,14 @@ finalize_it: \ /* prototypes */ -rsRetVal objInfoConstruct(objInfo_t **ppThis, objID_t objID, uchar *pszName, int iObjVers, rsRetVal (*pDestruct)(void *)); +rsRetVal objInfoConstruct(objInfo_t **ppThis, objID_t objID, uchar *pszName, int iObjVers, rsRetVal (*pConstruct)(void *), rsRetVal (*pDestruct)(void *)); rsRetVal objInfoSetMethod(objInfo_t *pThis, objMethod_t objMethod, rsRetVal (*pHandler)(void*)); rsRetVal objBeginSerialize(rsCStrObj **ppCStr, obj_t *pObj, size_t iExpectedObjSize); rsRetVal objSerializePsz(rsCStrObj *pCStr, uchar *psz, size_t len); rsRetVal objEndSerialize(rsCStrObj **ppCStr, obj_t *pObj); rsRetVal objSerializeProp(rsCStrObj *pCStr, uchar *pszPropName, propertyType_t propType, void *pUsr); rsRetVal objRegisterObj(objID_t oID, objInfo_t *pInfo); +rsRetVal objDeserialize(void *ppObj, objID_t objTypeExpected, serialStore_t *pSerStore); PROTOTYPEObjClassInit(obj); #endif /* #ifndef OBJ_H_INCLUDED */ diff --git a/plugins/imklog/imklog.c b/plugins/imklog/imklog.c index 11bc8d41..8ed900dd 100644 --- a/plugins/imklog/imklog.c +++ b/plugins/imklog/imklog.c @@ -131,14 +131,7 @@ static rsRetVal writeSyslogV(int iPRI, const char *szFmt, va_list va) /* here we must create our message object and supply it to the message queue */ - if((pMsg = MsgConstruct()) == NULL){ - /* There is not much we can do in this case - we discard the message - * then. - */ - dbgprintf("Memory shortage in imklogd: could not construct Msg object.\n"); - return RS_RET_OUT_OF_MEMORY; - } - + CHKiRet(MsgConstruct(&pMsg)); MsgSetUxTradMsg(pMsg, msgBuf); MsgSetRawMsg(pMsg, msgBuf); MsgSetMSG(pMsg, (msgBuf + iLen)); @@ -152,6 +145,7 @@ static rsRetVal writeSyslogV(int iPRI, const char *szFmt, va_list va) /* provide message to the queue engine */ logmsg(iPRI, pMsg, INTERNAL_MSG); +finalize_it: return iRet; } diff --git a/queue.c b/queue.c index c2b67d13..8630938a 100644 --- a/queue.c +++ b/queue.c @@ -42,6 +42,7 @@ #include "queue.h" #include "stringbuf.h" #include "srUtils.h" +#include "obj.h" /* static data */ @@ -275,6 +276,12 @@ static rsRetVal qDiskReadChar(queueFileDescription_t *pFile, uchar *pC) ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY); pFile->iBufPtrMax = 0; /* results in immediate read request */ } + + if(pFile->iUngetC != -1) { /* do we have an "unread" char that we need to provide? */ + *pC = pFile->iUngetC; + pFile->iUngetC = -1; + ABORT_FINALIZE(RS_RET_OK); + } /* do we need to obtain a new buffer */ if(pFile->iBufPtr >= pFile->iBufPtrMax) { @@ -295,6 +302,26 @@ finalize_it: return iRet; } + +/* unget a single character just like ungetc(). As with that call, there is only a single + * character buffering capability. + * rgerhards, 2008-01-07 + */ +static rsRetVal qDiskUnreadChar(queueFileDescription_t *pFile, uchar c) +{ + assert(pFile != NULL); + assert(pFile->iUngetC == -1); + pFile->iUngetC = c; + + return RS_RET_OK; +} + +#if 0 +/* we have commented out the code below because we would like to preserve it. It + * is currently not needed, but may be useful if we implemented a bufferred file + * class. + * rgerhards, 2008-01-07 + */ /* read a line from a queue file. A line is terminated by LF. The LF is read, but it * is not returned in the buffer (it is discared). The caller is responsible for * destruction of the returned CStr object! @@ -328,6 +355,7 @@ finalize_it: return iRet; } +#endif /* #if 0 - saved code */ /*** end buffered read functions for queue files ***/ @@ -349,10 +377,12 @@ static rsRetVal qConstructDisk(queue_t *pThis) pThis->tVars.disk.fWrite.iCurrFileNum = 1; pThis->tVars.disk.fWrite.iCurrOffs = 0; pThis->tVars.disk.fWrite.fd = -1; + pThis->tVars.disk.fWrite.iUngetC = -1; pThis->tVars.disk.fRead.iCurrFileNum = 1; pThis->tVars.disk.fRead.fd = -1; - pThis->tVars.disk.fWrite.iCurrOffs = 0; + pThis->tVars.disk.fRead.iCurrOffs = 0; + pThis->tVars.disk.fRead.iUngetC = -1; finalize_it: return iRet; @@ -401,29 +431,31 @@ finalize_it: return iRet; } -static rsRetVal qDelDisk(queue_t __attribute__((unused)) *pThis, void __attribute__((unused)) **ppUsr) +static rsRetVal qDelDisk(queue_t *pThis, void **ppUsr) { DEFiRet; + msg_t *pMsg = NULL; + serialStore_t serialStore; assert(pThis != NULL); if(pThis->tVars.disk.fRead.fd == -1) CHKiRet(qDiskOpenFile(pThis, &pThis->tVars.disk.fRead, O_RDONLY, 0600)); // TODO: open modes! - /* read here */ - rsCStrObj *pCStr = NULL; - CHKiRet(qDiskReadLine(&pThis->tVars.disk.fRead, &pCStr)); - dbgprintf("qDelDisk read line '%s'\n", rsCStrGetSzStr(pCStr)); - rsCStrDestruct(pCStr); - /* de-serialize here */ + /* de-serialize object from file */ + serialStore.pUsr = &pThis->tVars.disk.fRead; + serialStore.funcGetChar = (rsRetVal (*)(void*, uchar*)) qDiskReadChar; + serialStore.funcUngetChar = (rsRetVal (*)(void*, uchar)) qDiskUnreadChar; + CHKiRet(objDeserialize((void*) &pMsg, objMsg, &serialStore)); /* switch to next file when EOF is reached. We may also delete the last file in that case. pThis->tVars.disk.fWrite.iCurrOffs += iWritten; if(pThis->tVars.disk.fWrite.iCurrOffs >= pThis->tVars.disk.iMaxFileSize) CHKiRet(qDiskNextFile(pThis, &pThis->tVars.disk.fWrite)); */ +dbgprintf("got object %lx\n", (unsigned long) pMsg); - iRet = RS_RET_ERR; + *ppUsr = (void*) pMsg; finalize_it: return iRet; diff --git a/queue.h b/queue.h index 8459d0f6..80b835ab 100644 --- a/queue.h +++ b/queue.h @@ -38,6 +38,7 @@ typedef struct { uchar *pIOBuf; /* io Buffer */ int iBufPtrMax; /* current max Ptr in Buffer (if partial read!) */ int iBufPtr; /* pointer into current buffer */ + int iUngetC; /* char set via UngetChar() call or -1 if none set */ } queueFileDescription_t; #define qFILE_IOBUF_SIZE 4096 /* size of the IO buffer */ @@ -97,7 +98,6 @@ typedef struct queue_s { } tVars; } queue_t; - /* prototypes */ rsRetVal queueDestruct(queue_t *pThis); rsRetVal queueEnqObj(queue_t *pThis, void *pUsr); diff --git a/rsyslog.h b/rsyslog.h index c9993c3f..b46b4b10 100644 --- a/rsyslog.h +++ b/rsyslog.h @@ -97,6 +97,12 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth RS_RET_EOF = -2026, /**< end of file reached, not necessarily an error */ RS_RET_IO_ERROR = -2027, /**< some kind of IO error happened */ RS_RET_INVALID_OID = -2028, /**< invalid object ID */ + RS_RET_INVALID_HEADER = -2029, /**< invalid header */ + RS_RET_INVALID_HEADER_VERS = -2030, /**< invalid header version */ + RS_RET_INVALID_DELIMITER = -2031, /**< invalid delimiter, e.g. between params */ + RS_RET_INVALID_PROPFRAME = -2032, /**< invalid framing in serialized property */ + RS_RET_NO_PROPLINE = -2033, /**< line is not a property line */ + RS_RET_INVALID_TRAILER = -2034, /**< invalid trailer */ RS_RET_OK_DELETE_LISTENTRY = 1, /**< operation successful, but callee requested the deletion of an entry (special state) */ RS_RET_TERMINATE_NOW = 2, /**< operation successful, function is requested to terminate (mostly used with threads) */ RS_RET_NO_RUN = 3, /**< operation successful, but function does not like to be executed */ @@ -175,6 +181,9 @@ typedef unsigned char uchar; # define __attribute__(x) /*NOTHING*/ #endif +/* The following prototype is convenient, even though it may not be the 100% correct place.. -- rgerhards 2008-01-07 */ +void dbgprintf(char *, ...) __attribute__((format(printf, 1, 2))); + #endif /* multi-include protection */ /* * vi:set ai: diff --git a/syslogd.c b/syslogd.c index 1df661cd..bb3866f4 100644 --- a/syslogd.c +++ b/syslogd.c @@ -1254,22 +1254,16 @@ void untty(void) * changed parameter iSource to bParseHost. For details, see comment in * printchopped(). rgerhards 2005-10-06 */ -void printline(char *hname, char *msg, int bParseHost) +rsRetVal printline(char *hname, char *msg, int bParseHost) { + DEFiRet; register char *p; int pri; msg_t *pMsg; /* Now it is time to create the message object (rgerhards) */ - if((pMsg = MsgConstruct()) == NULL){ - /* rgerhards, 2007-06-21: if we can not get memory, we discard this - * message but continue to run (in the hope that things improve) - */ - glblHadMemShortage = 1; - dbgprintf("Memory shortage in printline(): Could not construct Msg object.\n"); - return; - } + CHKiRet(MsgConstruct(&pMsg)); MsgSetRawMsg(pMsg, msg); pMsg->bParseHOSTNAME = bParseHost; @@ -1306,11 +1300,13 @@ void printline(char *hname, char *msg, int bParseHost) * message. As we like to emulate it, we need to add the hostname * to it. */ - if(MsgSetUxTradMsg(pMsg, p) != 0) return; + if(MsgSetUxTradMsg(pMsg, p) != 0) + ABORT_FINALIZE(RS_RET_ERR); logmsg(pri, pMsg, SYNC_FILE); - return; +finalize_it: + return iRet; } @@ -1500,29 +1496,13 @@ void printchopped(char *hname, char *msg, int len, int fd, int bParseHost) * function here probably is only an interim solution and that we need to * think on the best way to do this. */ -void +rsRetVal logmsgInternal(int pri, char *msg, int flags) { + DEFiRet; msg_t *pMsg; - if((pMsg = MsgConstruct()) == NULL){ - /* rgerhards 2004-11-09: calling panic might not be the - * brightest idea - however, it is the best I currently have - * (think a bit more about this). - * rgehards, 2007-06-21: I have now thought a bit more about - * it. If we are so low on memory, there is few we can do. calling - * panic so far only write a debug line - this is seomthing we keep. - * Other than that, however, we ignore the error and hope that - * memory shortage will be resolved while we continue to run. In any - * case, there is no valid point in aborting the syslogd for this - * reason - that would be counter-productive. So we ignore the - * to be logged message. - */ - glblHadMemShortage = 1; - dbgprintf("Memory shortage in logmsgInternal: could not construct Msg object.\n"); - return; - } - + CHKiRet(MsgConstruct(&pMsg)); MsgSetUxTradMsg(pMsg, msg); MsgSetRawMsg(pMsg, msg); MsgSetHOSTNAME(pMsg, LocalHostName); @@ -1541,6 +1521,8 @@ logmsgInternal(int pri, char *msg, int flags) */ logmsg(pri, pMsg, flags); } +finalize_it: + return iRet; } /* This functions looks at the given message and checks if it matches the diff --git a/syslogd.h b/syslogd.h index 3eb002fc..67f10daf 100644 --- a/syslogd.h +++ b/syslogd.h @@ -49,7 +49,6 @@ #define ADDDATE 0x004 /* add a date to the message */ #define MARK 0x008 /* this message is a mark */ -void dbgprintf(char *, ...) __attribute__((format(printf, 1, 2))); void logerror(char *type); void logerrorSz(char *type, char *errMsg); void logerrorInt(char *type, int iErr); @@ -68,7 +67,7 @@ int getSubString(uchar **ppSrc, char *pDst, size_t DstSize, char cSep); /* the following prototypes should go away once we have an input * module interface -- rgerhards, 2007-12-12 */ -void logmsgInternal(int pri, char *msg, int flags); +rsRetVal logmsgInternal(int pri, char *msg, int flags); void logmsg(int pri, msg_t *pMsg, int flags); extern int glblHadMemShortage; /* indicates if we had memory shortage some time during the run */ extern char LocalHostName[]; -- cgit