/* 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;
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. -- rgerhards, 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 */
/* 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 */
int ifIsLoaded; /* is the interface loaded? (0-no, 1-yes, 2-load failed; if not 1, functions can NOT be called! */
} interface_t;
typedef struct objInfo_s {
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])();
rsRetVal (*QueryIF)(interface_t*);
struct modInfo_s *pModInfo;
} 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... */
#include
# 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(!strcmp((char*)(((obj_t*)pObj)->pObjInfo->pszID), #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(struct modInfo_s*)
/* below: objName must be the object name (e.g. vm, strm, ...) and ISCORE must be
* 1 if the module is a statically linked core module and 0 if it is a
* dynamically loaded one. -- rgerhards, 2008-02-29
*/
#define OBJ_IS_CORE_MODULE 1 /* This should better be renamed to something like "OBJ_IS_NOT_LIBHEAD" or so... ;) */
#define OBJ_IS_LOADABLE_MODULE 0
#define BEGINObjClassInit(objName, objVers, objType) \
rsRetVal objName##ClassInit(struct modInfo_s *pModInfo) \
{ \
DEFiRet; \
if(objType == OBJ_IS_CORE_MODULE) { /* are we a core module? */ \
CHKiRet(objGetObjInterface(&obj)); /* this provides the root pointer for all other queries */ \
} \
CHKiRet(obj.InfoConstruct(&pObjInfoOBJ, (uchar*) #objName, objVers, \
(rsRetVal (*)(void*))objName##Construct,\
(rsRetVal (*)(void*))objName##Destruct,\
(rsRetVal (*)(interface_t*))objName##QueryInterface, pModInfo)); \
#define ENDObjClassInit(objName) \
iRet = obj.RegisterObj((uchar*)#objName, pObjInfoOBJ); \
finalize_it: \
RETiRet; \
}
/* ... and now the same for abstract classes.
* TODO: consolidate the two -- rgerhards, 2008-02-29
*/
#define BEGINAbstractObjClassInit(objName, objVers, objType) \
rsRetVal objName##ClassInit(struct modInfo_s *pModInfo) \
{ \
DEFiRet; \
if(objType == OBJ_IS_CORE_MODULE) { /* are we a core module? */ \
CHKiRet(objGetObjInterface(&obj)); /* this provides the root pointer for all other queries */ \
} \
CHKiRet(obj.InfoConstruct(&pObjInfoOBJ, (uchar*) #objName, objVers, \
NULL,\
NULL,\
(rsRetVal (*)(interface_t*))objName##QueryInterface, pModInfo));
#define ENDObjClassInit(objName) \
iRet = obj.RegisterObj((uchar*)#objName, pObjInfoOBJ); \
finalize_it: \
RETiRet; \
}
/* now come the class exit. This is to be called immediately before the class is
* unloaded (actual unload for plugins, program termination for core modules)
* gerhards, 2008-03-10
*/
#define PROTOTYPEObjClassExit(objName) rsRetVal objName##ClassExit(void)
#define BEGINObjClassExit(objName, objType) \
rsRetVal objName##ClassExit(void) \
{ \
DEFiRet;
#define CODESTARTObjClassExit(objName)
#define ENDObjClassExit(objName) \
iRet = obj.UnregisterObj((uchar*)#objName, pObjInfoOBJ); \
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) { \
obj.DestructObjSelf((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 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. The MYLIB part is the name of my library, or NULL if
* the caller is a core module. Using the right value here is important to get
* the reference counting correct (object accesses from the same library must
* not be counted because that would cause a library plugin to never unload, as
* its ClassExit() entry points are only called if no object is referenced, which
* would never happen as the library references itself.
* rgerhards, 2008-03-11
*/
#define CORE_COMPONENT NULL /* use this to indicate this is a core component */
#define DONT_LOAD_LIB NULL /* do not load a library to obtain object interface (currently same as CORE_COMPONENT) */
/*#define objUse(objName, MYLIB, FILENAME) \
obj.UseObj(__FILE__, (uchar*)#objName, MYLIB, (uchar*)FILENAME, (void*) &objName)
*/
#define objUse(objName, FILENAME) \
obj.UseObj(__FILE__, (uchar*)#objName, (uchar*)FILENAME, (void*) &objName)
#define objRelease(objName, FILENAME) \
obj.ReleaseObj(__FILE__, (uchar*)#objName, (uchar*) FILENAME, (void*) &objName)
/* 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 */ \
int ifIsLoaded; /* is the interface loaded? (0-no, 1-yes; if no, functions can NOT be called! */
/* 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, .ifIsLoaded = 0 };
/* 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); \
PROTOTYPEObjClassExit(obj);
/* ------------------------------ end object loader system ------------------------------ */
#include "modules.h"
#endif /* #ifndef OBJ_TYPES_H_INCLUDED */