summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRainer Gerhards <rgerhards@adiscon.com>2008-03-11 16:43:13 +0000
committerRainer Gerhards <rgerhards@adiscon.com>2008-03-11 16:43:13 +0000
commite946e122d02987552874595f2613c07ce0c0aa23 (patch)
tree4bdf6d726cd80f991e971145f549bc9618c005cc
parenta98aeec6d0e5739ada471ece2b308ea787c3804a (diff)
downloadrsyslog-e946e122d02987552874595f2613c07ce0c0aa23.tar.gz
rsyslog-e946e122d02987552874595f2613c07ce0c0aa23.tar.xz
rsyslog-e946e122d02987552874595f2613c07ce0c0aa23.zip
implemented module unload handling (required a number of interface changes)
-rw-r--r--action.h2
-rw-r--r--conf.c14
-rw-r--r--configure.ac3
-rw-r--r--datetime.c1
-rw-r--r--debug.c2
-rw-r--r--gss-misc.c2
-rw-r--r--module-template.h13
-rw-r--r--modules.c284
-rw-r--r--modules.h32
-rw-r--r--net.c26
-rw-r--r--net.h8
-rw-r--r--obj-types.h54
-rw-r--r--obj.c156
-rw-r--r--obj.h8
-rw-r--r--omdiscard.h2
-rw-r--r--omfile.h2
-rw-r--r--omfwd.c3
-rw-r--r--omfwd.h2
-rw-r--r--omshell.h2
-rw-r--r--omusrmsg.h2
-rw-r--r--plugins/imgssapi/imgssapi.c11
-rw-r--r--plugins/imtcp/imtcp.c7
-rw-r--r--plugins/imudp/imudp.c5
-rw-r--r--queue.c6
-rw-r--r--regexp.c2
-rw-r--r--rsyslog.h3
-rwxr-xr-xstringbuf.c11
-rw-r--r--syslogd.c133
-rw-r--r--syslogd.h1
-rw-r--r--tcps_sess.c10
-rw-r--r--tcpsrv.c30
31 files changed, 679 insertions, 158 deletions
diff --git a/action.h b/action.h
index e949df61..1fa05c15 100644
--- a/action.h
+++ b/action.h
@@ -47,7 +47,7 @@ struct action_s {
int iResumeInterval;/* resume interval for this action */
int iResumeRetryCount;/* how often shall we retry a suspended action? (-1 --> eternal) */
int iNbrResRtry; /* number of retries since last suspend */
- struct moduleInfo *pMod;/* pointer to output module handling this selector */
+ struct modInfo_s *pMod;/* pointer to output module handling this selector */
void *pModData; /* pointer to module data - content is module-specific */
int f_ReduceRepeated;/* reduce repeated lines 0 - no, 1 - yes */
int f_prevcount; /* repetition cnt of prevline */
diff --git a/conf.c b/conf.c
index a00b6290..fd046fb4 100644
--- a/conf.c
+++ b/conf.c
@@ -1160,6 +1160,20 @@ finalize_it:
ENDobjQueryInterface(conf)
+/* exit our class
+ * rgerhards, 2008-03-11
+ */
+BEGINObjClassExit(conf, OBJ_IS_CORE_MODULE) /* CHANGE class also in END MACRO! */
+CODESTARTObjClassExit(conf)
+ /* release objects we no longer need */
+ objRelease(expr, CORE_COMPONENT);
+ objRelease(ctok, CORE_COMPONENT);
+ objRelease(module, CORE_COMPONENT);
+ objRelease(errmsg, CORE_COMPONENT);
+ objRelease(net, LM_NET_FILENAME);
+ENDObjClassExit(conf)
+
+
/* Initialize our class. Must be called as the very first method
* before anything else is called inside this class.
* rgerhards, 2008-02-29
diff --git a/configure.ac b/configure.ac
index eece80b9..e45c1f25 100644
--- a/configure.ac
+++ b/configure.ac
@@ -271,6 +271,9 @@ AC_ARG_ENABLE(debug,
esac],
[enable_debug="no"]
)
+if test "$enable_debug" = "yes"; then
+ AC_DEFINE(DEBUG, 1, [Defined if debug mode is enabled (its easier to check).])
+fi
if test "$enable_debug" = "no"; then
AC_DEFINE(NDEBUG, 1, [Defined if debug mode is disabled.])
fi
diff --git a/datetime.c b/datetime.c
index 1c3b1603..a4817a6d 100644
--- a/datetime.c
+++ b/datetime.c
@@ -37,6 +37,7 @@
#include "rsyslog.h"
#include "obj.h"
+#include "modules.h"
#include "datetime.h"
#include "sysvar.h"
#include "srUtils.h"
diff --git a/debug.c b/debug.c
index 534682d0..44f8bbd0 100644
--- a/debug.c
+++ b/debug.c
@@ -914,7 +914,7 @@ ENDfunc
*/
int dbgEntrFunc(dbgFuncDB_t **ppFuncDB, const char *file, const char *func, int line)
{
- int iStackPtr;
+ int iStackPtr = 0; /* TODO: find some better default, this one hurts the least, but it is not clean */
dbgThrdInfo_t *pThrd = dbgGetThrdInfo();
dbgFuncDBListEntry_t *pFuncDBListEntry;
unsigned int i;
diff --git a/gss-misc.c b/gss-misc.c
index a51b48ac..01d6833d 100644
--- a/gss-misc.c
+++ b/gss-misc.c
@@ -288,5 +288,5 @@ CODESTARTmodInit
*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
/* Initialize all classes that are in our module - this includes ourselfs */
- CHKiRet(gssutilClassInit()); /* must be done after tcps_sess, as we use it */
+ CHKiRet(gssutilClassInit(pModInfo)); /* must be done after tcps_sess, as we use it */
ENDmodInit
diff --git a/module-template.h b/module-template.h
index 3478acd0..900ee3aa 100644
--- a/module-template.h
+++ b/module-template.h
@@ -34,12 +34,15 @@
/* macro to define standard output-module static data members
*/
#define DEF_MOD_STATIC_DATA \
- DEFobjCurrIf(obj) \
static rsRetVal (*omsdRegCFSLineHdlr)();
#define DEF_OMOD_STATIC_DATA \
- DEF_MOD_STATIC_DATA
+ DEF_MOD_STATIC_DATA \
+ DEFobjCurrIf(obj)
#define DEF_IMOD_STATIC_DATA \
+ DEF_MOD_STATIC_DATA \
+ DEFobjCurrIf(obj)
+#define DEF_LMOD_STATIC_DATA \
DEF_MOD_STATIC_DATA
@@ -57,7 +60,9 @@ static rsRetVal modGetType(eModType_t *modType) \
#define MODULE_TYPE_INPUT MODULE_TYPE(eMOD_IN)
#define MODULE_TYPE_OUTPUT MODULE_TYPE(eMOD_OUT)
-#define MODULE_TYPE_LIB MODULE_TYPE(eMOD_LIB)
+#define MODULE_TYPE_LIB \
+ DEF_LMOD_STATIC_DATA \
+ MODULE_TYPE(eMOD_LIB)
/* macro to define a unique module id. This must be able to fit in a void*. The
* module id must be unique inside a running rsyslogd application. It is used to
@@ -385,7 +390,7 @@ static rsRetVal queryEtryPt(uchar *name, rsRetVal (**pEtryPoint)())\
* cached, left-in-memory copy of a previous incarnation.
*/
#define BEGINmodInit(uniqName) \
-rsRetVal modInit##uniqName(int iIFVersRequested __attribute__((unused)), int *ipIFVersProvided, rsRetVal (**pQueryEtryPt)(), rsRetVal (*pHostQueryEtryPt)(uchar*, rsRetVal (**)()))\
+rsRetVal modInit##uniqName(int iIFVersRequested __attribute__((unused)), int *ipIFVersProvided, rsRetVal (**pQueryEtryPt)(), rsRetVal (*pHostQueryEtryPt)(uchar*, rsRetVal (**)()), modInfo_t __attribute__((unused)) *pModInfo)\
{\
DEFiRet; \
rsRetVal (*pObjGetObjInterface)(obj_if_t *pIf);
diff --git a/modules.c b/modules.c
index 5f5f19dd..357a2fe9 100644
--- a/modules.c
+++ b/modules.c
@@ -2,6 +2,13 @@
* This is the implementation of syslogd modules object.
* This object handles plug-ins and build-in modules of all kind.
*
+ * Modules are reference-counted. Anyone who access a module must call
+ * Use() before any function is accessed and Release() when he is done.
+ * When the reference count reaches 0, rsyslog unloads the module (that
+ * may be changed in the future to cache modules). Rsyslog does NOT
+ * unload modules with a reference count > 0, even if the unload
+ * method is called!
+ *
* File begun on 2007-07-22 by RGerhards
*
* Copyright 2007 Rainer Gerhards and Adiscon GmbH.
@@ -54,6 +61,106 @@ static modInfo_t *pLoadedModulesLast = NULL; /* tail-pointer */
uchar *pModDir = NULL; /* read-only after startup */
+#ifdef DEBUG
+/* we add some home-grown support to track our users (and detect who does not free us). In
+ * the long term, this should probably be migrated into debug.c (TODO). -- rgerhards, 2008-03-11
+ */
+
+/* add a user to the current list of users (always at the root) */
+static void
+modUsrAdd(modInfo_t *pThis, char *pszUsr)
+{
+ modUsr_t *pUsr;
+
+ BEGINfunc
+ if((pUsr = calloc(1, sizeof(modUsr_t))) == NULL)
+ goto finalize_it;
+
+ if((pUsr->pszFile = strdup(pszUsr)) == NULL) {
+ free(pUsr);
+ goto finalize_it;
+ }
+
+ if(pThis->pModUsrRoot != NULL) {
+ pUsr->pNext = pThis->pModUsrRoot;
+ }
+ pThis->pModUsrRoot = pUsr;
+
+finalize_it:
+ ENDfunc
+}
+
+
+/* remove a user from the current user list
+ * rgerhards, 2008-03-11
+ */
+static void
+modUsrDel(modInfo_t *pThis, char *pszUsr)
+{
+ modUsr_t *pUsr;
+ modUsr_t *pPrev = NULL;
+
+ for(pUsr = pThis->pModUsrRoot ; pUsr != NULL ; pUsr = pUsr->pNext) {
+ if(!strcmp(pUsr->pszFile, pszUsr))
+ break;
+ else
+ pPrev = pUsr;
+ }
+
+ if(pUsr == NULL) {
+ dbgprintf("oops - tried to delete user %s from module %s and it wasn't registered as one...\n",
+ pszUsr, pThis->pszName);
+ } else {
+ if(pPrev == NULL) {
+ /* This was at the root! */
+ pThis->pModUsrRoot = pUsr->pNext;
+ } else {
+ pPrev->pNext = pUsr->pNext;
+ }
+ /* free ressources */
+ free(pUsr->pszFile);
+ free(pUsr);
+ pUsr = NULL; /* just to make sure... */
+ }
+}
+
+
+/* print a short list all all source files using the module in question
+ * rgerhards, 2008-03-11
+ */
+static void
+modUsrPrint(modInfo_t *pThis)
+{
+ modUsr_t *pUsr;
+
+ for(pUsr = pThis->pModUsrRoot ; pUsr != NULL ; pUsr = pUsr->pNext) {
+ dbgprintf("\tmodule %s is currently in use by file %s\n",
+ pThis->pszName, pUsr->pszFile);
+ }
+}
+
+
+/* print all loaded modules and who is accessing them. This is primarily intended
+ * to be called at end of run to detect "module leaks" and who is causing them.
+ * rgerhards, 2008-03-11
+ */
+//static void
+void
+modUsrPrintAll(void)
+{
+ modInfo_t *pMod;
+
+ BEGINfunc
+ for(pMod = pLoadedModules ; pMod != NULL ; pMod = pMod->pNext) {
+ dbgprintf("printing users of loadable module %s, refcount %u, ptr %p, type %d\n", pMod->pszName, pMod->uRefCnt, pMod, pMod->eType);
+ modUsrPrint(pMod);
+ }
+ ENDfunc
+}
+
+#endif /* #ifdef DEBUG */
+
+
/* Construct a new module object
*/
static rsRetVal moduleConstruct(modInfo_t **pThis)
@@ -78,6 +185,7 @@ static rsRetVal moduleConstruct(modInfo_t **pThis)
*/
static void moduleDestruct(modInfo_t *pThis)
{
+ assert(pThis != NULL);
if(pThis->pszName != NULL)
free(pThis->pszName);
if(pThis->pModHdlr != NULL)
@@ -145,6 +253,7 @@ addModToList(modInfo_t *pThis)
pLoadedModules = pLoadedModulesLast = pThis;
} else {
/* there already exist entries */
+ pThis->pPrev = pLoadedModulesLast;
pLoadedModulesLast->pNext = pThis;
pLoadedModulesLast = pThis;
}
@@ -196,14 +305,23 @@ static modInfo_t *GetNxtType(modInfo_t *pThis, eModType_t rqtdType)
* been destroyed. In the case of output modules, this happens when the
* rule set is being destroyed. When we implement other module types, we
* need to think how we handle it there (and if we have any instance data).
+ * rgerhards, 2008-03-10: reject unload request if the module has a reference
+ * count > 0.
*/
-static rsRetVal modPrepareUnload(modInfo_t *pThis)
+static rsRetVal
+modPrepareUnload(modInfo_t *pThis)
{
DEFiRet;
void *pModCookie;
assert(pThis != NULL);
+ if(pThis->uRefCnt > 0) {
+ dbgprintf("rejecting unload of module '%s' because it has a refcount of %d\n",
+ pThis->pszName, pThis->uRefCnt);
+ ABORT_FINALIZE(RS_RET_MODULE_STILL_REFERENCED);
+ }
+
CHKiRet(pThis->modGetID(&pModCookie));
pThis->modExit(); /* tell the module to get ready for unload */
CHKiRet(unregCfSysLineHdlrs4Owner(pModCookie));
@@ -217,7 +335,7 @@ finalize_it:
* everything needed to fully initialize the module.
*/
static rsRetVal
-doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)()), uchar *name, void *pModHdlr)
+doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_t*), uchar *name, void *pModHdlr)
{
DEFiRet;
modInfo_t *pNew = NULL;
@@ -230,7 +348,7 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)()), uchar *
ABORT_FINALIZE(iRet);
}
- CHKiRet((*modInit)(CURR_MOD_IF_VERSION, &pNew->iIFVers, &pNew->modQueryEtryPt, queryHostEtryPt));
+ CHKiRet((*modInit)(CURR_MOD_IF_VERSION, &pNew->iIFVers, &pNew->modQueryEtryPt, queryHostEtryPt, pNew));
if(pNew->iIFVers != CURR_MOD_IF_VERSION) {
ABORT_FINALIZE(RS_RET_MISSING_INTERFACE);
@@ -328,95 +446,71 @@ static void modPrintList(void)
}
-/* unload all modules and free module linked list
- * rgerhards, 2007-08-09
- */
-static rsRetVal modUnloadAndDestructAll(void)
-{
- DEFiRet;
- modInfo_t *pMod;
- modInfo_t *pModPrev;
-
- pMod = GetNxt(NULL);
- while(pMod != NULL) {
- pModPrev = pMod;
- pMod = GetNxt(pModPrev); /* get next */
- /* TODO: library modules are currently never unloaded! */
- if(pModPrev->eType == eMOD_LIB) {
- dbgprintf("NOT unloading library module %s\n", modGetName(pModPrev));
- } else {
- /* now we can destroy the previous module */
- dbgprintf("Unloading module %s\n", modGetName(pModPrev));
- modPrepareUnload(pModPrev);
- moduleDestruct(pModPrev);
- }
- }
-
- /* indicate list is now empty */
- pLoadedModules = NULL;
- pLoadedModulesLast = NULL;
-
- RETiRet;
-}
-
-
/* unlink and destroy a module. The caller must provide a pointer to the module
* itself as well as one to its immediate predecessor.
* rgerhards, 2008-02-26
*/
static rsRetVal
-modUnlinkAndDestroy(modInfo_t *pThis, modInfo_t *pPrev)
+modUnlinkAndDestroy(modInfo_t *pThis)
{
DEFiRet;
+ /* first check if we are permitted to unload */
+ if(pThis->eType == eMOD_LIB) {
+ if(pThis->uRefCnt > 0) {
+ dbgprintf("module %s NOT unloaded because it still has a refcount of %u\n",
+ pThis->pszName, pThis->uRefCnt);
+# ifdef DEBUG
+ modUsrPrintAll();
+# endif
+ ABORT_FINALIZE(RS_RET_MODULE_STILL_REFERENCED);
+ }
+ }
+
/* we need to unlink the module before we can destruct it -- rgerhards, 2008-02-26 */
- if(pPrev == NULL) {
+ if(pThis->pPrev == NULL) {
/* module is root, so we need to set a new root */
pLoadedModules = pThis->pNext;
} else {
- pPrev->pNext = pThis->pNext;
+ pThis->pPrev->pNext = pThis->pNext;
}
- /* check if we need to update the "last" pointer */
- if(pLoadedModulesLast == pThis) {
- pLoadedModulesLast = pPrev;
+ if(pThis->pNext == NULL) {
+ pLoadedModulesLast = NULL;
+ } else {
+ pThis->pNext->pPrev = pThis->pPrev;
}
/* finally, we are ready for the module to go away... */
dbgprintf("Unloading module %s\n", modGetName(pThis));
- modPrepareUnload(pThis);
+ CHKiRet(modPrepareUnload(pThis));
moduleDestruct(pThis);
+finalize_it:
RETiRet;
}
-/* unload dynamically loaded modules
+/* unload all loaded modules of a specific type (use eMOD_ALL if you want to
+ * unload all module types). The unload happens only if the module is no longer
+ * referenced. So some modules may survive this call.
+ * rgerhards, 2008-03-11
*/
-static rsRetVal modUnloadAndDestructDynamic(void)
+static rsRetVal
+modUnloadAndDestructAll(eModLinkType_t modLinkTypesToUnload)
{
DEFiRet;
modInfo_t *pMod;
modInfo_t *pModCurr; /* module currently being processed */
- modInfo_t *pModPrev; /* last module in active linked list */
- pModPrev = NULL; /* we do not yet have a previous module */
pMod = GetNxt(NULL);
while(pMod != NULL) {
pModCurr = pMod;
pMod = GetNxt(pModCurr); /* get next */
- /* now we can destroy the previous module */
- /* TODO: library modules are currently never unloaded! */
- if(pModCurr->eType == eMOD_LIB) {
- dbgprintf("NOT unloading library module %s\n", modGetName(pModCurr));
- } else {
- if(pModCurr->eLinkType != eMOD_LINK_STATIC) {
- modUnlinkAndDestroy(pModCurr, pModPrev);
- } else {
- pModPrev = pModCurr; /* don't delete, so this is the new prev ptr */
- }
- }
+ if(modLinkTypesToUnload == eMOD_LINK_ALL || pModCurr->eLinkType == modLinkTypesToUnload) {
+ modUnlinkAndDestroy(pModCurr);
}
+ }
RETiRet;
}
@@ -534,6 +628,79 @@ SetModDir(uchar *pszModDir)
}
+/* Reference-Counting object access: add 1 to the current reference count. Must be
+ * called by anyone interested in using a module. -- rgerhards, 20080-03-10
+ */
+static rsRetVal
+Use(char *srcFile, modInfo_t *pThis)
+{
+ DEFiRet;
+
+ assert(pThis != NULL);
+ pThis->uRefCnt++;
+ dbgprintf("source file %s requested reference for module '%s', reference count now %u\n",
+ srcFile, pThis->pszName, pThis->uRefCnt);
+
+# ifdef DEBUG
+ modUsrAdd(pThis, srcFile);
+# endif
+
+ RETiRet;
+
+}
+
+
+/* Reference-Counting object access: subract one from the current refcount. Must
+ * by called by anyone who no longer needs a module. If count reaches 0, the
+ * module is unloaded. -- rgerhards, 20080-03-10
+ */
+static rsRetVal
+Release(char *srcFile, modInfo_t **ppThis)
+{
+ DEFiRet;
+ modInfo_t *pThis;
+
+ assert(ppThis != NULL);
+ pThis = *ppThis;
+ assert(pThis != NULL);
+ if(pThis->uRefCnt == 0) {
+ /* oops, we are already at 0? */
+ dbgprintf("internal error: module '%s' already has a refcount of 0 (released by %s)!\n",
+ pThis->pszName, srcFile);
+ } else {
+ --pThis->uRefCnt;
+ dbgprintf("file %s released module '%s', reference count now %u\n",
+ srcFile, pThis->pszName, pThis->uRefCnt);
+# ifdef DEBUG
+ modUsrDel(pThis, srcFile);
+ modUsrPrint(pThis);
+# endif
+ }
+
+ if(pThis->uRefCnt == 0) {
+ /* we have a zero refcount, so we must unload the module */
+ dbgprintf("module '%s' has zero reference count, unloading...\n", pThis->pszName);
+ modUnlinkAndDestroy(pThis);
+ *ppThis = NULL; /* nobody can access it any longer! */
+ }
+
+ RETiRet;
+
+}
+
+
+/* exit our class
+ * rgerhards, 2008-03-11
+ */
+BEGINObjClassExit(module, OBJ_IS_LOADABLE_MODULE) /* CHANGE class also in END MACRO! */
+CODESTARTObjClassExit(module)
+ /* release objects we no longer need */
+ objRelease(errmsg, CORE_COMPONENT);
+
+ modUsrPrintAll(); /* debug aid - TODO: integrate with debug.c, at least the settings! */
+ENDObjClassExit(module)
+
+
/* queryInterface function
* rgerhards, 2008-03-05
*/
@@ -554,10 +721,11 @@ CODESTARTobjQueryInterface(module)
pIf->GetStateName = modGetStateName;
pIf->PrintList = modPrintList;
pIf->UnloadAndDestructAll = modUnloadAndDestructAll;
- pIf->UnloadAndDestructDynamic = modUnloadAndDestructDynamic;
pIf->doModInit = doModInit;
pIf->SetModDir = SetModDir;
pIf->Load = Load;
+ pIf->Use = Use;
+ pIf->Release = Release;
finalize_it:
ENDobjQueryInterface(module)
diff --git a/modules.h b/modules.h
index e354ae05..7efe01f8 100644
--- a/modules.h
+++ b/modules.h
@@ -42,8 +42,9 @@
* It can be used by any module which want's to simply prevent version conflicts
* and does not intend to do specific old-version emulations.
* rgerhards, 2008-03-04
+ * version 3 adds modInfo_t ptr to call of modInit -- rgerhards, 2008-03-10
*/
-#define CURR_MOD_IF_VERSION 2
+#define CURR_MOD_IF_VERSION 3
typedef enum eModType_ {
eMOD_IN, /* input module */
@@ -51,19 +52,31 @@ typedef enum eModType_ {
eMOD_LIB /* library module - this module provides one or many interfaces */
} eModType_t;
+
+#ifdef DEBUG
+typedef struct modUsr_s {
+ struct modUsr_s *pNext;
+ char *pszFile;
+} modUsr_t;
+#endif
+
+
/* how is this module linked? */
typedef enum eModLinkType_ {
eMOD_LINK_STATIC,
eMOD_LINK_DYNAMIC_UNLOADED, /* dynalink module, currently not loaded */
- eMOD_LINK_DYNAMIC_LOADED /* dynalink module, currently loaded */
+ eMOD_LINK_DYNAMIC_LOADED, /* dynalink module, currently loaded */
+ eMOD_LINK_ALL /* special: all linkage types, e.g. for unload */
} eModLinkType_t;
-typedef struct moduleInfo {
- struct moduleInfo *pNext; /* support for creating a linked module list */
+typedef struct modInfo_s {
+ struct modInfo_s *pPrev; /* support for creating a double linked module list */
+ struct modInfo_s *pNext; /* support for creating a linked module list */
int iIFVers; /* Interface version of module */
eModType_t eType; /* type of this module */
eModLinkType_t eLinkType;
uchar* pszName; /* printable module name, e.g. for dbgprintf */
+ unsigned uRefCnt; /* reference count for this module; 0 -> may be unloaded */
/* functions supported by all types of modules */
rsRetVal (*modInit)(int, int*, rsRetVal(**)()); /* initialize the module */
/* be sure to support version handshake! */
@@ -100,6 +113,12 @@ typedef struct moduleInfo {
} fm;
} mod;
void *pModHdlr; /* handler to the dynamic library holding the module */
+# ifdef DEBUG
+ /* we add some home-grown support to track our users (and detect who does not free us). In
+ * the long term, this should probably be migrated into debug.c (TODO). -- rgerhards, 2008-03-11
+ */
+ modUsr_t *pModUsrRoot;
+# endif
} modInfo_t;
/* interfaces */
@@ -108,9 +127,10 @@ BEGINinterface(module) /* name must also be changed in ENDinterface macro! */
modInfo_t *(*GetNxtType)(modInfo_t *pThis, eModType_t rqtdType);
uchar *(*GetName)(modInfo_t *pThis);
uchar *(*GetStateName)(modInfo_t *pThis);
+ rsRetVal (*Use)(char *srcFile, modInfo_t *pThis); /**< must be called before a module is used (ref counting) */
+ rsRetVal (*Release)(char *srcFile, modInfo_t **ppThis); /**< release a module (ref counting) */
void (*PrintList)(void);
- rsRetVal (*UnloadAndDestructAll)(void);
- rsRetVal (*UnloadAndDestructDynamic)(void);
+ rsRetVal (*UnloadAndDestructAll)(eModLinkType_t modLinkTypesToUnload);
rsRetVal (*doModInit)(rsRetVal (*modInit)(), uchar *name, void *pModHdlr);
rsRetVal (*Load)(uchar *name);
rsRetVal (*SetModDir)(uchar *name);
diff --git a/net.c b/net.c
index 74b27806..12058349 100644
--- a/net.c
+++ b/net.c
@@ -546,7 +546,7 @@ static inline int MaskCmp(struct NetAddr *pAllow, uint8_t bits, struct sockaddr
* returns 1, if the sender is allowed, 0 otherwise.
* rgerhards, 2005-09-26
*/
-int isAllowedSender(struct AllowedSenders *pAllowRoot, struct sockaddr *pFrom, const char *pszFromHost)
+static int isAllowedSender(struct AllowedSenders *pAllowRoot, struct sockaddr *pFrom, const char *pszFromHost)
{
struct AllowedSenders *pAllow;
@@ -577,10 +577,11 @@ int isAllowedSender(struct AllowedSenders *pAllowRoot, struct sockaddr *pFrom, c
* It still needs to be a bit better adapted to rsyslog.
* rgerhards 2005-09-19
*/
-#ifndef BSD
#include <sys/utsname.h>
-int should_use_so_bsdcompat(void)
+static int
+should_use_so_bsdcompat(void)
{
+#ifndef BSD
static int init_done;
static int so_bsdcompat_is_obsolete;
@@ -608,10 +609,10 @@ int should_use_so_bsdcompat(void)
so_bsdcompat_is_obsolete = 1;
}
return !so_bsdcompat_is_obsolete;
-}
#else /* #ifndef BSD */
-#define should_use_so_bsdcompat() 1
+ return 1;
#endif /* #ifndef BSD */
+}
#ifndef SO_BSDCOMPAT
/* this shall prevent compiler errors due to undfined name */
#define SO_BSDCOMPAT 0
@@ -1046,10 +1047,22 @@ CODESTARTobjQueryInterface(net)
pIf->debugListenInfo = debugListenInfo;
pIf->create_udp_socket = create_udp_socket;
pIf->closeUDPListenSockets = closeUDPListenSockets;
+ pIf->isAllowedSender = isAllowedSender;
+ pIf->should_use_so_bsdcompat = should_use_so_bsdcompat;
finalize_it:
ENDobjQueryInterface(net)
+/* exit our class
+ * rgerhards, 2008-03-10
+ */
+BEGINObjClassExit(net, OBJ_IS_LOADABLE_MODULE) /* CHANGE class also in END MACRO! */
+CODESTARTObjClassExit(net)
+ /* release objects we no longer need */
+ objRelease(errmsg, CORE_COMPONENT);
+ENDObjClassExit(net)
+
+
/* Initialize the net class. Must be called as the very first method
* before anything else is called inside this class.
* rgerhards, 2008-02-19
@@ -1067,6 +1080,7 @@ ENDObjClassInit(net)
BEGINmodExit
CODESTARTmodExit
+ netClassExit();
ENDmodExit
@@ -1081,7 +1095,7 @@ CODESTARTmodInit
*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
/* Initialize all classes that are in our module - this includes ourselfs */
- CHKiRet(netClassInit()); /* must be done after tcps_sess, as we use it */
+ CHKiRet(netClassInit(pModInfo)); /* must be done after tcps_sess, as we use it */
ENDmodInit
/* vi:set ai:
*/
diff --git a/net.h b/net.h
index cd2b22cd..2004dcfc 100644
--- a/net.h
+++ b/net.h
@@ -48,12 +48,6 @@ struct NetAddr {
} addr;
};
-#ifndef BSD
- int should_use_so_bsdcompat(void);
-#else
-# define should_use_so_bsdcompat() 1
-#endif /* #ifndef BSD */
-
#ifndef SO_BSDCOMPAT
/* this shall prevent compiler errors due to undfined name */
# define SO_BSDCOMPAT 0
@@ -102,6 +96,8 @@ BEGINinterface(net) /* name must also be changed in ENDinterface macro! */
void (*debugListenInfo)(int fd, char *type);
int *(*create_udp_socket)(uchar *hostname, uchar *LogPort, int bIsServer);
void (*closeUDPListenSockets)(int *finet);
+ int (*isAllowedSender)(struct AllowedSenders *pAllowRoot, struct sockaddr *pFrom, const char *pszFromHost);
+ int (*should_use_so_bsdcompat)(void);
/* data memebers - these should go away over time... TODO */
int *pACLAddHostnameOnFail; /* add hostname to acl when DNS resolving has failed */
int *pACLDontResolve; /* add hostname to acl instead of resolving it to IP(s) */
diff --git a/obj-types.h b/obj-types.h
index aaca5cca..afbe1a8b 100644
--- a/obj-types.h
+++ b/obj-types.h
@@ -76,6 +76,7 @@ typedef struct objInfo_s {
uchar *pszName;
rsRetVal (*objMethods[OBJ_NUM_METHODS])();
rsRetVal (*QueryIF)(interface_t*);
+ struct modInfo_s *pModInfo;
} objInfo_t;
@@ -149,24 +150,24 @@ typedef struct obj { /* the dummy struct that each derived class can be casted t
#define INTERFACEpropSetMeth(obj, prop, dataType)\
rsRetVal (*Set##prop)(obj##_t *pThis, dataType)
/* class initializer */
-#define PROTOTYPEObjClassInit(objName) rsRetVal objName##ClassInit(void)
+#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
+#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(void) \
+rsRetVal objName##ClassInit(struct modInfo_s *pModInfo) \
{ \
DEFiRet; \
- if(objType == OBJ_IS_CORE_MODULE) { \
+ 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));
+ (rsRetVal (*)(interface_t*))objName##QueryInterface, pModInfo)); \
#define ENDObjClassInit(objName) \
iRet = obj.RegisterObj((uchar*)#objName, pObjInfoOBJ); \
@@ -178,16 +179,16 @@ finalize_it: \
* TODO: consolidate the two -- rgerhards, 2008-02-29
*/
#define BEGINAbstractObjClassInit(objName, objVers, objType) \
-rsRetVal objName##ClassInit(void) \
+rsRetVal objName##ClassInit(struct modInfo_s *pModInfo) \
{ \
DEFiRet; \
- if(objType == OBJ_IS_CORE_MODULE) { \
+ 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));
+ (rsRetVal (*)(interface_t*))objName##QueryInterface, pModInfo));
#define ENDObjClassInit(objName) \
iRet = obj.RegisterObj((uchar*)#objName, pObjInfoOBJ); \
@@ -195,6 +196,24 @@ 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
*/
@@ -342,12 +361,23 @@ finalize_it: \
/* 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.
+ * 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 \
@@ -359,15 +389,17 @@ finalize_it: \
* the beginning
*/
#define DEFobjCurrIf(obj) \
- static obj##_if_t obj = { .ifVersion = obj##CURR_IF_VERSION, .ifIsLoaded = 0 };
+ 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);
+ PROTOTYPEObjClassInit(obj); \
+ PROTOTYPEObjClassExit(obj);
/* ------------------------------ end object loader system ------------------------------ */
+#include "modules.h"
#endif /* #ifndef OBJ_TYPES_H_INCLUDED */
diff --git a/obj.c b/obj.c
index b7ae5332..9156be9f 100644
--- a/obj.c
+++ b/obj.c
@@ -130,7 +130,7 @@ static rsRetVal objInfoNotImplementedDummy(void __attribute__((unused)) *pThis)
static rsRetVal
InfoConstruct(objInfo_t **ppThis, uchar *pszID, int iObjVers,
rsRetVal (*pConstruct)(void *), rsRetVal (*pDestruct)(void *),
- rsRetVal (*pQueryIF)(interface_t*))
+ rsRetVal (*pQueryIF)(interface_t*), modInfo_t *pModInfo)
{
DEFiRet;
int i;
@@ -146,6 +146,7 @@ InfoConstruct(objInfo_t **ppThis, uchar *pszID, int iObjVers,
pThis->pszName = (uchar*)strdup((char*)pszID); /* it's OK if we have NULL ptr, GetName() will deal with that! */
pThis->iObjVers = iObjVers;
pThis->QueryIF = pQueryIF;
+ pThis->pModInfo = pModInfo;
pThis->objMethods[0] = pConstruct;
pThis->objMethods[1] = pDestruct;
@@ -160,6 +161,28 @@ finalize_it:
}
+/* destruct the objInfo object - must be done only when no more instances exist.
+ * rgerhards, 2008-03-10
+ */
+static rsRetVal
+InfoDestruct(objInfo_t **ppThis)
+{
+ DEFiRet;
+ objInfo_t *pThis;
+
+ assert(ppThis != NULL);
+ pThis = *ppThis;
+ assert(pThis != NULL);
+
+ if(pThis->pszName != NULL)
+ free(pThis->pszName);
+ free(pThis);
+ *ppThis = NULL;
+
+ RETiRet;
+}
+
+
/* set a method handler */
static rsRetVal
InfoSetMethod(objInfo_t *pThis, objMethod_t objMethod, rsRetVal (*pHandler)(void*))
@@ -978,8 +1001,8 @@ FindObjInfo(cstr_t *pstrOID, objInfo_t **ppInfo)
bFound = 0;
i = 0;
- while(!bFound && i < OBJ_NUM_IDS && arrObjInfo[i] != NULL) {
- if(!rsCStrSzStrCmp(pstrOID, arrObjInfo[i]->pszID, arrObjInfo[i]->lenID)) {
+ while(!bFound && i < OBJ_NUM_IDS) {
+ if(arrObjInfo[i] != NULL && !rsCStrSzStrCmp(pstrOID, arrObjInfo[i]->pszID, arrObjInfo[i]->lenID)) {
bFound = 1;
break;
}
@@ -993,7 +1016,8 @@ FindObjInfo(cstr_t *pstrOID, objInfo_t **ppInfo)
finalize_it:
if(iRet == RS_RET_OK) {
- dbgprintf("caller requested object '%s', found at index %d\n", (*ppInfo)->pszID, i);
+ /* DEV DEBUG ONLY dbgprintf("caller requested object '%s', found at index %d\n", (*ppInfo)->pszID, i);*/
+ /*EMPTY BY INTENSION*/;
} else {
dbgprintf("caller requested object '%s', not found (iRet %d)\n", rsCStrGetSzStr(pstrOID), iRet);
}
@@ -1045,6 +1069,46 @@ finalize_it:
}
+/* deregister a classes' info pointer, usually called because the class is unloaded.
+ * After deregistration, the class can no longer be accessed, except if it is reloaded.
+ * rgerhards, 2008-03-10
+ */
+static rsRetVal
+UnregisterObj(uchar *pszObjName, objInfo_t *pInfo)
+{
+ DEFiRet;
+ int bFound;
+ int i;
+
+ assert(pszObjName != NULL);
+ assert(pInfo != NULL);
+
+ bFound = 0;
+ i = 0;
+ while(!bFound && i < OBJ_NUM_IDS) {
+ if( arrObjInfo[i] != NULL
+ && !strcmp((char*)arrObjInfo[i]->pszID, (char*)pszObjName)) {
+ bFound = 1;
+ break;
+ }
+ ++i;
+ }
+
+ if(!bFound)
+ ABORT_FINALIZE(RS_RET_OBJ_NOT_REGISTERED);
+
+ InfoDestruct(&arrObjInfo[i]);
+ dbgprintf("object '%s' successfully unregistered with index %d\n", pszObjName, i);
+
+finalize_it:
+ if(iRet != RS_RET_OK) {
+ dbgprintf("unregistering object '%s' failed with error code %d\n", pszObjName, iRet);
+ }
+
+ 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.
@@ -1090,6 +1154,12 @@ UseObj(char *srcFile, uchar *pObjName, uchar *pObjFile, interface_t *pIf)
FINALIZE; /* give up */
}
+ /* if we reach this point, we have a valid pObjInfo */
+ //if(pObjInfo->pModInfo != NULL) { /* NULL means core module */
+ if(pObjFile != NULL) { /* NULL means core module */
+ module.Use(srcFile, pObjInfo->pModInfo); /* increase refcount */
+ }
+
CHKiRet(pObjInfo->QueryIF(pIf));
pIf->ifIsLoaded = 1; /* we are happy */
@@ -1101,6 +1171,49 @@ finalize_it:
}
+/* This function shall be called when a caller is done with an object. Its primary
+ * purpose is to keep the reference count correct, which is highly important for
+ * modules residing in loadable modules.
+ * rgerhards, 2008-03-10
+ */
+static rsRetVal
+ReleaseObj(char *srcFile, uchar *pObjName, uchar *pObjFile, interface_t *pIf)
+{
+ DEFiRet;
+ cstr_t *pStr = NULL;
+ objInfo_t *pObjInfo;
+
+
+ dbgprintf("source file %s requests object '%s', ifIsLoaded %d\n", srcFile, pObjName, pIf->ifIsLoaded);
+
+ if(pObjFile == NULL)
+ FINALIZE; /* if it is not a lodable module, we do not need to do anything... */
+
+ if(pIf->ifIsLoaded == 0) {
+ ABORT_FINALIZE(RS_RET_OK); /* we are already set */ /* TODO: flag an error? */
+ }
+ if(pIf->ifIsLoaded == 2) {
+ pIf->ifIsLoaded = 0; /* clean up */
+ ABORT_FINALIZE(RS_RET_OK); /* we had a load error and can not continue */
+ }
+
+ CHKiRet(rsCStrConstructFromszStr(&pStr, pObjName));
+ CHKiRet(FindObjInfo(pStr, &pObjInfo));
+
+ /* if we reach this point, we have a valid pObjInfo */
+ //if(pObjInfo->pModInfo != NULL) { /* NULL means core module */
+ module.Release(srcFile, &pObjInfo->pModInfo); /* decrease refcount */
+
+ pIf->ifIsLoaded = 0; /* indicated "no longer valid" */
+
+finalize_it:
+ if(pStr != NULL)
+ rsCStrDestruct(&pStr);
+
+ RETiRet;
+}
+
+
/* queryInterface function
* rgerhards, 2008-02-29
*/
@@ -1116,6 +1229,7 @@ CODESTARTobjQueryInterface(obj)
* of course, also affects the "if" above).
*/
pIf->UseObj = UseObj;
+ pIf->ReleaseObj = ReleaseObj;
pIf->InfoConstruct = InfoConstruct;
pIf->DestructObjSelf = DestructObjSelf;
pIf->BeginSerializePropBag = BeginSerializePropBag;
@@ -1124,6 +1238,7 @@ CODESTARTobjQueryInterface(obj)
pIf->SerializeProp = SerializeProp;
pIf->EndSerialize = EndSerialize;
pIf->RegisterObj = RegisterObj;
+ pIf->UnregisterObj = UnregisterObj;
pIf->Deserialize = Deserialize;
pIf->DeserializePropBag = DeserializePropBag;
pIf->SetName = SetName;
@@ -1149,6 +1264,29 @@ objGetObjInterface(obj_if_t *pIf)
}
+/* exit our class
+ * rgerhards, 2008-03-11
+ */
+rsRetVal
+objClassExit(void)
+{
+ DEFiRet;
+ /* release objects we no longer need */
+ objRelease(var, CORE_COMPONENT);
+ objRelease(module, CORE_COMPONENT);
+ objRelease(errmsg, CORE_COMPONENT);
+
+ /* TODO: implement the class exits! */
+#if 0
+ errmsgClassInit(pModInfo);
+ cfsyslineInit(pModInfo);
+ varClassInit(pModInfo);
+#endif
+ moduleClassExit();
+ RETiRet;
+}
+
+
/* initialize our own class
* Please note that this also initializes those classes that we rely on.
* Though this is a bit dirty, we need to do it - otherwise we can't get
@@ -1158,7 +1296,7 @@ objGetObjInterface(obj_if_t *pIf)
* rgerhards, 2008-02-29
*/
rsRetVal
-objClassInit(void)
+objClassInit(modInfo_t *pModInfo)
{
DEFiRet;
int i;
@@ -1174,10 +1312,10 @@ objClassInit(void)
CHKiRet(objGetObjInterface(&obj)); /* get ourselves ;) */
/* init classes we use (limit to as few as possible!) */
- CHKiRet(errmsgClassInit());
- CHKiRet(cfsyslineInit());
- CHKiRet(varClassInit());
- CHKiRet(moduleClassInit());
+ CHKiRet(errmsgClassInit(pModInfo));
+ CHKiRet(cfsyslineInit(pModInfo));
+ CHKiRet(varClassInit(pModInfo));
+ CHKiRet(moduleClassInit(pModInfo));
CHKiRet(objUse(var, CORE_COMPONENT));
CHKiRet(objUse(module, CORE_COMPONENT));
CHKiRet(objUse(errmsg, CORE_COMPONENT));
diff --git a/obj.h b/obj.h
index cf7835a5..a9d676d5 100644
--- a/obj.h
+++ b/obj.h
@@ -92,10 +92,12 @@
/* interfaces */
BEGINinterface(obj) /* name must also be changed in ENDinterface macro! */
- rsRetVal (*UseObj)(char *srcFile, uchar *pObjName, uchar *pObjFile, interface_t *ppIf);
+ //rsRetVal (*UseObj)(char *srcFile, uchar *pObjName, uchar *pMyLib, uchar *pObjFile, interface_t *pIf);
+ rsRetVal (*UseObj)(char *srcFile, uchar *pObjName, uchar *pObjFile, interface_t *pIf);
+ rsRetVal (*ReleaseObj)(char *srcFile, uchar *pObjName, uchar *pObjFile, interface_t *pIf);
rsRetVal (*InfoConstruct)(objInfo_t **ppThis, uchar *pszID, int iObjVers,
rsRetVal (*pConstruct)(void *), rsRetVal (*pDestruct)(void *),
- rsRetVal (*pQueryIF)(interface_t*));
+ rsRetVal (*pQueryIF)(interface_t*), modInfo_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*));
@@ -103,6 +105,7 @@ BEGINinterface(obj) /* name must also be changed in ENDinterface macro! */
rsRetVal (*SerializeProp)(strm_t *pStrm, uchar *pszPropName, propType_t propType, void *pUsr);
rsRetVal (*EndSerialize)(strm_t *pStrm);
rsRetVal (*RegisterObj)(uchar *pszObjName, objInfo_t *pInfo);
+ rsRetVal (*UnregisterObj)(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);
@@ -117,5 +120,6 @@ ENDinterface(obj)
*/
rsRetVal objGetObjInterface(obj_if_t *pIf);
PROTOTYPEObjClassInit(obj);
+PROTOTYPEObjClassExit(obj);
#endif /* #ifndef OBJ_H_INCLUDED */
diff --git a/omdiscard.h b/omdiscard.h
index 06e39f88..116308a4 100644
--- a/omdiscard.h
+++ b/omdiscard.h
@@ -26,7 +26,7 @@
#define OMDISCARD_H_INCLUDED 1
/* prototypes */
-rsRetVal modInitDiscard(int iIFVersRequested __attribute__((unused)), int *ipIFVersProvided, rsRetVal (**pQueryEtryPt)(), rsRetVal (*pHostQueryEtryPt)(uchar*, rsRetVal (**)()));
+rsRetVal modInitDiscard(int iIFVersRequested __attribute__((unused)), int *ipIFVersProvided, rsRetVal (**pQueryEtryPt)(), rsRetVal (*pHostQueryEtryPt)(uchar*, rsRetVal (**)()), modInfo_t*);
#endif /* #ifndef OMDISCARD_H_INCLUDED */
/*
diff --git a/omfile.h b/omfile.h
index 765173ff..03e081f3 100644
--- a/omfile.h
+++ b/omfile.h
@@ -26,7 +26,7 @@
#define OMFILE_H_INCLUDED 1
/* prototypes */
-rsRetVal modInitFile(int iIFVersRequested __attribute__((unused)), int *ipIFVersProvided, rsRetVal (**pQueryEtryPt)(), rsRetVal (*pHostQueryEtryPt)(uchar*, rsRetVal (**)()));
+rsRetVal modInitFile(int iIFVersRequested __attribute__((unused)), int *ipIFVersProvided, rsRetVal (**pQueryEtryPt)(), rsRetVal (*pHostQueryEtryPt)(uchar*, rsRetVal (**)()), modInfo_t*);
#endif /* #ifndef OMFILE_H_INCLUDED */
/*
diff --git a/omfwd.c b/omfwd.c
index 61a879d3..62b774cc 100644
--- a/omfwd.c
+++ b/omfwd.c
@@ -608,6 +608,9 @@ ENDneedUDPSocket
BEGINmodExit
CODESTARTmodExit
+ /* release what we no longer need */
+ objRelease(errmsg, CORE_COMPONENT);
+ objRelease(net, LM_NET_FILENAME);
ENDmodExit
diff --git a/omfwd.h b/omfwd.h
index d5dc8881..dea432e5 100644
--- a/omfwd.h
+++ b/omfwd.h
@@ -26,7 +26,7 @@
#define OMFWD_H_INCLUDED 1
/* prototypes */
-rsRetVal modInitFwd(int iIFVersRequested __attribute__((unused)), int *ipIFVersProvided, rsRetVal (**pQueryEtryPt)(), rsRetVal (*pHostQueryEtryPt)(uchar*, rsRetVal (**)()));
+rsRetVal modInitFwd(int iIFVersRequested __attribute__((unused)), int *ipIFVersProvided, rsRetVal (**pQueryEtryPt)(), rsRetVal (*pHostQueryEtryPt)(uchar*, rsRetVal (**)()), modInfo_t*);
#endif /* #ifndef OMFWD_H_INCLUDED */
/*
diff --git a/omshell.h b/omshell.h
index 0b5f8faf..3061ad07 100644
--- a/omshell.h
+++ b/omshell.h
@@ -26,7 +26,7 @@
#define ACTSHELL_H_INCLUDED 1
/* prototypes */
-rsRetVal modInitShell(int iIFVersRequested __attribute__((unused)), int *ipIFVersProvided, rsRetVal (**pQueryEtryPt)(), rsRetVal (*pHostQueryEtryPt)(uchar*, rsRetVal (**)()));
+rsRetVal modInitShell(int iIFVersRequested __attribute__((unused)), int *ipIFVersProvided, rsRetVal (**pQueryEtryPt)(), rsRetVal (*pHostQueryEtryPt)(uchar*, rsRetVal (**)()), modInfo_t*);
#endif /* #ifndef ACTSHELL_H_INCLUDED */
/*
diff --git a/omusrmsg.h b/omusrmsg.h
index 542bea3f..52e780f7 100644
--- a/omusrmsg.h
+++ b/omusrmsg.h
@@ -26,7 +26,7 @@
#define OMUSRMSG_H_INCLUDED 1
/* prototypes */
-rsRetVal modInitUsrMsg(int iIFVersRequested __attribute__((unused)), int *ipIFVersProvided, rsRetVal (**pQueryEtryPt)(), rsRetVal (*pHostQueryEtryPt)(uchar*, rsRetVal (**)()));
+rsRetVal modInitUsrMsg(int iIFVersRequested __attribute__((unused)), int *ipIFVersProvided, rsRetVal (**pQueryEtryPt)(), rsRetVal (*pHostQueryEtryPt)(uchar*, rsRetVal (**)()), modInfo_t*);
#endif /* #ifndef OMUSRMSG_H_INCLUDED */
/*
diff --git a/plugins/imgssapi/imgssapi.c b/plugins/imgssapi/imgssapi.c
index 5b966c65..f551d616 100644
--- a/plugins/imgssapi/imgssapi.c
+++ b/plugins/imgssapi/imgssapi.c
@@ -172,10 +172,10 @@ isPermittedHost(struct sockaddr *addr, char *fromHostFQDN, void *pUsrSrv, void*p
pGSess = (gss_sess_t*) pUsrSess;
if((pGSrv->allowedMethods & ALLOWEDMETHOD_TCP) &&
- isAllowedSender(net.pAllowedSenders_TCP, addr, (char*)fromHostFQDN))
+ net.isAllowedSender(net.pAllowedSenders_TCP, addr, (char*)fromHostFQDN))
allowedMethods |= ALLOWEDMETHOD_TCP;
if((pGSrv->allowedMethods & ALLOWEDMETHOD_GSS) &&
- isAllowedSender(net.pAllowedSenders_GSS, addr, (char*)fromHostFQDN))
+ net.isAllowedSender(net.pAllowedSenders_GSS, addr, (char*)fromHostFQDN))
allowedMethods |= ALLOWEDMETHOD_GSS;
if(allowedMethods && pGSess != NULL)
pGSess->allowedMethods = allowedMethods;
@@ -649,6 +649,13 @@ CODESTARTmodExit
if(pOurTcpsrv != NULL)
iRet = tcpsrv.Destruct(&pOurTcpsrv);
TCPSessGSSDeinit();
+
+ /* release objects we used */
+ objRelease(tcps_sess, LM_TCPSRV_FILENAME);
+ objRelease(tcpsrv, LM_TCPSRV_FILENAME);
+ objRelease(gssutil, LM_GSSUTIL_FILENAME);
+ objRelease(errmsg, CORE_COMPONENT);
+ objRelease(net, LM_NET_FILENAME);
ENDmodExit
diff --git a/plugins/imtcp/imtcp.c b/plugins/imtcp/imtcp.c
index d58c6f56..d4ac9cb6 100644
--- a/plugins/imtcp/imtcp.c
+++ b/plugins/imtcp/imtcp.c
@@ -66,7 +66,7 @@ static int
isPermittedHost(struct sockaddr *addr, char *fromHostFQDN, void __attribute__((unused)) *pUsrSrv,
void __attribute__((unused)) *pUsrSess)
{
- return isAllowedSender(net.pAllowedSenders_TCP, addr, fromHostFQDN);
+ return net.isAllowedSender(net.pAllowedSenders_TCP, addr, fromHostFQDN);
}
@@ -181,6 +181,11 @@ BEGINmodExit
CODESTARTmodExit
if(pOurTcpsrv != NULL)
iRet = tcpsrv.Destruct(&pOurTcpsrv);
+
+ /* release objects we used */
+ objRelease(net, LM_NET_FILENAME);
+ objRelease(tcps_sess, LM_TCPSRV_FILENAME);
+ objRelease(tcpsrv, LM_TCPSRV_FILENAME);
ENDmodExit
diff --git a/plugins/imudp/imudp.c b/plugins/imudp/imudp.c
index 17afa9a0..b7b5336b 100644
--- a/plugins/imudp/imudp.c
+++ b/plugins/imudp/imudp.c
@@ -189,7 +189,7 @@ CODESTARTrunInput
* configured to do this).
* rgerhards, 2005-09-26
*/
- if(isAllowedSender(net.pAllowedSenders_UDP,
+ if(net.isAllowedSender(net.pAllowedSenders_UDP,
(struct sockaddr *)&frominet, (char*)fromHostFQDN)) {
parseAndSubmitMessage((char*)fromHost, (char*) pRcvBuf, l,
MSG_PARSE_HOSTNAME, NOFLAG);
@@ -251,6 +251,9 @@ ENDafterRun
BEGINmodExit
CODESTARTmodExit
+ /* release what we no longer need */
+ objRelease(errmsg, CORE_COMPONENT);
+ objRelease(net, LM_NET_FILENAME);
ENDmodExit
diff --git a/queue.c b/queue.c
index 79b6fa50..859bff4f 100644
--- a/queue.c
+++ b/queue.c
@@ -934,7 +934,11 @@ queueUngetObj(queue_t *pThis, obj_t *pUsr, int bLockMutex)
DEFVARS_mutexProtection;
ISOBJ_TYPE_assert(pThis, queue);
- ISOBJ_assert(pUsr); /* TODO: we aborted right at this place at least once -- race? 2008-02-28 */
+ ISOBJ_assert(pUsr); /* TODO: we aborted right at this place at least twice -- race? 2008-02-28, -03-10
+ The second time I noticed it the queue was in destruction with NO worker threads
+ running. The pUsr ptr was totally off and provided no clue what it may be pointing
+ at (except that it looked like the static data pool). Both times, the abort happend
+ inside an action queue */
dbgoprint((obj_t*) pThis, "ungetting user object %s\n", obj.GetName(pUsr));
BEGIN_MTX_PROTECTED_OPERATIONS(pThis->mut, bLockMutex);
diff --git a/regexp.c b/regexp.c
index a1a9e1cd..96ef4f5f 100644
--- a/regexp.c
+++ b/regexp.c
@@ -93,7 +93,7 @@ BEGINmodInit()
CODESTARTmodInit
*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
- CHKiRet(regexpClassInit()); /* must be done after tcps_sess, as we use it */
+ CHKiRet(regexpClassInit(pModInfo)); /* must be done after tcps_sess, as we use it */
/* Initialize all classes that are in our module - this includes ourselfs */
ENDmodInit
/* vi:set ai:
diff --git a/rsyslog.h b/rsyslog.h
index e06ae7d2..76c6d849 100644
--- a/rsyslog.h
+++ b/rsyslog.h
@@ -82,6 +82,9 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth
RS_RET_MODULE_ENTRY_POINT_NOT_FOUND = -1004,/**< a entry point requested from a module was not present in it */
RS_RET_OBJ_NOT_AVAILABLE = -1005,/**< something could not be completed because the required object is not available*/
RS_RET_LOAD_ERROR = -1006,/**< we had an error loading the object/interface and can not continue */
+ RS_RET_MODULE_STILL_REFERENCED = -1007,/**< module could not be unloaded because it still is referenced by someone */
+ RS_RET_OBJ_UNKNOWN = -1008,/**< object is unknown where required */
+ RS_RET_OBJ_NOT_REGISTERED = -1009,/**< tried to unregister an object that is not registered */
/* return states for config file processing */
RS_RET_NONE = -2000, /**< some value is not available - not necessarily an error */
RS_RET_CONFLINE_UNPROCESSED = -2001,/**< config line was not processed, pass to other module */
diff --git a/stringbuf.c b/stringbuf.c
index f1063745..4254d5bd 100755
--- a/stringbuf.c
+++ b/stringbuf.c
@@ -1046,6 +1046,17 @@ int rsCStrLocateSzStr(cstr_t *pThis, uchar *sz)
#endif /* end comment out */
+/* our exit function. TODO: remove once converted to a class
+ * rgerhards, 2008-03-11
+ */
+rsRetVal strExit()
+{
+ DEFiRet;
+ objRelease(regexp, LM_REGEXP_FILENAME);
+ RETiRet;
+}
+
+
/* our init function. TODO: remove once converted to a class
*/
rsRetVal strInit()
diff --git a/syslogd.c b/syslogd.c
index 303358d1..c811c897 100644
--- a/syslogd.c
+++ b/syslogd.c
@@ -178,6 +178,9 @@ DEFobjCurrIf(errmsg)
DEFobjCurrIf(net) /* TODO: make go away! */
+/* forward definitions */
+static rsRetVal GlobalClassExit(void);
+
/* We define our own set of syslog defintions so that we
* do not need to rely on (possibly different) implementations.
* 2007-07-19 rgerhards
@@ -1933,18 +1936,6 @@ die(int sig)
modExitIminternal();
/*dbgPrintAllDebugInfo(); / * this is the last spot where this can be done - below output modules are unloaded! */
-
- /* TODO: this would also be the right place to de-init the builtin output modules. We
- * do not currently do that, because the module interface does not allow for
- * it. This will come some time later (it's essential with loadable modules).
- * For the time being, this is a memory leak on exit, but as the process is
- * terminated, we do not really bother about it.
- * rgerhards, 2007-08-03
- * I have added some code now, but all that mod init/de-init should be moved to
- * init, so that modules are unloaded and reloaded on HUP to. Eventually it should go
- * into freeSelectors() - but that needs to be seen. -- rgerhards, 2007-08-09
- */
- module.UnloadAndDestructAll();
/* the following line cleans up CfSysLineHandlers that were not based on loadable
* modules. As such, they are not yet cleared.
@@ -1956,10 +1947,25 @@ die(int sig)
free(pModDir);
legacyOptsFree();
- dbgprintf("Clean shutdown completed, bye\n");
-dbgprintf("hostenv %s\n", HOSTENV);
+ /* terminate the remaining classes */
+ GlobalClassExit();
- /* exit classes... This MUST be after the dbgprintf (because it de-inits the debug system!) */
+ /* TODO: this would also be the right place to de-init the builtin output modules. We
+ * do not currently do that, because the module interface does not allow for
+ * it. This will come some time later (it's essential with loadable modules).
+ * For the time being, this is a memory leak on exit, but as the process is
+ * terminated, we do not really bother about it.
+ * rgerhards, 2007-08-03
+ * I have added some code now, but all that mod init/de-init should be moved to
+ * init, so that modules are unloaded and reloaded on HUP to. Eventually it should go
+ * into freeSelectors() - but that needs to be seen. -- rgerhards, 2007-08-09
+ */
+ module.UnloadAndDestructAll(eMOD_LINK_ALL);
+
+dbgprintf("modules still loaded:\n");
+modUsrPrintAll();
+ dbgprintf("Clean shutdown completed, bye\n");
+ /* dbgClassExit MUST be the last one, because it de-inits the debug system */
dbgClassExit();
exit(0); /* "good" exit, this is the terminator function for rsyslog [die()] */
@@ -2214,7 +2220,7 @@ init(void)
/* Unload all non-static modules */
dbgprintf("Unloading non-static modules.\n");
- module.UnloadAndDestructDynamic();
+ module.UnloadAndDestructAll(eMOD_LINK_DYNAMIC_LOADED);
dbgprintf("Clearing templates.\n");
tplDeleteNew();
@@ -2865,11 +2871,12 @@ static void mainThread()
/* Method to initialize all global classes.
* rgerhards, 2008-01-04
*/
-static rsRetVal InitGlobalClasses(void)
+static rsRetVal
+InitGlobalClasses(void)
{
DEFiRet;
- CHKiRet(objClassInit()); /* *THIS* *MUST* always be the first class initilizer being called! */
+ CHKiRet(objClassInit(NULL)); /* *THIS* *MUST* always be the first class initilizer being called! */
CHKiRet(objGetObjInterface(&obj)); /* this provides the root pointer for all other queries */
/* the following classes were intialized by objClassInit() */
CHKiRet(objUse(errmsg, CORE_COMPONENT));
@@ -2883,24 +2890,24 @@ static rsRetVal InitGlobalClasses(void)
* class immediately after it is initialized. And, of course, we load those classes
* first that we use ourselfs... -- rgerhards, 2008-03-07
*/
- CHKiRet(datetimeClassInit());
+ CHKiRet(datetimeClassInit(NULL));
CHKiRet(objUse(datetime, CORE_COMPONENT));
- CHKiRet(msgClassInit());
- CHKiRet(strmClassInit());
- CHKiRet(wtiClassInit());
- CHKiRet(wtpClassInit());
- CHKiRet(queueClassInit());
- CHKiRet(vmstkClassInit());
- CHKiRet(sysvarClassInit());
- CHKiRet(vmClassInit());
+ CHKiRet(msgClassInit(NULL));
+ CHKiRet(strmClassInit(NULL));
+ CHKiRet(wtiClassInit(NULL));
+ CHKiRet(wtpClassInit(NULL));
+ CHKiRet(queueClassInit(NULL));
+ CHKiRet(vmstkClassInit(NULL));
+ CHKiRet(sysvarClassInit(NULL));
+ CHKiRet(vmClassInit(NULL));
CHKiRet(objUse(vm, CORE_COMPONENT));
- CHKiRet(vmopClassInit());
- CHKiRet(vmprgClassInit());
- CHKiRet(ctok_tokenClassInit());
- CHKiRet(ctokClassInit());
- CHKiRet(exprClassInit());
+ CHKiRet(vmopClassInit(NULL));
+ CHKiRet(vmprgClassInit(NULL));
+ CHKiRet(ctok_tokenClassInit(NULL));
+ CHKiRet(ctokClassInit(NULL));
+ CHKiRet(exprClassInit(NULL));
CHKiRet(objUse(expr, CORE_COMPONENT));
- CHKiRet(confClassInit());
+ CHKiRet(confClassInit(NULL));
CHKiRet(objUse(conf, CORE_COMPONENT));
/* dummy "classes" */
@@ -2916,6 +2923,66 @@ finalize_it:
}
+/* Method to exit all global classes. We do not do any error checking here,
+ * because that wouldn't help us at all. So better try to deinit blindly
+ * as much as succeeds (which usually means everything will). We just must
+ * be careful to do the de-init in the opposite order of the init, because
+ * of the dependencies. However, its not as important this time, because
+ * we have reference counting.
+ * rgerhards, 2008-03-10
+ */
+static rsRetVal
+GlobalClassExit(void)
+{
+ DEFiRet;
+
+ /* first, release everything we used ourself */
+ objRelease(net, LM_NET_FILENAME);/* TODO: the dependency on net shall go away! -- rgerhards, 2008-03-07 */
+ objRelease(conf, CORE_COMPONENT);
+ objRelease(expr, CORE_COMPONENT);
+ objRelease(vm, CORE_COMPONENT);
+ objRelease(datetime, CORE_COMPONENT);
+
+ /* TODO: implement the rest of the deinit */
+ confClassExit();
+#if 0
+ CHKiRet(datetimeClassInit(NULL));
+ CHKiRet(msgClassInit(NULL));
+ CHKiRet(strmClassInit(NULL));
+ CHKiRet(wtiClassInit(NULL));
+ CHKiRet(wtpClassInit(NULL));
+ CHKiRet(queueClassInit(NULL));
+ CHKiRet(vmstkClassInit(NULL));
+ CHKiRet(sysvarClassInit(NULL));
+ CHKiRet(vmClassInit(NULL));
+ CHKiRet(vmopClassInit(NULL));
+ CHKiRet(vmprgClassInit(NULL));
+ CHKiRet(ctok_tokenClassInit(NULL));
+ CHKiRet(ctokClassInit(NULL));
+ CHKiRet(exprClassInit(NULL));
+
+ /* dummy "classes" */
+ CHKiRet(actionClassInit());
+ CHKiRet(templateInit());
+#endif
+ /* dummy "classes */
+dbgprintf("pre strExit()\n");
+ strExit();
+dbgprintf("post strExit()\n");
+
+
+#if 0
+ CHKiRet(objGetObjInterface(&obj)); /* this provides the root pointer for all other queries */
+ /* the following classes were intialized by objClassInit() */
+ CHKiRet(objUse(errmsg, CORE_COMPONENT));
+ CHKiRet(objUse(module, CORE_COMPONENT));
+#endif
+ objClassExit(); /* *THIS* *MUST/SHOULD?* always be the first class initilizer being called (except debug)! */
+
+ RETiRet;
+}
+
+
/* This is the main entry point into rsyslogd. Over time, we should try to
* modularize it a bit more...
diff --git a/syslogd.h b/syslogd.h
index a65749be..d9e798bc 100644
--- a/syslogd.h
+++ b/syslogd.h
@@ -120,7 +120,6 @@ typedef struct filed selector_t; /* new type name */
#define MSG_DONT_PARSE_HOSTNAME 0
rsRetVal parseAndSubmitMessage(char *hname, char *msg, int len, int bParseHost, int flags);
#include "net.h" /* TODO: remove when you remoe isAllowedSender from here! */
-int isAllowedSender(struct AllowedSenders *pAllowRoot, struct sockaddr *pFrom, const char *pszFromHost);
void untty(void);
rsRetVal selectorConstruct(selector_t **ppThis);
rsRetVal cflineParseTemplateName(uchar** pp, omodStringRequest_t *pOMSR, int iEntry, int iTplOpts, uchar *dfltTplName);
diff --git a/tcps_sess.c b/tcps_sess.c
index 9f64be11..74de3c28 100644
--- a/tcps_sess.c
+++ b/tcps_sess.c
@@ -419,6 +419,16 @@ finalize_it:
ENDobjQueryInterface(tcps_sess)
+/* exit our class
+ * rgerhards, 2008-03-10
+ */
+BEGINObjClassExit(tcps_sess, OBJ_IS_LOADABLE_MODULE) /* CHANGE class also in END MACRO! */
+CODESTARTObjClassExit(tcps_sess)
+ /* release objects we no longer need */
+ objRelease(errmsg, CORE_COMPONENT);
+ENDObjClassExit(tcps_sess)
+
+
/* Initialize our class. Must be called as the very first method
* before anything else is called inside this class.
* rgerhards, 2008-02-29
diff --git a/tcpsrv.c b/tcpsrv.c
index 2831d038..85d0c670 100644
--- a/tcpsrv.c
+++ b/tcpsrv.c
@@ -344,7 +344,7 @@ static int *create_tcp_socket(tcpsrv_t *pThis)
* could flood our log files by sending us tons of ICMP errors.
*/
#ifndef BSD
- if (should_use_so_bsdcompat()) {
+ if(net.should_use_so_bsdcompat()) {
if (setsockopt(*s, SOL_SOCKET, SO_BSDCOMPAT,
(char *) &on, sizeof(on)) < 0) {
errmsg.LogError(NO_ERRCODE, "TCP setsockopt(BSDCOMPAT)");
@@ -794,13 +794,28 @@ finalize_it:
ENDobjQueryInterface(tcpsrv)
+/* exit our class
+ * rgerhards, 2008-03-10
+ */
+BEGINObjClassExit(tcpsrv, OBJ_IS_LOADABLE_MODULE) /* CHANGE class also in END MACRO! */
+CODESTARTObjClassExit(tcpsrv)
+ /* release objects we no longer need */
+ objRelease(tcps_sess, DONT_LOAD_LIB);
+ objRelease(conf, CORE_COMPONENT);
+ objRelease(errmsg, CORE_COMPONENT);
+ objRelease(net, LM_NET_FILENAME);
+ENDObjClassExit(tcpsrv)
+
+
/* Initialize our class. Must be called as the very first method
* before anything else is called inside this class.
* rgerhards, 2008-02-29
*/
BEGINObjClassInit(tcpsrv, 1, OBJ_IS_LOADABLE_MODULE) /* class, version - CHANGE class also in END MACRO! */
/* request objects we use */
- CHKiRet(objUse(tcps_sess, "tcps_sess"));
+ CHKiRet(objUse(errmsg, CORE_COMPONENT));
+ CHKiRet(objUse(net, LM_NET_FILENAME));
+ CHKiRet(objUse(tcps_sess, DONT_LOAD_LIB));
CHKiRet(objUse(conf, CORE_COMPONENT));
/* set our own handlers */
@@ -814,6 +829,9 @@ ENDObjClassInit(tcpsrv)
BEGINmodExit
CODESTARTmodExit
+ /* de-init in reverse order! */
+ tcpsrvClassExit();
+ tcps_sessClassExit();
ENDmodExit
@@ -828,12 +846,8 @@ CODESTARTmodInit
*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
/* Initialize all classes that are in our module - this includes ourselfs */
- CHKiRet(tcps_sessClassInit());
- CHKiRet(tcpsrvClassInit()); /* must be done after tcps_sess, as we use it */
-
- /* request objects we use */
- CHKiRet(objUse(errmsg, CORE_COMPONENT));
- CHKiRet(objUse(net, LM_NET_FILENAME));
+ CHKiRet(tcps_sessClassInit(pModInfo));
+ CHKiRet(tcpsrvClassInit(pModInfo)); /* must be done after tcps_sess, as we use it */
ENDmodInit
/* vim:set ai: