diff options
-rw-r--r-- | action.h | 2 | ||||
-rw-r--r-- | conf.c | 14 | ||||
-rw-r--r-- | configure.ac | 3 | ||||
-rw-r--r-- | datetime.c | 1 | ||||
-rw-r--r-- | debug.c | 2 | ||||
-rw-r--r-- | gss-misc.c | 2 | ||||
-rw-r--r-- | module-template.h | 13 | ||||
-rw-r--r-- | modules.c | 284 | ||||
-rw-r--r-- | modules.h | 32 | ||||
-rw-r--r-- | net.c | 26 | ||||
-rw-r--r-- | net.h | 8 | ||||
-rw-r--r-- | obj-types.h | 54 | ||||
-rw-r--r-- | obj.c | 156 | ||||
-rw-r--r-- | obj.h | 8 | ||||
-rw-r--r-- | omdiscard.h | 2 | ||||
-rw-r--r-- | omfile.h | 2 | ||||
-rw-r--r-- | omfwd.c | 3 | ||||
-rw-r--r-- | omfwd.h | 2 | ||||
-rw-r--r-- | omshell.h | 2 | ||||
-rw-r--r-- | omusrmsg.h | 2 | ||||
-rw-r--r-- | plugins/imgssapi/imgssapi.c | 11 | ||||
-rw-r--r-- | plugins/imtcp/imtcp.c | 7 | ||||
-rw-r--r-- | plugins/imudp/imudp.c | 5 | ||||
-rw-r--r-- | queue.c | 6 | ||||
-rw-r--r-- | regexp.c | 2 | ||||
-rw-r--r-- | rsyslog.h | 3 | ||||
-rwxr-xr-x | stringbuf.c | 11 | ||||
-rw-r--r-- | syslogd.c | 133 | ||||
-rw-r--r-- | syslogd.h | 1 | ||||
-rw-r--r-- | tcps_sess.c | 10 | ||||
-rw-r--r-- | tcpsrv.c | 30 |
31 files changed, 679 insertions, 158 deletions
@@ -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 */ @@ -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 @@ -37,6 +37,7 @@ #include "rsyslog.h" #include "obj.h" +#include "modules.h" #include "datetime.h" #include "sysvar.h" #include "srUtils.h" @@ -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; @@ -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); @@ -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) @@ -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); @@ -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: */ @@ -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 */ @@ -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)); @@ -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 */ /* @@ -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 */ /* @@ -608,6 +608,9 @@ ENDneedUDPSocket BEGINmodExit CODESTARTmodExit + /* release what we no longer need */ + objRelease(errmsg, CORE_COMPONENT); + objRelease(net, LM_NET_FILENAME); ENDmodExit @@ -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 */ /* @@ -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 */ /* @@ -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 @@ -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); @@ -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: @@ -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() @@ -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... @@ -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 @@ -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: |