summaryrefslogtreecommitdiffstats
path: root/runtime/obj-types.h
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/obj-types.h')
-rw-r--r--runtime/obj-types.h444
1 files changed, 444 insertions, 0 deletions
diff --git a/runtime/obj-types.h b/runtime/obj-types.h
new file mode 100644
index 0000000..21fb89b
--- /dev/null
+++ b/runtime/obj-types.h
@@ -0,0 +1,444 @@
+/* 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-2019 Rainer Gerhards and Adiscon GmbH.
+ *
+ * This file is part of the rsyslog runtime library.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * -or-
+ * see COPYING.ASL20 in the source distribution
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#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
+ */
+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! */
+};
+
+
+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;
+};
+
+
+struct obj_s { /* 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 */
+};
+
+
+/* macros which must be gloablly-visible (because they are used during definition of
+ * other objects.
+ */
+#ifndef NDEBUG /* this means if debug... */
+#include <string.h>
+# 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); \
+ if(strcmp((char*)(((obj_t*)pObj)->pObjInfo->pszID), #objType)) { \
+ dbgprintf("%s:%d ISOBJ assert failure: invalid object type, expected '%s' " \
+ "actual '%s', cookie: %X\n", __FILE__, __LINE__, #objType, \
+ (((obj_t*)pObj)->pObjInfo->pszID), ((obj_t*)(pObj))->iObjCooCKiE); \
+ fprintf(stderr, "%s:%d ISOBJ assert failure: invalid object type, expected '%s' " \
+ "actual '%s', cookie: %X\n", __FILE__, __LINE__, #objType, \
+ (((obj_t*)pObj)->pObjInfo->pszID), ((obj_t*)(pObj))->iObjCooCKiE); \
+ fflush(stderr); \
+ assert(!strcmp((char*)(((obj_t*)pObj)->pObjInfo->pszID), #objType)); \
+ } \
+ assert((unsigned) ((obj_t*)(pObj))->iObjCooCKiE == (unsigned) 0xBADEFEE); \
+ } while(0)
+ /* now the same for pointers to "regular" objects (like wrkrInstanceData) */
+# define PTR_ASSERT_DEF unsigned int _Assert_type;
+# define PTR_ASSERT_SET_TYPE(_ptr, _type) _ptr->_Assert_type = _type
+# define PTR_ASSERT_CHK(_ptr, _type) do { \
+ assert(_ptr != NULL); \
+ if(_ptr->_Assert_type != _type) {\
+ dbgprintf("%s:%d PTR_ASSERT_CHECK failure: invalid pointer type %x, " \
+ "expected %x\n", __FILE__, __LINE__, _ptr->_Assert_type, _type); \
+ fprintf(stderr, "%s:%d PTR_ASSERT_CHECK failure: invalid pointer type %x, " \
+ "expected %x\n", __FILE__, __LINE__, _ptr->_Assert_type, _type); \
+ assert(_ptr->_Assert_type == _type); \
+ } \
+ } 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)
+
+# define PTR_ASSERT_DEF
+# define PTR_ASSERT_SET_TYPE(_ptr, _type)
+# define PTR_ASSERT_CHK(_ptr, _type)
+#endif
+
+/* a set method for *very simple* object accesses. Note that this does
+ * NOT conform to the standard calling conventions and should be
+ * used only if actually nothing can go wrong! -- rgerhards, 2008-04-17
+ */
+#define DEFpropGetMeth(obj, prop, dataType)\
+ dataType obj##Get##prop(void)\
+ { \
+ return pThis->prop = pVal; \
+ }
+
+#define DEFpropSetMethPTR(obj, prop, dataType)\
+ rsRetVal obj##Set##prop(obj##_t *pThis, dataType *pVal)\
+ { \
+ pThis->prop = pVal; \
+ return RS_RET_OK; \
+ }
+#define PROTOTYPEpropSetMethPTR(obj, prop, dataType)\
+ rsRetVal obj##Set##prop(obj##_t *pThis, dataType*)
+#define DEFpropSetMethFP(obj, prop, dataType)\
+ rsRetVal obj##Set##prop(obj##_t *pThis, dataType)\
+ { \
+ 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);\
+ rsRetVal obj##Set##prop(obj##_t *pThis, dataType pVal)\
+ { \
+ 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); \
+ RETiRet; \
+}
+
+/* this defines both the constructor and initializer
+ * rgerhards, 2008-01-10
+ */
+#define BEGINobjConstruct(obj) \
+ static 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); \
+ 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 lengthy 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 PROTOTYPEobjDestruct(OBJ) \
+ rsRetVal OBJ##Destruct(OBJ##_t __attribute__((unused)) **ppThis)
+/* note: we generate a prototype in any case, as this does not hurt but
+ * many modules otherwise seem to miss one, which generates compiler
+ * warnings.
+ */
+#define BEGINobjDestruct(OBJ) \
+ rsRetVal OBJ##Destruct(OBJ##_t __attribute__((unused)) **ppThis);\
+ rsRetVal OBJ##Destruct(OBJ##_t __attribute__((unused)) **ppThis) \
+ { \
+ DEFiRet; \
+ OBJ##_t *pThis;
+
+#define CODESTARTobjDestruct(OBJ) \
+ assert(ppThis != NULL); \
+ pThis = *ppThis; \
+ ISOBJ_TYPE_assert(pThis, OBJ);
+
+/* note: there was a long-time bug in the macro below that lead to *ppThis = NULL
+ * only when the object was actually destructed. I discovered this issue during
+ * introduction of the pRcvFrom property in smsg_t, but it potentially had other
+ * effects, too. I am not sure if some experienced instability resulted from this
+ * bug OR if its fix will cause harm to so-far "correctly" running code. The later
+ * may very well be. Thus I will change it only for the current branch and also
+ * the beta, but not in all old builds. Let's see how things evolve.
+ * rgerhards, 2009-06-30
+ */
+#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; \
+ 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 __attribute__((unused)) *pThis);\
+ rsRetVal obj##DebugPrint(obj##_t __attribute__((unused)) *pThis) \
+ { \
+ DEFiRet; \
+
+#define CODESTARTobjDebugPrint(obj) \
+ assert(pThis != NULL); \
+ ISOBJ_TYPE_assert(pThis, obj); \
+
+#define ENDobjDebugPrint(obj) \
+ RETiRet; \
+ }
+
+/* ------------------------------ object loader system ------------------------------ *
+ * The following code builds a dynamic object loader system. The
+ * root idea is that all objects are dynamically loadable,
+ * 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 <obj>_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.
+ *
+ * rgerhards, 2008-02-21 (initial implementation), 2008-04-17 (update of this note)
+ */
+
+/* this defines the QueryInterface print entry point. Over time, it should be
+ * present in all objects.
+ */
+#define BEGINobjQueryInterface(obj) \
+ rsRetVal obj##QueryInterface(obj##_if_t *pIf);\
+ rsRetVal obj##QueryInterface(obj##_if_t *pIf) \
+ { \
+ DEFiRet; \
+
+#define CODESTARTobjQueryInterface(obj) \
+ assert(pIf != NULL);
+
+#define ENDobjQueryInterface(obj) \
+ RETiRet; \
+ }
+
+#define PROTOTYPEObjQueryInterface(obj) rsRetVal obj##QueryInterface(obj##_if_t *pIf)
+
+
+/* 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, 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); \
+ PROTOTYPEObjQueryInterface(obj)
+
+/* ------------------------------ end object loader system ------------------------------ */
+
+
+#include "modules.h"
+
+#endif /* #ifndef OBJ_TYPES_H_INCLUDED */