/* Some type definitions and macros for the obj object.
* I needed to move them out of the main obj.h, because obj.h's
* prototypes use other data types. However, their .h's rely
* on some of the obj.h data types and macros. So I needed to break
* that loop somehow and I've done that by moving the typedefs
* into this file here.
*
* Copyright 2008 Rainer Gerhards and Adiscon GmbH.
*
* This file is part of rsyslog.
*
* Rsyslog is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Rsyslog is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Rsyslog. If not, see .
*
* A copy of the GPL can be found in the file "COPYING" in this distribution.
*/
#ifndef OBJ_TYPES_H_INCLUDED
#define OBJ_TYPES_H_INCLUDED
#include "stringbuf.h"
#include "syslogd-types.h"
/* property types for obj[De]Serialize() */
typedef enum {
PROPTYPE_NONE = 0, /* currently no value set */
PROPTYPE_PSZ = 1,
PROPTYPE_SHORT = 2,
PROPTYPE_INT = 3,
PROPTYPE_LONG = 4,
PROPTYPE_INT64 = 5,
PROPTYPE_CSTR = 6,
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,
OBJexpr = 14 /* remeber to UPDATE OBJ_NUM_IDS (below) if you add one! */
} objID_t;
#define OBJ_NUM_IDS 15
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_CONSTRUCT = 0,
objMethod_DESTRUCT = 1,
objMethod_SERIALIZE = 2,
objMethod_DESERIALIZE = 3,
objMethod_SETPROPERTY = 4,
objMethod_CONSTRUCTION_FINALIZER = 5,
objMethod_GETSEVERITY = 6,
objMethod_DEBUGPRINT = 7
} objMethod_t;
#define OBJ_NUM_METHODS 8 /* must be updated to contain the max number of methods supported */
typedef struct objInfo_s {
objID_t objID;
int iObjVers;
uchar *pszName;
rsRetVal (*objMethods[OBJ_NUM_METHODS])();
} objInfo_t;
typedef struct obj { /* the dummy struct that each derived class can be casted to */
objInfo_t *pObjInfo;
#ifndef NDEBUG /* this means if debug... */
unsigned int iObjCooCKiE; /* must always be 0xBADEFEE for a valid object */
#endif
uchar *pszName; /* the name of *this* specific object instance */
} obj_t;
/* macros which must be gloablly-visible (because they are used during definition of
* other objects.
*/
#ifndef NDEBUG /* this means if debug... */
# define BEGINobjInstance \
obj_t objData
# define ISOBJ_assert(pObj) \
do { \
ASSERT((pObj) != NULL); \
ASSERT((unsigned) ((obj_t*)(pObj))->iObjCooCKiE == (unsigned) 0xBADEFEE); \
} while(0);
# define ISOBJ_TYPE_assert(pObj, objType) \
do { \
ASSERT(pObj != NULL); \
ASSERT((unsigned) ((obj_t*) (pObj))->iObjCooCKiE == (unsigned) 0xBADEFEE); \
ASSERT(objGetObjID(pObj) == OBJ##objType); \
} while(0);
#else /* non-debug mode, no checks but much faster */
# define BEGINobjInstance obj_t objData
# define ISOBJ_TYPE_assert(pObj, objType)
# define ISOBJ_assert(pObj)
#endif
#define DEFpropSetMethPTR(obj, prop, dataType)\
rsRetVal obj##Set##prop(obj##_t *pThis, dataType *pVal)\
{ \
/* DEV debug: dbgprintf("%sSet%s()\n", #obj, #prop); */\
pThis->prop = pVal; \
return RS_RET_OK; \
}
#define PROTOTYPEpropSetMethPTR(obj, prop, dataType)\
rsRetVal obj##Set##prop(obj##_t *pThis, dataType*)
#define DEFpropSetMeth(obj, prop, dataType)\
rsRetVal obj##Set##prop(obj##_t *pThis, dataType pVal)\
{ \
/* DEV debug: dbgprintf("%sSet%s()\n", #obj, #prop); */\
pThis->prop = pVal; \
return RS_RET_OK; \
}
#define DEFpropSetMethFP(obj, prop, dataType)\
rsRetVal obj##Set##prop(obj##_t *pThis, dataType)\
{ \
/* DEV debug: dbgprintf("%sSet%s()\n", #obj, #prop); */\
pThis->prop = pVal; \
return RS_RET_OK; \
}
#define PROTOTYPEpropSetMethFP(obj, prop, dataType)\
rsRetVal obj##Set##prop(obj##_t *pThis, dataType)
#define DEFpropSetMeth(obj, prop, dataType)\
rsRetVal obj##Set##prop(obj##_t *pThis, dataType pVal)\
{ \
/* DEV debug: dbgprintf("%sSet%s()\n", #obj, #prop); */\
pThis->prop = pVal; \
return RS_RET_OK; \
}
#define PROTOTYPEpropSetMeth(obj, prop, dataType)\
rsRetVal obj##Set##prop(obj##_t *pThis, dataType pVal)
#define INTERFACEpropSetMeth(obj, prop, dataType)\
rsRetVal (*Set##prop)(obj##_t *pThis, dataType)
/* class initializer */
#define PROTOTYPEObjClassInit(objName) rsRetVal objName##ClassInit(void)
#define BEGINObjClassInit(objName, objVers) \
rsRetVal objName##ClassInit(void) \
{ \
DEFiRet; \
CHKiRet(objInfoConstruct(&pObjInfoOBJ, OBJ##objName, (uchar*) #objName, objVers, \
(rsRetVal (*)(void*))objName##Construct, (rsRetVal (*)(void*))objName##Destruct));
#define ENDObjClassInit(objName) \
objRegisterObj(OBJ##objName, pObjInfoOBJ); \
finalize_it: \
RETiRet; \
}
/* this defines both the constructor and initializer
* rgerhards, 2008-01-10
*/
#define BEGINobjConstruct(obj) \
rsRetVal obj##Initialize(obj##_t __attribute__((unused)) *pThis) \
{ \
DEFiRet;
#define ENDobjConstruct(obj) \
/* use finalize_it: before calling the macro (if you need it)! */ \
RETiRet; \
} \
rsRetVal obj##Construct(obj##_t **ppThis) \
{ \
DEFiRet; \
obj##_t *pThis; \
\
ASSERT(ppThis != NULL); \
\
if((pThis = (obj##_t *)calloc(1, sizeof(obj##_t))) == NULL) { \
ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY); \
} \
objConstructSetObjInfo(pThis); \
\
obj##Initialize(pThis); \
\
finalize_it: \
OBJCONSTRUCT_CHECK_SUCCESS_AND_CLEANUP \
RETiRet; \
}
/* this defines the destructor. The important point is that the base object
* destructor is called. The upper-level class shall destruct all of its
* properties, but not the instance itself. This is freed here by the
* framework (we need an intact pointer because we need to free the
* obj_t structures inside it). A pointer to the object pointer must be
* parse, because it is re-set to NULL (this, for example, is important in
* cancellation handlers). The object pointer is always named pThis.
* The object is always freed, even if there is some error while
* Cancellation is blocked during destructors, as this could have fatal
* side-effects. However, this also means the upper-level object should
* not perform any lenghty processing.
* IMPORTANT: if the upper level object requires some situations where the
* object shall not be destructed (e.g. via reference counting), then
* it shall set pThis to NULL, which prevents destruction of the
* object.
* processing.
* rgerhards, 2008-01-30
*/
#define BEGINobjDestruct(obj) \
rsRetVal obj##Destruct(obj##_t **ppThis) \
{ \
DEFiRet; \
int iCancelStateSave; \
obj##_t *pThis;
#define CODESTARTobjDestruct(obj) \
ASSERT(ppThis != NULL); \
pThis = *ppThis; \
ISOBJ_TYPE_assert(pThis, obj); \
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &iCancelStateSave);
#define ENDobjDestruct(obj) \
goto finalize_it; /* prevent compiler warning ;) */ \
/* no more code here! */ \
finalize_it: \
if(pThis != NULL) { \
objDestructObjSelf((obj_t*) pThis); \
free(pThis); \
*ppThis = NULL; \
} \
pthread_setcancelstate(iCancelStateSave, NULL); \
RETiRet; \
}
/* this defines the debug print entry point. DebugPrint is optional. If
* it is provided, the object should output some meaningful information
* via the debug system.
* rgerhards, 2008-02-20
*/
#define PROTOTYPEObjDebugPrint(obj) rsRetVal obj##DebugPrint(obj##_t *pThis)
#define INTERFACEObjDebugPrint(obj) rsRetVal (*DebugPrint)(obj##_t *pThis)
#define BEGINobjDebugPrint(obj) \
rsRetVal obj##DebugPrint(obj##_t *pThis) \
{ \
DEFiRet; \
#define CODESTARTobjDebugPrint(obj) \
ASSERT(pThis != NULL); \
ISOBJ_TYPE_assert(pThis, obj); \
#define ENDobjDebugPrint(obj) \
RETiRet; \
}
/* ------------------------------ object loader system ------------------------------ *
* The following code is the early beginning of a dynamic object loader system. The
* root idea is that all objects will become dynamically loadable libraries over time,
* which is necessary to get a clean plug-in interface where every plugin can access
* rsyslog's rich object model via simple and quite portable methods.
*
* To do so, each object defines one or more interfaces. They are essentially structures
* with function (method) pointers. Anyone interested in calling an object must first
* obtain the interface and can then call through it.
*
* The interface data type must always be called _if_t, as this is expected
* by the macros. Having consitent naming is also easier for the programmer. By default,
* macros create a static variable named like the object in each calling objects
* static data block.
*
* To facilitate moving to this system, I begin to implement some hooks, which
* allows to use interfaces today (when the rest of the infrastructure is not yet
* there). This is in the hope that it will ease migration to the full-fledged system
* once we are ready to work on that.
* rgerhards, 2008-02-21
*/
/* 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 BEGINobjQueryInterface(obj) \
rsRetVal obj##QueryInterface(obj##_if_t *pIf) \
{ \
DEFiRet; \
#define CODESTARTobjQueryInterface(obj) \
ASSERT(pIf != NULL);
#define ENDobjQueryInterface(obj) \
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.
*/
#define BEGINinterface(obj) \
typedef struct obj##_if_s {\
ifBEGIN; /* This MUST always be the first interface member */
#define ENDinterface(obj) \
} obj##_if_t;
/* the following macro is used to get access to an object (not an instance,
* just the class itself!). It must be called before any of the object's
* methods can be accessed.
*/
#define objUse(obj) \
obj##QueryInterface(&obj)
/* defines data that must always be present at the very begin of the interface structure */
#define ifBEGIN \
int ifVersion; /* must be set to version requested */ \
objID_t oID; /* our object ID (later dynamically assigned) */
/* use the following define some place in your static data (suggested right at
* the beginning
*/
#define DEFobjCurrIf(obj) \
static obj##_if_t obj = { .ifVersion = obj##CURR_IF_VERSION };
/* define the prototypes for a class - when we use interfaces, we just have few
* functions that actually need to be non-static.
*/
#define PROTOTYPEObj(obj) \
PROTOTYPEObjClassInit(obj); \
PROTOTYPEObjQueryInterface(obj) \
/* ------------------------------ end object loader system ------------------------------ */
#endif /* #ifndef OBJ_TYPES_H_INCLUDED */