summaryrefslogtreecommitdiff
path: root/msg.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2008-12-12 17:46:20 +0100
committerMichael Biebl <biebl@debian.org>2008-12-12 17:46:20 +0100
commit84080b58f8c6c5c040723a02503ddd90f02b5898 (patch)
treecf8c63e076f1ebb9cb2bea644a4f45172808a3e5 /msg.c
parent53123ea8a1b9180b9aa0568e847f9245987c1b7c (diff)
downloadrsyslog-84080b58f8c6c5c040723a02503ddd90f02b5898.tar.gz
Imported Upstream version 3.20.2upstream/3.20.2
Diffstat (limited to 'msg.c')
-rw-r--r--msg.c2350
1 files changed, 0 insertions, 2350 deletions
diff --git a/msg.c b/msg.c
deleted file mode 100644
index bd1e425..0000000
--- a/msg.c
+++ /dev/null
@@ -1,2350 +0,0 @@
-/* msg.c
- * The msg object. Implementation of all msg-related functions
- *
- * File begun on 2007-07-13 by RGerhards (extracted from syslogd.c)
- * This file is under development and has not yet arrived at being fully
- * self-contained and a real object. So far, it is mostly an excerpt
- * of the "old" message code without any modifications. However, it
- * helps to have things at the right place one we go to the meat of it.
- *
- * Copyright 2007 Rainer Gerhards and Adiscon GmbH.
- *
- * This file is part of rsyslog.
- *
- * Rsyslog is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Rsyslog is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Rsyslog. If not, see <http://www.gnu.org/licenses/>.
- *
- * A copy of the GPL can be found in the file "COPYING" in this distribution.
- */
-#include "config.h"
-#include <stdio.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#define SYSLOG_NAMES
-#include <string.h>
-#include <assert.h>
-#include <ctype.h>
-#include "rsyslog.h"
-#include "syslogd.h"
-#include "srUtils.h"
-#include "stringbuf.h"
-#include "template.h"
-#include "msg.h"
-#include "var.h"
-#include "datetime.h"
-#include "regexp.h"
-#include "atomic.h"
-
-/* static data */
-DEFobjStaticHelpers
-DEFobjCurrIf(var)
-DEFobjCurrIf(datetime)
-DEFobjCurrIf(regexp)
-
-static syslogCODE rs_prioritynames[] =
- {
- { "alert", LOG_ALERT },
- { "crit", LOG_CRIT },
- { "debug", LOG_DEBUG },
- { "emerg", LOG_EMERG },
- { "err", LOG_ERR },
- { "error", LOG_ERR }, /* DEPRECATED */
- { "info", LOG_INFO },
- { "none", INTERNAL_NOPRI }, /* INTERNAL */
- { "notice", LOG_NOTICE },
- { "panic", LOG_EMERG }, /* DEPRECATED */
- { "warn", LOG_WARNING }, /* DEPRECATED */
- { "warning", LOG_WARNING },
- { NULL, -1 }
- };
-
-#ifndef LOG_AUTHPRIV
-# define LOG_AUTHPRIV LOG_AUTH
-#endif
-static syslogCODE rs_facilitynames[] =
- {
- { "auth", LOG_AUTH },
- { "authpriv", LOG_AUTHPRIV },
- { "cron", LOG_CRON },
- { "daemon", LOG_DAEMON },
-#if defined(LOG_FTP)
- {"ftp", LOG_FTP},
-#endif
- { "kern", LOG_KERN },
- { "lpr", LOG_LPR },
- { "mail", LOG_MAIL },
- //{ "mark", INTERNAL_MARK }, /* INTERNAL */
- { "news", LOG_NEWS },
- { "security", LOG_AUTH }, /* DEPRECATED */
- { "syslog", LOG_SYSLOG },
- { "user", LOG_USER },
- { "uucp", LOG_UUCP },
- { "local0", LOG_LOCAL0 },
- { "local1", LOG_LOCAL1 },
- { "local2", LOG_LOCAL2 },
- { "local3", LOG_LOCAL3 },
- { "local4", LOG_LOCAL4 },
- { "local5", LOG_LOCAL5 },
- { "local6", LOG_LOCAL6 },
- { "local7", LOG_LOCAL7 },
- { NULL, -1 }
- };
-
-/* some forward declarations */
-static int getAPPNAMELen(msg_t *pM);
-
-/* The following functions will support advanced output module
- * multithreading, once this is implemented. Currently, we
- * include them as hooks only. The idea is that we need to guard
- * some msg objects data fields against concurrent access if
- * we run on multiple threads. Please note that in any case this
- * is not necessary for calls from INPUT modules, because they
- * construct the message object and do this serially. Only when
- * the message is in the processing queue, multiple threads may
- * access a single object. Consequently, there are no guard functions
- * for "set" methods, as these are called during input. Only "get"
- * functions that modify important structures have them.
- * rgerhards, 2007-07-20
- * We now support locked and non-locked operations, depending on
- * the configuration of rsyslog. To support this, we use function
- * pointers. Initially, we start in non-locked mode. There, all
- * locking operations call into dummy functions. When locking is
- * enabled, the function pointers are changed to functions doing
- * actual work. We also introduced another MsgPrepareEnqueue() function
- * which initializes the locking structures, if needed. This is
- * necessary because internal messages during config file startup
- * processing are always created in non-locking mode. So we can
- * not initialize locking structures during constructions. We now
- * postpone this until when the message is fully constructed and
- * enqueued. Then we know the status of locking. This has a nice
- * side effect, and that is that during the initial creation of
- * the Msg object no locking needs to be done, which results in better
- * performance. -- rgerhards, 2008-01-05
- */
-static void (*funcLock)(msg_t *pMsg);
-static void (*funcUnlock)(msg_t *pMsg);
-static void (*funcDeleteMutex)(msg_t *pMsg);
-void (*funcMsgPrepareEnqueue)(msg_t *pMsg);
-#if 1 /* This is a debug aid */
-#define MsgLock(pMsg) funcLock(pMsg)
-#define MsgUnlock(pMsg) funcUnlock(pMsg)
-#else
-#define MsgLock(pMsg) {dbgprintf("line %d\n - ", __LINE__); funcLock(pMsg);; }
-#define MsgUnlock(pMsg) {dbgprintf("line %d - ", __LINE__); funcUnlock(pMsg); }
-#endif
-
-/* the next function is a dummy to be used by the looking functions
- * when the class is not yet running in an environment where locking
- * is necessary. Please note that the need to lock can (and will) change
- * during a single run. Typically, this is depending on the operation mode
- * of the message queues (which is operator-configurable). -- rgerhards, 2008-01-05
- */
-static void MsgLockingDummy(msg_t __attribute__((unused)) *pMsg)
-{
- /* empty be design */
-}
-
-
-/* The following function prepares a message for enqueue into the queue. This is
- * where a message may be accessed by multiple threads. This implementation here
- * is the version for multiple concurrent acces. It initializes the locking
- * structures.
- * TODO: change to an iRet interface! -- rgerhards, 2008-07-14
- */
-static void MsgPrepareEnqueueLockingCase(msg_t *pThis)
-{
- int iErr;
- BEGINfunc
- assert(pThis != NULL);
- iErr = pthread_mutexattr_init(&pThis->mutAttr);
- if(iErr != 0) {
- dbgprintf("error initializing mutex attribute in %s:%d, trying to continue\n",
- __FILE__, __LINE__);
- }
- iErr = pthread_mutexattr_settype(&pThis->mutAttr, PTHREAD_MUTEX_RECURSIVE);
- if(iErr != 0) {
- dbgprintf("ERROR setting mutex attribute to recursive in %s:%d, trying to continue "
- "but we will probably either abort or hang soon\n",
- __FILE__, __LINE__);
- /* TODO: it makes very little sense to continue here,
- * but it requires an iRet interface to gracefully shut
- * down. We should do that over time. -- rgerhards, 2008-07-14
- */
- }
- pthread_mutex_init(&pThis->mut, &pThis->mutAttr);
-
- /* we do no longer need the attribute. According to the
- * POSIX spec, we can destroy it without affecting the
- * initialized mutex (that used the attribute).
- * rgerhards, 2008-07-14
- */
- pthread_mutexattr_destroy(&pThis->mutAttr);
- ENDfunc
-}
-
-
-/* ... and now the locking and unlocking implementations: */
-static void MsgLockLockingCase(msg_t *pThis)
-{
- /* DEV debug only! dbgprintf("MsgLock(0x%lx)\n", (unsigned long) pThis); */
- assert(pThis != NULL);
- pthread_mutex_lock(&pThis->mut);
-}
-
-static void MsgUnlockLockingCase(msg_t *pThis)
-{
- /* DEV debug only! dbgprintf("MsgUnlock(0x%lx)\n", (unsigned long) pThis); */
- assert(pThis != NULL);
- pthread_mutex_unlock(&pThis->mut);
-}
-
-/* delete the mutex object on message destruction (locking case)
- */
-static void MsgDeleteMutexLockingCase(msg_t *pThis)
-{
- assert(pThis != NULL);
- pthread_mutex_destroy(&pThis->mut);
-}
-
-/* enable multiple concurrent access on the message object
- * This works on a class-wide basis and can bot be undone.
- * That is, if it is once enabled, it can not be disabled during
- * the same run. When this function is called, no other thread
- * must manipulate message objects. Then we would have race conditions,
- * but guarding against this is counter-productive because it
- * would cost additional time. Plus, it would be a programming error.
- * rgerhards, 2008-01-05
- */
-rsRetVal MsgEnableThreadSafety(void)
-{
- DEFiRet;
- funcLock = MsgLockLockingCase;
- funcUnlock = MsgUnlockLockingCase;
- funcMsgPrepareEnqueue = MsgPrepareEnqueueLockingCase;
- funcDeleteMutex = MsgDeleteMutexLockingCase;
- RETiRet;
-}
-
-/* end locking functions */
-
-
-/* "Constructor" for a msg "object". Returns a pointer to
- * the new object or NULL if no such object could be allocated.
- * An object constructed via this function should only be destroyed
- * via "msgDestruct()".
- */
-rsRetVal msgConstruct(msg_t **ppThis)
-{
- DEFiRet;
- msg_t *pM;
-
- assert(ppThis != NULL);
- if((pM = calloc(1, sizeof(msg_t))) == NULL)
- ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
-
- /* initialize members that are non-zero */
- pM->iRefCount = 1;
- pM->iSeverity = -1;
- pM->iFacility = -1;
- datetime.getCurrTime(&(pM->tRcvdAt));
- objConstructSetObjInfo(pM);
-
- /* DEV debugging only! dbgprintf("msgConstruct\t0x%x, ref 1\n", (int)pM);*/
-
- *ppThis = pM;
-
-finalize_it:
- RETiRet;
-}
-
-
-BEGINobjDestruct(msg) /* be sure to specify the object type also in END and CODESTART macros! */
- int currRefCount;
-CODESTARTobjDestruct(msg)
- /* DEV Debugging only ! dbgprintf("msgDestruct\t0x%lx, Ref now: %d\n", (unsigned long)pM, pM->iRefCount - 1); */
-# ifdef DO_HAVE_ATOMICS
- currRefCount = ATOMIC_DEC_AND_FETCH(pThis->iRefCount);
-# else
- currRefCount = --pThis->iRefCount;
-# endif
- if(currRefCount == 0)
- {
- /* DEV Debugging Only! dbgprintf("msgDestruct\t0x%lx, RefCount now 0, doing DESTROY\n", (unsigned long)pThis); */
- if(pThis->pszUxTradMsg != NULL)
- free(pThis->pszUxTradMsg);
- if(pThis->pszRawMsg != NULL)
- free(pThis->pszRawMsg);
- if(pThis->pszTAG != NULL)
- free(pThis->pszTAG);
- if(pThis->pszHOSTNAME != NULL)
- free(pThis->pszHOSTNAME);
- if(pThis->pszRcvFrom != NULL)
- free(pThis->pszRcvFrom);
- if(pThis->pszMSG != NULL)
- free(pThis->pszMSG);
- if(pThis->pszFacility != NULL)
- free(pThis->pszFacility);
- if(pThis->pszFacilityStr != NULL)
- free(pThis->pszFacilityStr);
- if(pThis->pszSeverity != NULL)
- free(pThis->pszSeverity);
- if(pThis->pszSeverityStr != NULL)
- free(pThis->pszSeverityStr);
- if(pThis->pszRcvdAt3164 != NULL)
- free(pThis->pszRcvdAt3164);
- if(pThis->pszRcvdAt3339 != NULL)
- free(pThis->pszRcvdAt3339);
- if(pThis->pszRcvdAt_MySQL != NULL)
- free(pThis->pszRcvdAt_MySQL);
- if(pThis->pszRcvdAt_PgSQL != NULL)
- free(pThis->pszRcvdAt_PgSQL);
- if(pThis->pszTIMESTAMP3164 != NULL)
- free(pThis->pszTIMESTAMP3164);
- if(pThis->pszTIMESTAMP3339 != NULL)
- free(pThis->pszTIMESTAMP3339);
- if(pThis->pszTIMESTAMP_MySQL != NULL)
- free(pThis->pszTIMESTAMP_MySQL);
- if(pThis->pszTIMESTAMP_PgSQL != NULL)
- free(pThis->pszTIMESTAMP_PgSQL);
- if(pThis->pszPRI != NULL)
- free(pThis->pszPRI);
- if(pThis->pCSProgName != NULL)
- rsCStrDestruct(&pThis->pCSProgName);
- if(pThis->pCSStrucData != NULL)
- rsCStrDestruct(&pThis->pCSStrucData);
- if(pThis->pCSAPPNAME != NULL)
- rsCStrDestruct(&pThis->pCSAPPNAME);
- if(pThis->pCSPROCID != NULL)
- rsCStrDestruct(&pThis->pCSPROCID);
- if(pThis->pCSMSGID != NULL)
- rsCStrDestruct(&pThis->pCSMSGID);
- funcDeleteMutex(pThis);
- } else {
- pThis = NULL; /* tell framework not to destructing the object! */
- }
-ENDobjDestruct(msg)
-
-
-/* The macros below are used in MsgDup(). I use macros
- * to keep the fuction code somewhat more readyble. It is my
- * replacement for inline functions in CPP
- */
-#define tmpCOPYSZ(name) \
- if(pOld->psz##name != NULL) { \
- if((pNew->psz##name = srUtilStrDup(pOld->psz##name, pOld->iLen##name)) == NULL) {\
- msgDestruct(&pNew);\
- return NULL;\
- }\
- pNew->iLen##name = pOld->iLen##name;\
- }
-
-/* copy the CStr objects.
- * if the old value is NULL, we do not need to do anything because we
- * initialized the new value to NULL via calloc().
- */
-#define tmpCOPYCSTR(name) \
- if(pOld->pCS##name != NULL) {\
- if(rsCStrConstructFromCStr(&(pNew->pCS##name), pOld->pCS##name) != RS_RET_OK) {\
- msgDestruct(&pNew);\
- return NULL;\
- }\
- }
-/* Constructs a message object by duplicating another one.
- * Returns NULL if duplication failed. We do not need to lock the
- * message object here, because a fully-created msg object is never
- * allowed to be manipulated. For this, MsgDup() must be used, so MsgDup()
- * can never run into a situation where the message object is being
- * modified while its content is copied - it's forbidden by definition.
- * rgerhards, 2007-07-10
- */
-msg_t* MsgDup(msg_t* pOld)
-{
- msg_t* pNew;
-
- assert(pOld != NULL);
-
- BEGINfunc
- if(msgConstruct(&pNew) != RS_RET_OK) {
- return NULL;
- }
-
- /* now copy the message properties */
- pNew->iRefCount = 1;
- pNew->iSeverity = pOld->iSeverity;
- pNew->iFacility = pOld->iFacility;
- pNew->bParseHOSTNAME = pOld->bParseHOSTNAME;
- pNew->msgFlags = pOld->msgFlags;
- pNew->iProtocolVersion = pOld->iProtocolVersion;
- memcpy(&pNew->tRcvdAt, &pOld->tRcvdAt, sizeof(struct syslogTime));
- memcpy(&pNew->tTIMESTAMP, &pOld->tTIMESTAMP, sizeof(struct syslogTime));
- tmpCOPYSZ(Severity);
- tmpCOPYSZ(SeverityStr);
- tmpCOPYSZ(Facility);
- tmpCOPYSZ(FacilityStr);
- tmpCOPYSZ(PRI);
- tmpCOPYSZ(RawMsg);
- tmpCOPYSZ(MSG);
- tmpCOPYSZ(UxTradMsg);
- tmpCOPYSZ(TAG);
- tmpCOPYSZ(HOSTNAME);
- tmpCOPYSZ(RcvFrom);
-
- tmpCOPYCSTR(ProgName);
- tmpCOPYCSTR(StrucData);
- tmpCOPYCSTR(APPNAME);
- tmpCOPYCSTR(PROCID);
- tmpCOPYCSTR(MSGID);
-
- /* we do not copy all other cache properties, as we do not even know
- * if they are needed once again. So we let them re-create if needed.
- */
-
- ENDfunc
- return pNew;
-}
-#undef tmpCOPYSZ
-#undef tmpCOPYCSTR
-
-
-/* This method serializes a message object. That means the whole
- * object is modified into text form. That text form is suitable for
- * later reconstruction of the object by calling MsgDeSerialize().
- * The most common use case for this method is the creation of an
- * on-disk representation of the message object.
- * We do not serialize the cache properties. We re-create them when needed.
- * This saves us a lot of memory. Performance is no concern, as serializing
- * is a so slow operation that recration of the caches does not count. Also,
- * we do not serialize bParseHOSTNAME, as this is only a helper variable
- * during msg construction - and never again used later.
- * rgerhards, 2008-01-03
- */
-static rsRetVal MsgSerialize(msg_t *pThis, strm_t *pStrm)
-{
- DEFiRet;
-
- assert(pThis != NULL);
- assert(pStrm != NULL);
-
- CHKiRet(obj.BeginSerialize(pStrm, (obj_t*) pThis));
- objSerializeSCALAR(pStrm, iProtocolVersion, SHORT);
- objSerializeSCALAR(pStrm, iSeverity, SHORT);
- objSerializeSCALAR(pStrm, iFacility, SHORT);
- objSerializeSCALAR(pStrm, msgFlags, INT);
- objSerializeSCALAR(pStrm, tRcvdAt, SYSLOGTIME);
- objSerializeSCALAR(pStrm, tTIMESTAMP, SYSLOGTIME);
-
- objSerializePTR(pStrm, pszRawMsg, PSZ);
- objSerializePTR(pStrm, pszMSG, PSZ);
- objSerializePTR(pStrm, pszUxTradMsg, PSZ);
- objSerializePTR(pStrm, pszTAG, PSZ);
- objSerializePTR(pStrm, pszHOSTNAME, PSZ);
- objSerializePTR(pStrm, pszRcvFrom, PSZ);
-
- objSerializePTR(pStrm, pCSStrucData, CSTR);
- objSerializePTR(pStrm, pCSAPPNAME, CSTR);
- objSerializePTR(pStrm, pCSPROCID, CSTR);
- objSerializePTR(pStrm, pCSMSGID, CSTR);
-
- CHKiRet(obj.EndSerialize(pStrm));
-
-finalize_it:
- RETiRet;
-}
-
-
-/* Increment reference count - see description of the "msg"
- * structure for details. As a convenience to developers,
- * this method returns the msg pointer that is passed to it.
- * It is recommended that it is called as follows:
- *
- * pSecondMsgPointer = MsgAddRef(pOrgMsgPointer);
- */
-msg_t *MsgAddRef(msg_t *pM)
-{
- assert(pM != NULL);
-# ifdef DO_HAVE_ATOMICS
- ATOMIC_INC(pM->iRefCount);
-# else
- MsgLock(pM);
- pM->iRefCount++;
- MsgUnlock(pM);
-# endif
- /* DEV debugging only! dbgprintf("MsgAddRef\t0x%x done, Ref now: %d\n", (int)pM, pM->iRefCount);*/
- return(pM);
-}
-
-
-/* This functions tries to aquire the PROCID from TAG. Its primary use is
- * when a legacy syslog message has been received and should be forwarded as
- * syslog-protocol (or the PROCID is requested for any other reason).
- * In legacy syslog, the PROCID is considered to be the character sequence
- * between the first [ and the first ]. This usually are digits only, but we
- * do not check that. However, if there is no closing ], we do not assume we
- * can obtain a PROCID. Take in mind that not every legacy syslog message
- * actually has a PROCID.
- * rgerhards, 2005-11-24
- */
-static rsRetVal aquirePROCIDFromTAG(msg_t *pM)
-{
- register int i;
- DEFiRet;
-
- assert(pM != NULL);
- if(pM->pCSPROCID != NULL)
- return RS_RET_OK; /* we are already done ;) */
-
- if(getProtocolVersion(pM) != 0)
- return RS_RET_OK; /* we can only emulate if we have legacy format */
-
- /* find first '['... */
- i = 0;
- while((i < pM->iLenTAG) && (pM->pszTAG[i] != '['))
- ++i;
- if(!(i < pM->iLenTAG))
- return RS_RET_OK; /* no [, so can not emulate... */
-
- ++i; /* skip '[' */
-
- /* now obtain the PROCID string... */
- CHKiRet(rsCStrConstruct(&pM->pCSPROCID));
- rsCStrSetAllocIncrement(pM->pCSPROCID, 16);
- while((i < pM->iLenTAG) && (pM->pszTAG[i] != ']')) {
- CHKiRet(rsCStrAppendChar(pM->pCSPROCID, pM->pszTAG[i]));
- ++i;
- }
-
- if(!(i < pM->iLenTAG)) {
- /* oops... it looked like we had a PROCID, but now it has
- * turned out this is not true. In this case, we need to free
- * the buffer and simply return. Note that this is NOT an error
- * case!
- */
- rsCStrDestruct(&pM->pCSPROCID);
- FINALIZE;
- }
-
- /* OK, finaally we could obtain a PROCID. So let's use it ;) */
- CHKiRet(rsCStrFinish(pM->pCSPROCID));
-
-finalize_it:
- RETiRet;
-}
-
-
-/* Parse and set the "programname" for a given MSG object. Programname
- * is a BSD concept, it is the tag without any instance-specific information.
- * Precisely, the programname is terminated by either (whichever occurs first):
- * - end of tag
- * - nonprintable character
- * - ':'
- * - '['
- * - '/'
- * The above definition has been taken from the FreeBSD syslogd sources.
- *
- * The program name is not parsed by default, because it is infrequently-used.
- * If it is needed, this function should be called first. It checks if it is
- * already set and extracts it, if not.
- * A message object must be provided, else a crash will occur.
- * rgerhards, 2005-10-19
- */
-static rsRetVal aquireProgramName(msg_t *pM)
-{
- DEFiRet;
- register int i;
-
- assert(pM != NULL);
- if(pM->pCSProgName == NULL) {
- /* ok, we do not yet have it. So let's parse the TAG
- * to obtain it.
- */
- CHKiRet(rsCStrConstruct(&pM->pCSProgName));
- rsCStrSetAllocIncrement(pM->pCSProgName, 33);
- for( i = 0
- ; (i < pM->iLenTAG) && isprint((int) pM->pszTAG[i])
- && (pM->pszTAG[i] != '\0') && (pM->pszTAG[i] != ':')
- && (pM->pszTAG[i] != '[') && (pM->pszTAG[i] != '/')
- ; ++i) {
- CHKiRet(rsCStrAppendChar(pM->pCSProgName, pM->pszTAG[i]));
- }
- CHKiRet(rsCStrFinish(pM->pCSProgName));
- }
-finalize_it:
- RETiRet;
-}
-
-
-/* This function moves the HOSTNAME inside the message object to the
- * TAG. It is a specialised function used to handle the condition when
- * a message without HOSTNAME is being processed. The missing HOSTNAME
- * is only detected at a later stage, during TAG processing, so that
- * we already had set the HOSTNAME property and now need to move it to
- * the TAG. Of course, we could do this via a couple of get/set methods,
- * but it is far more efficient to do it via this specialised method.
- * This is especially important as this can be a very common case, e.g.
- * when BSD syslog is acting as a sender.
- * rgerhards, 2005-11-10.
- */
-void moveHOSTNAMEtoTAG(msg_t *pM)
-{
- assert(pM != NULL);
- if(pM->pszTAG != NULL)
- free(pM->pszTAG);
- pM->pszTAG = pM->pszHOSTNAME;
- pM->iLenTAG = pM->iLenHOSTNAME;
- pM->pszHOSTNAME = NULL;
- pM->iLenHOSTNAME = 0;
-}
-
-/* Access methods - dumb & easy, not a comment for each ;)
- */
-void setProtocolVersion(msg_t *pM, int iNewVersion)
-{
- assert(pM != NULL);
- if(iNewVersion != 0 && iNewVersion != 1) {
- dbgprintf("Tried to set unsupported protocol version %d - changed to 0.\n", iNewVersion);
- iNewVersion = 0;
- }
- pM->iProtocolVersion = iNewVersion;
-}
-
-int getProtocolVersion(msg_t *pM)
-{
- assert(pM != NULL);
- return(pM->iProtocolVersion);
-}
-
-/* note: string is taken from constant pool, do NOT free */
-char *getProtocolVersionString(msg_t *pM)
-{
- assert(pM != NULL);
- return(pM->iProtocolVersion ? "1" : "0");
-}
-
-int getMSGLen(msg_t *pM)
-{
- return((pM == NULL) ? 0 : pM->iLenMSG);
-}
-
-
-char *getRawMsg(msg_t *pM)
-{
- if(pM == NULL)
- return "";
- else
- if(pM->pszRawMsg == NULL)
- return "";
- else
- return (char*)pM->pszRawMsg;
-}
-
-char *getUxTradMsg(msg_t *pM)
-{
- if(pM == NULL)
- return "";
- else
- if(pM->pszUxTradMsg == NULL)
- return "";
- else
- return (char*)pM->pszUxTradMsg;
-}
-
-char *getMSG(msg_t *pM)
-{
- if(pM == NULL)
- return "";
- else
- if(pM->pszMSG == NULL)
- return "";
- else
- return (char*)pM->pszMSG;
-}
-
-
-/* Get PRI value in text form */
-char *getPRI(msg_t *pM)
-{
- int pri;
-
- if(pM == NULL)
- return "";
-
- MsgLock(pM);
- if(pM->pszPRI == NULL) {
- /* OK, we need to construct it... we use a 5 byte buffer - as of
- * RFC 3164, it can't be longer. Should it still be, snprintf will truncate...
- * Note that we do not use the LOG_MAKEPRI macro. This macro
- * is a simple add of the two values under FreeBSD 7. So we implement
- * the logic in our own code. This is a change from a bug
- * report. -- rgerhards, 2008-07-14
- */
- pri = pM->iFacility * 8 + pM->iSeverity;
- if((pM->pszPRI = malloc(5)) == NULL) return "";
- pM->iLenPRI = snprintf((char*)pM->pszPRI, 5, "%d", pri);
- }
- MsgUnlock(pM);
-
- return (char*)pM->pszPRI;
-}
-
-
-/* Get PRI value as integer */
-int getPRIi(msg_t *pM)
-{
- assert(pM != NULL);
- return (pM->iFacility << 3) + (pM->iSeverity);
-}
-
-
-char *getTimeReported(msg_t *pM, enum tplFormatTypes eFmt)
-{
- if(pM == NULL)
- return "";
-
- switch(eFmt) {
- case tplFmtDefault:
- MsgLock(pM);
- if(pM->pszTIMESTAMP3164 == NULL) {
- if((pM->pszTIMESTAMP3164 = malloc(16)) == NULL) {
- glblHadMemShortage = 1;
- MsgUnlock(pM);
- return "";
- }
- datetime.formatTimestamp3164(&pM->tTIMESTAMP, pM->pszTIMESTAMP3164, 16);
- }
- MsgUnlock(pM);
- return(pM->pszTIMESTAMP3164);
- case tplFmtMySQLDate:
- MsgLock(pM);
- if(pM->pszTIMESTAMP_MySQL == NULL) {
- if((pM->pszTIMESTAMP_MySQL = malloc(15)) == NULL) {
- glblHadMemShortage = 1;
- MsgUnlock(pM);
- return "";
- }
- datetime.formatTimestampToMySQL(&pM->tTIMESTAMP, pM->pszTIMESTAMP_MySQL, 15);
- }
- MsgUnlock(pM);
- return(pM->pszTIMESTAMP_MySQL);
- case tplFmtPgSQLDate:
- MsgLock(pM);
- if(pM->pszTIMESTAMP_PgSQL == NULL) {
- if((pM->pszTIMESTAMP_PgSQL = malloc(21)) == NULL) {
- glblHadMemShortage = 1;
- MsgUnlock(pM);
- return "";
- }
- datetime.formatTimestampToPgSQL(&pM->tTIMESTAMP, pM->pszTIMESTAMP_PgSQL, 21);
- }
- MsgUnlock(pM);
- return(pM->pszTIMESTAMP_PgSQL);
- case tplFmtRFC3164Date:
- MsgLock(pM);
- if(pM->pszTIMESTAMP3164 == NULL) {
- if((pM->pszTIMESTAMP3164 = malloc(16)) == NULL) {
- glblHadMemShortage = 1;
- MsgUnlock(pM);
- return "";
- }
- datetime.formatTimestamp3164(&pM->tTIMESTAMP, pM->pszTIMESTAMP3164, 16);
- }
- MsgUnlock(pM);
- return(pM->pszTIMESTAMP3164);
- case tplFmtRFC3339Date:
- MsgLock(pM);
- if(pM->pszTIMESTAMP3339 == NULL) {
- if((pM->pszTIMESTAMP3339 = malloc(33)) == NULL) {
- glblHadMemShortage = 1;
- MsgUnlock(pM);
- return ""; /* TODO: check this: can it cause a free() of constant memory?) */
- }
- datetime.formatTimestamp3339(&pM->tTIMESTAMP, pM->pszTIMESTAMP3339, 33);
- }
- MsgUnlock(pM);
- return(pM->pszTIMESTAMP3339);
- }
- return "INVALID eFmt OPTION!";
-}
-
-char *getTimeGenerated(msg_t *pM, enum tplFormatTypes eFmt)
-{
- if(pM == NULL)
- return "";
-
- switch(eFmt) {
- case tplFmtDefault:
- MsgLock(pM);
- if(pM->pszRcvdAt3164 == NULL) {
- if((pM->pszRcvdAt3164 = malloc(16)) == NULL) {
- glblHadMemShortage = 1;
- MsgUnlock(pM);
- return "";
- }
- datetime.formatTimestamp3164(&pM->tRcvdAt, pM->pszRcvdAt3164, 16);
- }
- MsgUnlock(pM);
- return(pM->pszRcvdAt3164);
- case tplFmtMySQLDate:
- MsgLock(pM);
- if(pM->pszRcvdAt_MySQL == NULL) {
- if((pM->pszRcvdAt_MySQL = malloc(15)) == NULL) {
- glblHadMemShortage = 1;
- MsgUnlock(pM);
- return "";
- }
- datetime.formatTimestampToMySQL(&pM->tRcvdAt, pM->pszRcvdAt_MySQL, 15);
- }
- MsgUnlock(pM);
- return(pM->pszRcvdAt_MySQL);
- case tplFmtPgSQLDate:
- MsgLock(pM);
- if(pM->pszRcvdAt_PgSQL == NULL) {
- if((pM->pszRcvdAt_PgSQL = malloc(21)) == NULL) {
- glblHadMemShortage = 1;
- MsgUnlock(pM);
- return "";
- }
- datetime.formatTimestampToPgSQL(&pM->tRcvdAt, pM->pszRcvdAt_PgSQL, 21);
- }
- MsgUnlock(pM);
- return(pM->pszRcvdAt_PgSQL);
- case tplFmtRFC3164Date:
- MsgLock(pM);
- if(pM->pszRcvdAt3164 == NULL) {
- if((pM->pszRcvdAt3164 = malloc(16)) == NULL) {
- glblHadMemShortage = 1;
- MsgUnlock(pM);
- return "";
- }
- datetime.formatTimestamp3164(&pM->tRcvdAt, pM->pszRcvdAt3164, 16);
- }
- MsgUnlock(pM);
- return(pM->pszRcvdAt3164);
- case tplFmtRFC3339Date:
- MsgLock(pM);
- if(pM->pszRcvdAt3339 == NULL) {
- if((pM->pszRcvdAt3339 = malloc(33)) == NULL) {
- glblHadMemShortage = 1;
- MsgUnlock(pM);
- return "";
- }
- datetime.formatTimestamp3339(&pM->tRcvdAt, pM->pszRcvdAt3339, 33);
- }
- MsgUnlock(pM);
- return(pM->pszRcvdAt3339);
- }
- return "INVALID eFmt OPTION!";
-}
-
-
-char *getSeverity(msg_t *pM)
-{
- if(pM == NULL)
- return "";
-
- MsgLock(pM);
- if(pM->pszSeverity == NULL) {
- /* we use a 2 byte buffer - can only be one digit */
- if((pM->pszSeverity = malloc(2)) == NULL) { MsgUnlock(pM) ; return ""; }
- pM->iLenSeverity =
- snprintf((char*)pM->pszSeverity, 2, "%d", pM->iSeverity);
- }
- MsgUnlock(pM);
- return((char*)pM->pszSeverity);
-}
-
-
-char *getSeverityStr(msg_t *pM)
-{
- syslogCODE *c;
- int val;
- char *name = NULL;
-
- if(pM == NULL)
- return "";
-
- MsgLock(pM);
- if(pM->pszSeverityStr == NULL) {
- for(c = rs_prioritynames, val = pM->iSeverity; c->c_name; c++)
- if(c->c_val == val) {
- name = c->c_name;
- break;
- }
- if(name == NULL) {
- /* we use a 2 byte buffer - can only be one digit */
- if((pM->pszSeverityStr = malloc(2)) == NULL) { MsgUnlock(pM) ; return ""; }
- pM->iLenSeverityStr =
- snprintf((char*)pM->pszSeverityStr, 2, "%d", pM->iSeverity);
- } else {
- if((pM->pszSeverityStr = (uchar*) strdup(name)) == NULL) { MsgUnlock(pM) ; return ""; }
- pM->iLenSeverityStr = strlen((char*)name);
- }
- }
- MsgUnlock(pM);
- return((char*)pM->pszSeverityStr);
-}
-
-char *getFacility(msg_t *pM)
-{
- if(pM == NULL)
- return "";
-
- MsgLock(pM);
- if(pM->pszFacility == NULL) {
- /* we use a 12 byte buffer - as of
- * syslog-protocol, facility can go
- * up to 2^32 -1
- */
- if((pM->pszFacility = malloc(12)) == NULL) { MsgUnlock(pM) ; return ""; }
- pM->iLenFacility =
- snprintf((char*)pM->pszFacility, 12, "%d", pM->iFacility);
- }
- MsgUnlock(pM);
- return((char*)pM->pszFacility);
-}
-
-char *getFacilityStr(msg_t *pM)
-{
- syslogCODE *c;
- int val;
- char *name = NULL;
-
- if(pM == NULL)
- return "";
-
- MsgLock(pM);
- if(pM->pszFacilityStr == NULL) {
- for(c = rs_facilitynames, val = pM->iFacility << 3; c->c_name; c++)
- if(c->c_val == val) {
- name = c->c_name;
- break;
- }
- if(name == NULL) {
- /* we use a 12 byte buffer - as of
- * syslog-protocol, facility can go
- * up to 2^32 -1
- */
- if((pM->pszFacilityStr = malloc(12)) == NULL) { MsgUnlock(pM) ; return ""; }
- pM->iLenFacilityStr =
- snprintf((char*)pM->pszFacilityStr, 12, "%d", val >> 3);
- } else {
- if((pM->pszFacilityStr = (uchar*)strdup(name)) == NULL) { MsgUnlock(pM) ; return ""; }
- pM->iLenFacilityStr = strlen((char*)name);
- }
- }
- MsgUnlock(pM);
- return((char*)pM->pszFacilityStr);
-}
-
-
-/* set flow control state (if not called, the default - NO_DELAY - is used)
- * This needs no locking because it is only done while the object is
- * not fully constructed (which also means you must not call this
- * method after the msg has been handed over to a queue).
- * rgerhards, 2008-03-14
- */
-rsRetVal
-MsgSetFlowControlType(msg_t *pMsg, flowControl_t eFlowCtl)
-{
- DEFiRet;
- assert(pMsg != NULL);
- assert(eFlowCtl == eFLOWCTL_NO_DELAY || eFlowCtl == eFLOWCTL_LIGHT_DELAY || eFlowCtl == eFLOWCTL_FULL_DELAY);
-
- pMsg->flowCtlType = eFlowCtl;
-
- RETiRet;
-}
-
-
-/* rgerhards 2004-11-24: set APP-NAME in msg object
- * TODO: revisit msg locking code!
- */
-rsRetVal MsgSetAPPNAME(msg_t *pMsg, char* pszAPPNAME)
-{
- DEFiRet;
- assert(pMsg != NULL);
- if(pMsg->pCSAPPNAME == NULL) {
- /* we need to obtain the object first */
- CHKiRet(rsCStrConstruct(&pMsg->pCSAPPNAME));
- rsCStrSetAllocIncrement(pMsg->pCSAPPNAME, 128);
- }
- /* if we reach this point, we have the object */
- iRet = rsCStrSetSzStr(pMsg->pCSAPPNAME, (uchar*) pszAPPNAME);
-
-finalize_it:
- RETiRet;
-}
-
-
-static void tryEmulateAPPNAME(msg_t *pM); /* forward reference */
-/* rgerhards, 2005-11-24
- */
-char *getAPPNAME(msg_t *pM)
-{
- assert(pM != NULL);
- MsgLock(pM);
- if(pM->pCSAPPNAME == NULL)
- tryEmulateAPPNAME(pM);
- MsgUnlock(pM);
- return (pM->pCSAPPNAME == NULL) ? "" : (char*) rsCStrGetSzStrNoNULL(pM->pCSAPPNAME);
-}
-
-
-/* rgerhards 2004-11-24: set PROCID in msg object
- */
-rsRetVal MsgSetPROCID(msg_t *pMsg, char* pszPROCID)
-{
- DEFiRet;
- ISOBJ_TYPE_assert(pMsg, msg);
- if(pMsg->pCSPROCID == NULL) {
- /* we need to obtain the object first */
- CHKiRet(rsCStrConstruct(&pMsg->pCSPROCID));
- rsCStrSetAllocIncrement(pMsg->pCSPROCID, 128);
- }
- /* if we reach this point, we have the object */
- iRet = rsCStrSetSzStr(pMsg->pCSPROCID, (uchar*) pszPROCID);
-
-finalize_it:
- RETiRet;
-}
-
-/* rgerhards, 2005-11-24
- */
-int getPROCIDLen(msg_t *pM)
-{
- assert(pM != NULL);
- MsgLock(pM);
- if(pM->pCSPROCID == NULL)
- aquirePROCIDFromTAG(pM);
- MsgUnlock(pM);
- return (pM->pCSPROCID == NULL) ? 1 : rsCStrLen(pM->pCSPROCID);
-}
-
-
-/* rgerhards, 2005-11-24
- */
-char *getPROCID(msg_t *pM)
-{
- char* pszRet;
-
- ISOBJ_TYPE_assert(pM, msg);
- MsgLock(pM);
- if(pM->pCSPROCID == NULL)
- aquirePROCIDFromTAG(pM);
- pszRet = (pM->pCSPROCID == NULL) ? "-" : (char*) rsCStrGetSzStrNoNULL(pM->pCSPROCID);
- MsgUnlock(pM);
- return pszRet;
-}
-
-
-/* rgerhards 2004-11-24: set MSGID in msg object
- */
-rsRetVal MsgSetMSGID(msg_t *pMsg, char* pszMSGID)
-{
- DEFiRet;
- ISOBJ_TYPE_assert(pMsg, msg);
- if(pMsg->pCSMSGID == NULL) {
- /* we need to obtain the object first */
- CHKiRet(rsCStrConstruct(&pMsg->pCSMSGID));
- rsCStrSetAllocIncrement(pMsg->pCSMSGID, 128);
- }
- /* if we reach this point, we have the object */
- iRet = rsCStrSetSzStr(pMsg->pCSMSGID, (uchar*) pszMSGID);
-
-finalize_it:
- RETiRet;
-}
-
-/* rgerhards, 2005-11-24
- */
-#if 0 /* This method is currently not called, be we like to preserve it */
-static int getMSGIDLen(msg_t *pM)
-{
- return (pM->pCSMSGID == NULL) ? 1 : rsCStrLen(pM->pCSMSGID);
-}
-#endif
-
-
-/* rgerhards, 2005-11-24
- */
-char *getMSGID(msg_t *pM)
-{
- return (pM->pCSMSGID == NULL) ? "-" : (char*) rsCStrGetSzStrNoNULL(pM->pCSMSGID);
-}
-
-
-/* Set the TAG to a caller-provided string. This is thought
- * to be a heap buffer that the caller will no longer use. This
- * function is a performance optimization over MsgSetTAG().
- * rgerhards 2004-11-19
- */
-void MsgAssignTAG(msg_t *pMsg, uchar *pBuf)
-{
- assert(pMsg != NULL);
- pMsg->iLenTAG = (pBuf == NULL) ? 0 : strlen((char*)pBuf);
- pMsg->pszTAG = (uchar*) pBuf;
-}
-
-
-/* rgerhards 2004-11-16: set TAG in msg object
- */
-void MsgSetTAG(msg_t *pMsg, char* pszTAG)
-{
- assert(pMsg != NULL);
- if(pMsg->pszTAG != NULL)
- free(pMsg->pszTAG);
- pMsg->iLenTAG = strlen(pszTAG);
- if((pMsg->pszTAG = malloc(pMsg->iLenTAG + 1)) != NULL)
- memcpy(pMsg->pszTAG, pszTAG, pMsg->iLenTAG + 1);
- else
- dbgprintf("Could not allocate memory in MsgSetTAG()\n");
-}
-
-
-/* This function tries to emulate the TAG if none is
- * set. Its primary purpose is to provide an old-style TAG
- * when a syslog-protocol message has been received. Then,
- * the tag is APP-NAME "[" PROCID "]". The function first checks
- * if there is a TAG and, if not, if it can emulate it.
- * rgerhards, 2005-11-24
- */
-static void tryEmulateTAG(msg_t *pM)
-{
- int iTAGLen;
- uchar *pBuf;
- assert(pM != NULL);
-
- if(pM->pszTAG != NULL)
- return; /* done, no need to emulate */
-
- if(getProtocolVersion(pM) == 1) {
- if(!strcmp(getPROCID(pM), "-")) {
- /* no process ID, use APP-NAME only */
- MsgSetTAG(pM, getAPPNAME(pM));
- } else {
- /* now we can try to emulate */
- iTAGLen = getAPPNAMELen(pM) + getPROCIDLen(pM) + 3;
- if((pBuf = malloc(iTAGLen * sizeof(char))) == NULL)
- return; /* nothing we can do */
- snprintf((char*)pBuf, iTAGLen, "%s[%s]", getAPPNAME(pM), getPROCID(pM));
- MsgAssignTAG(pM, pBuf);
- }
- }
-}
-
-
-#if 0 /* This method is currently not called, be we like to preserve it */
-static int getTAGLen(msg_t *pM)
-{
- if(pM == NULL)
- return 0;
- else {
- tryEmulateTAG(pM);
- if(pM->pszTAG == NULL)
- return 0;
- else
- return pM->iLenTAG;
- }
-}
-#endif
-
-
-char *getTAG(msg_t *pM)
-{
- char *ret;
-
- if(pM == NULL)
- ret = "";
- else {
- MsgLock(pM);
- tryEmulateTAG(pM);
- if(pM->pszTAG == NULL)
- ret = "";
- else
- ret = (char*) pM->pszTAG;
- MsgUnlock(pM);
- }
- return(ret);
-}
-
-
-int getHOSTNAMELen(msg_t *pM)
-{
- if(pM == NULL)
- return 0;
- else
- if(pM->pszHOSTNAME == NULL)
- return 0;
- else
- return pM->iLenHOSTNAME;
-}
-
-
-char *getHOSTNAME(msg_t *pM)
-{
- if(pM == NULL)
- return "";
- else
- if(pM->pszHOSTNAME == NULL)
- return "";
- else
- return (char*) pM->pszHOSTNAME;
-}
-
-
-char *getRcvFrom(msg_t *pM)
-{
- if(pM == NULL)
- return "";
- else
- if(pM->pszRcvFrom == NULL)
- return "";
- else
- return (char*) pM->pszRcvFrom;
-}
-
-/* rgerhards 2004-11-24: set STRUCTURED DATA in msg object
- */
-rsRetVal MsgSetStructuredData(msg_t *pMsg, char* pszStrucData)
-{
- DEFiRet;
- ISOBJ_TYPE_assert(pMsg, msg);
- if(pMsg->pCSStrucData == NULL) {
- /* we need to obtain the object first */
- CHKiRet(rsCStrConstruct(&pMsg->pCSStrucData));
- rsCStrSetAllocIncrement(pMsg->pCSStrucData, 128);
- }
- /* if we reach this point, we have the object */
- iRet = rsCStrSetSzStr(pMsg->pCSStrucData, (uchar*) pszStrucData);
-
-finalize_it:
- RETiRet;
-}
-
-/* get the length of the "STRUCTURED-DATA" sz string
- * rgerhards, 2005-11-24
- */
-#if 0 /* This method is currently not called, be we like to preserve it */
-static int getStructuredDataLen(msg_t *pM)
-{
- return (pM->pCSStrucData == NULL) ? 1 : rsCStrLen(pM->pCSStrucData);
-}
-#endif
-
-
-/* get the "STRUCTURED-DATA" as sz string
- * rgerhards, 2005-11-24
- */
-char *getStructuredData(msg_t *pM)
-{
- return (pM->pCSStrucData == NULL) ? "-" : (char*) rsCStrGetSzStrNoNULL(pM->pCSStrucData);
-}
-
-
-
-/* get the length of the "programname" sz string
- * rgerhards, 2005-10-19
- */
-int getProgramNameLen(msg_t *pM)
-{
- int iRet;
-
- assert(pM != NULL);
- MsgLock(pM);
- if((iRet = aquireProgramName(pM)) != RS_RET_OK) {
- dbgprintf("error %d returned by aquireProgramName() in getProgramNameLen()\n", iRet);
- MsgUnlock(pM);
- return 0; /* best we can do (consistent wiht what getProgramName() returns) */
- }
- MsgUnlock(pM);
-
- return (pM->pCSProgName == NULL) ? 0 : rsCStrLen(pM->pCSProgName);
-}
-
-
-/* get the "programname" as sz string
- * rgerhards, 2005-10-19
- */
-char *getProgramName(msg_t *pM) /* this is the non-locking version for internal use */
-{
- int iRet;
- char *pszRet;
-
- assert(pM != NULL);
- MsgLock(pM);
- if((iRet = aquireProgramName(pM)) != RS_RET_OK) {
- dbgprintf("error %d returned by aquireProgramName() in getProgramName()\n", iRet);
- pszRet = ""; /* best we can do */
- } else {
- pszRet = (pM->pCSProgName == NULL) ? "" : (char*) rsCStrGetSzStrNoNULL(pM->pCSProgName);
- }
-
- MsgUnlock(pM);
- return pszRet;
-}
-/* The code below was an approach without PTHREAD_MUTEX_RECURSIVE
- * However, it turned out to be quite complex. So far, we use recursive
- * locking, which is OK from a performance point of view, especially as
- * we do not anticipate that multithreading msg objects is used often.
- * However, we may re-think about using non-recursive locking and I leave this
- * code in here to conserve the idea. -- rgerhards, 2008-01-05
- */
-#if 0
-static char *getProgramNameNoLock(msg_t *pM) /* this is the non-locking version for internal use */
-{
- int iRet;
-
- assert(pM != NULL);
- if((iRet = aquireProgramName(pM)) != RS_RET_OK) {
- dbgprintf("error %d returned by aquireProgramName() in getProgramName()\n", iRet);
- return ""; /* best we can do */
- }
-
- return (pM->pCSProgName == NULL) ? "" : (char*) rsCStrGetSzStrNoNULL(pM->pCSProgName);
-}
-char *getProgramName(msg_t *pM) /* this is the external callable version */
-{
- char *pszRet;
-
- MsgLock(pM);
- pszRet = getProgramNameNoLock(pM);
- MsgUnlock(pM);
- return pszRet;
-}
-/* an alternative approach has been: */
-/* The macro below is used to generate external function definitions
- * for such functions that may also be called internally (and thus have
- * both a locking and non-locking implementation. Over time, we could
- * reconsider how we handle that. -- rgerhards, 2008-01-05
- */
-#define EXT_LOCKED_FUNC(fName, ret) \
-ret fName(msg_t *pM) \
-{ \
- ret valRet; \
- MsgLock(pM); \
- valRet = fName##NoLock(pM); \
- MsgUnlock(pM); \
- return(valRet); \
-}
-EXT_LOCKED_FUNC(getProgramName, char*)
-/* in this approach, the external function is provided by the macro and
- * needs not to be writen.
- */
-#endif /* #if 0 -- saved code */
-
-
-/* This function tries to emulate APPNAME if it is not present. Its
- * main use is when we have received a log record via legacy syslog and
- * now would like to send out the same one via syslog-protocol.
- */
-static void tryEmulateAPPNAME(msg_t *pM)
-{
- assert(pM != NULL);
- if(pM->pCSAPPNAME != NULL)
- return; /* we are already done */
-
- if(getProtocolVersion(pM) == 0) {
- /* only then it makes sense to emulate */
- MsgSetAPPNAME(pM, getProgramName(pM));
- }
-}
-
-
-/* rgerhards, 2005-11-24
- */
-static int getAPPNAMELen(msg_t *pM)
-{
- assert(pM != NULL);
- if(pM->pCSAPPNAME == NULL)
- tryEmulateAPPNAME(pM);
- return (pM->pCSAPPNAME == NULL) ? 0 : rsCStrLen(pM->pCSAPPNAME);
-}
-
-
-/* rgerhards 2004-11-16: set pszRcvFrom in msg object
- */
-void MsgSetRcvFrom(msg_t *pMsg, char* pszRcvFrom)
-{
- assert(pMsg != NULL);
- if(pMsg->pszRcvFrom != NULL)
- free(pMsg->pszRcvFrom);
-
- pMsg->iLenRcvFrom = strlen(pszRcvFrom);
- if((pMsg->pszRcvFrom = malloc(pMsg->iLenRcvFrom + 1)) != NULL) {
- memcpy(pMsg->pszRcvFrom, pszRcvFrom, pMsg->iLenRcvFrom + 1);
- }
-}
-
-
-/* Set the HOSTNAME to a caller-provided string. This is thought
- * to be a heap buffer that the caller will no longer use. This
- * function is a performance optimization over MsgSetHOSTNAME().
- * rgerhards 2004-11-19
- */
-void MsgAssignHOSTNAME(msg_t *pMsg, char *pBuf)
-{
- assert(pMsg != NULL);
- assert(pBuf != NULL);
- pMsg->iLenHOSTNAME = strlen(pBuf);
- pMsg->pszHOSTNAME = (uchar*) pBuf;
-}
-
-
-/* rgerhards 2004-11-09: set HOSTNAME in msg object
- * rgerhards, 2007-06-21:
- * Does not return anything. If an error occurs, the hostname is
- * simply not set. I have changed this behaviour. The only problem
- * we can run into is memory shortage. If we have such, it is better
- * to loose the hostname than the full message. So we silently ignore
- * that problem and hope that memory will be available the next time
- * we need it. The rest of the code already knows how to handle an
- * unset HOSTNAME.
- */
-void MsgSetHOSTNAME(msg_t *pMsg, char* pszHOSTNAME)
-{
- assert(pMsg != NULL);
- if(pMsg->pszHOSTNAME != NULL)
- free(pMsg->pszHOSTNAME);
-
- pMsg->iLenHOSTNAME = strlen(pszHOSTNAME);
- if((pMsg->pszHOSTNAME = malloc(pMsg->iLenHOSTNAME + 1)) != NULL)
- memcpy(pMsg->pszHOSTNAME, pszHOSTNAME, pMsg->iLenHOSTNAME + 1);
- else
- dbgprintf("Could not allocate memory in MsgSetHOSTNAME()\n");
-}
-
-
-/* Set the UxTradMsg to a caller-provided string. This is thought
- * to be a heap buffer that the caller will no longer use. This
- * function is a performance optimization over MsgSetUxTradMsg().
- * rgerhards 2004-11-19
- */
-#if 0 /* This method is currently not called, be we like to preserve it */
-static void MsgAssignUxTradMsg(msg_t *pMsg, char *pBuf)
-{
- assert(pMsg != NULL);
- assert(pBuf != NULL);
- pMsg->iLenUxTradMsg = strlen(pBuf);
- pMsg->pszUxTradMsg = pBuf;
-}
-#endif
-
-
-/* rgerhards 2004-11-17: set the traditional Unix message in msg object
- */
-int MsgSetUxTradMsg(msg_t *pMsg, char* pszUxTradMsg)
-{
- assert(pMsg != NULL);
- assert(pszUxTradMsg != NULL);
- pMsg->iLenUxTradMsg = strlen(pszUxTradMsg);
- if(pMsg->pszUxTradMsg != NULL)
- free(pMsg->pszUxTradMsg);
- if((pMsg->pszUxTradMsg = malloc(pMsg->iLenUxTradMsg + 1)) != NULL)
- memcpy(pMsg->pszUxTradMsg, pszUxTradMsg, pMsg->iLenUxTradMsg + 1);
- else
- dbgprintf("Could not allocate memory for pszUxTradMsg buffer.");
-
- return(0);
-}
-
-
-/* rgerhards 2004-11-09: set MSG in msg object
- */
-void MsgSetMSG(msg_t *pMsg, char* pszMSG)
-{
- assert(pMsg != NULL);
- assert(pszMSG != NULL);
-
- if(pMsg->pszMSG != NULL)
- free(pMsg->pszMSG);
-
- pMsg->iLenMSG = strlen(pszMSG);
- if((pMsg->pszMSG = (uchar*) malloc(pMsg->iLenMSG + 1)) != NULL)
- memcpy(pMsg->pszMSG, pszMSG, pMsg->iLenMSG + 1);
- else
- dbgprintf("MsgSetMSG could not allocate memory for pszMSG buffer.");
-}
-
-/* rgerhards 2004-11-11: set RawMsg in msg object
- */
-void MsgSetRawMsg(msg_t *pMsg, char* pszRawMsg)
-{
- assert(pMsg != NULL);
- if(pMsg->pszRawMsg != NULL)
- free(pMsg->pszRawMsg);
-
- pMsg->iLenRawMsg = strlen(pszRawMsg);
- if((pMsg->pszRawMsg = (uchar*) malloc(pMsg->iLenRawMsg + 1)) != NULL)
- memcpy(pMsg->pszRawMsg, pszRawMsg, pMsg->iLenRawMsg + 1);
- else
- dbgprintf("Could not allocate memory for pszRawMsg buffer.");
-}
-
-
-/* Decode a priority into textual information like auth.emerg.
- * The variable pRes must point to a user-supplied buffer and
- * pResLen must contain its size. The pointer to the buffer
- * is also returned, what makes this functiona suitable for
- * use in printf-like functions.
- * Note: a buffer size of 20 characters is always sufficient.
- * Interface to this function changed 2007-06-15 by RGerhards
- */
-char *textpri(char *pRes, size_t pResLen, int pri)
-{
- syslogCODE *c_pri, *c_fac;
-
- assert(pRes != NULL);
- assert(pResLen > 0);
-
- for (c_fac = rs_facilitynames; c_fac->c_name && !(c_fac->c_val == LOG_FAC(pri)<<3); c_fac++);
- for (c_pri = rs_prioritynames; c_pri->c_name && !(c_pri->c_val == LOG_PRI(pri)); c_pri++);
-
- snprintf (pRes, pResLen, "%s.%s<%d>", c_fac->c_name, c_pri->c_name, pri);
-
- return pRes;
-}
-
-
-/* This function returns the current date in different
- * variants. It is used to construct the $NOW series of
- * system properties. The returned buffer must be freed
- * by the caller when no longer needed. If the function
- * can not allocate memory, it returns a NULL pointer.
- * Added 2007-07-10 rgerhards
- */
-typedef enum ENOWType { NOW_NOW, NOW_YEAR, NOW_MONTH, NOW_DAY, NOW_HOUR, NOW_HHOUR, NOW_QHOUR, NOW_MINUTE } eNOWType;
-#define tmpBUFSIZE 16 /* size of formatting buffer */
-static uchar *getNOW(eNOWType eNow)
-{
- uchar *pBuf;
- struct syslogTime t;
-
- if((pBuf = (uchar*) malloc(sizeof(uchar) * tmpBUFSIZE)) == NULL) {
- glblHadMemShortage = 1;
- return NULL;
- }
-
- datetime.getCurrTime(&t);
- switch(eNow) {
- case NOW_NOW:
- snprintf((char*) pBuf, tmpBUFSIZE, "%4.4d-%2.2d-%2.2d", t.year, t.month, t.day);
- break;
- case NOW_YEAR:
- snprintf((char*) pBuf, tmpBUFSIZE, "%4.4d", t.year);
- break;
- case NOW_MONTH:
- snprintf((char*) pBuf, tmpBUFSIZE, "%2.2d", t.month);
- break;
- case NOW_DAY:
- snprintf((char*) pBuf, tmpBUFSIZE, "%2.2d", t.day);
- break;
- case NOW_HOUR:
- snprintf((char*) pBuf, tmpBUFSIZE, "%2.2d", t.hour);
- break;
- case NOW_HHOUR:
- snprintf((char*) pBuf, tmpBUFSIZE, "%2.2d", t.minute / 30);
- break;
- case NOW_QHOUR:
- snprintf((char*) pBuf, tmpBUFSIZE, "%2.2d", t.minute / 15);
- break;
- case NOW_MINUTE:
- snprintf((char*) pBuf, tmpBUFSIZE, "%2.2d", t.minute);
- break;
- }
-
- return(pBuf);
-}
-#undef tmpBUFSIZE /* clean up */
-
-
-/* This function returns a string-representation of the
- * requested message property. This is a generic function used
- * to abstract properties so that these can be easier
- * queried. Returns NULL if property could not be found.
- * Actually, this function is a big if..elseif. What it does
- * is simply to map property names (from MonitorWare) to the
- * message object data fields.
- *
- * In case we need string forms of propertis we do not
- * yet have in string form, we do a memory allocation that
- * is sufficiently large (in all cases). Once the string
- * form has been obtained, it is saved until the Msg object
- * is finally destroyed. This is so that we save the processing
- * time in the (likely) case that this property is requested
- * again. It also saves us a lot of dynamic memory management
- * issues in the upper layers, because we so can guarantee that
- * the buffer will remain static AND available during the lifetime
- * of the object. Please note that both the max size allocation as
- * well as keeping things in memory might like look like a
- * waste of memory (some might say it actually is...) - we
- * deliberately accept this because performance is more important
- * to us ;)
- * rgerhards 2004-11-18
- * Parameter "bMustBeFreed" is set by this function. It tells the
- * caller whether or not the string returned must be freed by the
- * caller itself. It is is 0, the caller MUST NOT free it. If it is
- * 1, the caller MUST free 1. Handling this wrongly leads to either
- * a memory leak of a program abort (do to double-frees or frees on
- * the constant memory pool). So be careful to do it right.
- * rgerhards 2004-11-23
- * regular expression support contributed by Andres Riancho merged
- * on 2005-09-13
- * changed so that it now an be called without a template entry (NULL).
- * In this case, only the (unmodified) property is returned. This will
- * be used in selector line processing.
- * rgerhards 2005-09-15
- */
-char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
- cstr_t *pCSPropName, unsigned short *pbMustBeFreed)
-{
- uchar *pName;
- char *pRes; /* result pointer */
- char *pBufStart;
- char *pBuf;
- int iLen;
-
-#ifdef FEATURE_REGEXP
- /* Variables necessary for regular expression matching */
- size_t nmatch = 1;
- regmatch_t pmatch[1];
-#endif
-
- assert(pMsg != NULL);
- assert(pbMustBeFreed != NULL);
-
- if(pCSPropName == NULL) {
- assert(pTpe != NULL);
- pName = pTpe->data.field.pPropRepl;
- } else {
- pName = rsCStrGetSzStrNoNULL(pCSPropName);
- }
- *pbMustBeFreed = 0;
-
- /* sometimes there are aliases to the original MonitoWare
- * property names. These come after || in the ifs below. */
- if(!strcmp((char*) pName, "msg")) {
- pRes = getMSG(pMsg);
- } else if(!strcmp((char*) pName, "rawmsg")) {
- pRes = getRawMsg(pMsg);
- } else if(!strcmp((char*) pName, "uxtradmsg")) {
- pRes = getUxTradMsg(pMsg);
- } else if(!strcmp((char*) pName, "fromhost")) {
- pRes = getRcvFrom(pMsg);
- } else if(!strcmp((char*) pName, "source") || !strcmp((char*) pName, "hostname")) {
- pRes = getHOSTNAME(pMsg);
- } else if(!strcmp((char*) pName, "syslogtag")) {
- pRes = getTAG(pMsg);
- } else if(!strcmp((char*) pName, "pri")) {
- pRes = getPRI(pMsg);
- } else if(!strcmp((char*) pName, "pri-text")) {
- pBuf = malloc(20 * sizeof(char));
- if(pBuf == NULL) {
- *pbMustBeFreed = 0;
- return "**OUT OF MEMORY**";
- } else {
- *pbMustBeFreed = 1;
- pRes = textpri(pBuf, 20, getPRIi(pMsg));
- }
- } else if(!strcmp((char*) pName, "iut")) {
- pRes = "1"; /* always 1 for syslog messages (a MonitorWare thing;)) */
- } else if(!strcmp((char*) pName, "syslogfacility")) {
- pRes = getFacility(pMsg);
- } else if(!strcmp((char*) pName, "syslogfacility-text")) {
- pRes = getFacilityStr(pMsg);
- } else if(!strcmp((char*) pName, "syslogseverity") || !strcmp((char*) pName, "syslogpriority")) {
- pRes = getSeverity(pMsg);
- } else if(!strcmp((char*) pName, "syslogseverity-text") || !strcmp((char*) pName, "syslogpriority-text")) {
- pRes = getSeverityStr(pMsg);
- } else if(!strcmp((char*) pName, "timegenerated")) {
- pRes = getTimeGenerated(pMsg, pTpe->data.field.eDateFormat);
- } else if(!strcmp((char*) pName, "timereported")
- || !strcmp((char*) pName, "timestamp")) {
- pRes = getTimeReported(pMsg, pTpe->data.field.eDateFormat);
- } else if(!strcmp((char*) pName, "programname")) {
- pRes = getProgramName(pMsg);
- } else if(!strcmp((char*) pName, "protocol-version")) {
- pRes = getProtocolVersionString(pMsg);
- } else if(!strcmp((char*) pName, "structured-data")) {
- pRes = getStructuredData(pMsg);
- } else if(!strcmp((char*) pName, "app-name")) {
- pRes = getAPPNAME(pMsg);
- } else if(!strcmp((char*) pName, "procid")) {
- pRes = getPROCID(pMsg);
- } else if(!strcmp((char*) pName, "msgid")) {
- pRes = getMSGID(pMsg);
- /* here start system properties (those, that do not relate to the message itself */
- } else if(!strcmp((char*) pName, "$now")) {
- if((pRes = (char*) getNOW(NOW_NOW)) == NULL) {
- return "***OUT OF MEMORY***";
- } else
- *pbMustBeFreed = 1; /* all of these functions allocate dyn. memory */
- } else if(!strcmp((char*) pName, "$year")) {
- if((pRes = (char*) getNOW(NOW_YEAR)) == NULL) {
- return "***OUT OF MEMORY***";
- } else
- *pbMustBeFreed = 1; /* all of these functions allocate dyn. memory */
- } else if(!strcmp((char*) pName, "$month")) {
- if((pRes = (char*) getNOW(NOW_MONTH)) == NULL) {
- return "***OUT OF MEMORY***";
- } else
- *pbMustBeFreed = 1; /* all of these functions allocate dyn. memory */
- } else if(!strcmp((char*) pName, "$day")) {
- if((pRes = (char*) getNOW(NOW_DAY)) == NULL) {
- return "***OUT OF MEMORY***";
- } else
- *pbMustBeFreed = 1; /* all of these functions allocate dyn. memory */
- } else if(!strcmp((char*) pName, "$hour")) {
- if((pRes = (char*) getNOW(NOW_HOUR)) == NULL) {
- return "***OUT OF MEMORY***";
- } else
- *pbMustBeFreed = 1; /* all of these functions allocate dyn. memory */
- } else if(!strcmp((char*) pName, "$hhour")) {
- if((pRes = (char*) getNOW(NOW_HHOUR)) == NULL) {
- return "***OUT OF MEMORY***";
- } else
- *pbMustBeFreed = 1; /* all of these functions allocate dyn. memory */
- } else if(!strcmp((char*) pName, "$qhour")) {
- if((pRes = (char*) getNOW(NOW_QHOUR)) == NULL) {
- return "***OUT OF MEMORY***";
- } else
- *pbMustBeFreed = 1; /* all of these functions allocate dyn. memory */
- } else if(!strcmp((char*) pName, "$minute")) {
- if((pRes = (char*) getNOW(NOW_MINUTE)) == NULL) {
- return "***OUT OF MEMORY***";
- } else
- *pbMustBeFreed = 1; /* all of these functions allocate dyn. memory */
- } else {
- /* there is no point in continuing, we may even otherwise render the
- * error message unreadable. rgerhards, 2007-07-10
- */
- dbgprintf("invalid property name: '%s'\n", pName);
- return "**INVALID PROPERTY NAME**";
- }
-
- /* If we did not receive a template pointer, we are already done... */
- if(pTpe == NULL) {
- return pRes;
- }
-
- /* Now check if we need to make "temporary" transformations (these
- * are transformations that do not go back into the message -
- * memory must be allocated for them!).
- */
-
- /* substring extraction */
- /* first we check if we need to extract by field number
- * rgerhards, 2005-12-22
- */
- if(pTpe->data.field.has_fields == 1) {
- size_t iCurrFld;
- char *pFld;
- char *pFldEnd;
- /* first, skip to the field in question. The field separator
- * is always one character and is stored in the template entry.
- */
- iCurrFld = 1;
- pFld = pRes;
- while(*pFld && iCurrFld < pTpe->data.field.iToPos) {
- /* skip fields until the requested field or end of string is found */
- while(*pFld && (uchar) *pFld != pTpe->data.field.field_delim)
- ++pFld; /* skip to field terminator */
- if(*pFld == pTpe->data.field.field_delim) {
- ++pFld; /* eat it */
- ++iCurrFld;
- }
- }
- dbgprintf("field requested %d, field found %d\n", pTpe->data.field.iToPos, (int) iCurrFld);
-
- if(iCurrFld == pTpe->data.field.iToPos) {
- /* field found, now extract it */
- /* first of all, we need to find the end */
- pFldEnd = pFld;
- while(*pFldEnd && *pFldEnd != pTpe->data.field.field_delim)
- ++pFldEnd;
- --pFldEnd; /* we are already at the delimiter - so we need to
- * step back a little not to copy it as part of the field. */
- /* we got our end pointer, now do the copy */
- /* TODO: code copied from below, this is a candidate for a separate function */
- iLen = pFldEnd - pFld + 1; /* the +1 is for an actual char, NOT \0! */
- pBufStart = pBuf = malloc((iLen + 1) * sizeof(char));
- if(pBuf == NULL) {
- if(*pbMustBeFreed == 1)
- free(pRes);
- *pbMustBeFreed = 0;
- return "**OUT OF MEMORY**";
- }
- /* now copy */
- memcpy(pBuf, pFld, iLen);
- pBuf[iLen] = '\0'; /* terminate it */
- if(*pbMustBeFreed == 1)
- free(pRes);
- pRes = pBufStart;
- *pbMustBeFreed = 1;
- if(*(pFldEnd+1) != '\0')
- ++pFldEnd; /* OK, skip again over delimiter char */
- } else {
- /* field not found, return error */
- if(*pbMustBeFreed == 1)
- free(pRes);
- *pbMustBeFreed = 0;
- return "**FIELD NOT FOUND**";
- }
- } else if(pTpe->data.field.iFromPos != 0 || pTpe->data.field.iToPos != 0) {
- /* we need to obtain a private copy */
- int iFrom, iTo;
- char *pSb;
- iFrom = pTpe->data.field.iFromPos;
- iTo = pTpe->data.field.iToPos;
- /* need to zero-base to and from (they are 1-based!) */
- if(iFrom > 0)
- --iFrom;
- if(iTo > 0)
- --iTo;
- iLen = iTo - iFrom + 1; /* the +1 is for an actual char, NOT \0! */
- pBufStart = pBuf = malloc((iLen + 1) * sizeof(char));
- if(pBuf == NULL) {
- if(*pbMustBeFreed == 1)
- free(pRes);
- *pbMustBeFreed = 0;
- return "**OUT OF MEMORY**";
- }
- pSb = pRes;
- if(iFrom) {
- /* skip to the start of the substring (can't do pointer arithmetic
- * because the whole string might be smaller!!)
- */
- while(*pSb && iFrom) {
- --iFrom;
- ++pSb;
- }
- }
- /* OK, we are at the begin - now let's copy... */
- while(*pSb && iLen) {
- *pBuf++ = *pSb;
- ++pSb;
- --iLen;
- }
- *pBuf = '\0';
- if(*pbMustBeFreed == 1)
- free(pRes);
- pRes = pBufStart;
- *pbMustBeFreed = 1;
-#ifdef FEATURE_REGEXP
- } else {
- /* Check for regular expressions */
- if (pTpe->data.field.has_regex != 0) {
- if (pTpe->data.field.has_regex == 2)
- /* Could not compile regex before! */
- return "**NO MATCH** **BAD REGULAR EXPRESSION**";
-
- dbgprintf("debug: String to match for regex is: %s\n", pRes);
-
- if(objUse(regexp, LM_REGEXP_FILENAME) == RS_RET_OK) {
- if (0 != regexp.regexec(&pTpe->data.field.re, pRes, nmatch, pmatch, 0)) {
- /* we got no match! */
- if (*pbMustBeFreed == 1) {
- free(pRes);
- *pbMustBeFreed = 0;
- }
- return "**NO MATCH**";
- } else {
- /* Match! */
- /* I need to malloc pB */
- int iLenBuf;
- char *pB;
-
- iLenBuf = pmatch[0].rm_eo - pmatch[0].rm_so;
- pB = (char *) malloc((iLenBuf + 1) * sizeof(char));
-
- if (pB == NULL) {
- if (*pbMustBeFreed == 1)
- free(pRes);
- *pbMustBeFreed = 0;
- return "**OUT OF MEMORY ALLOCATING pBuf**";
- }
-
- /* Lets copy the matched substring to the buffer */
- memcpy(pB, pRes + pmatch[0].rm_so, iLenBuf);
- pB[iLenBuf] = '\0';/* terminate string, did not happen before */
-
- if (*pbMustBeFreed == 1)
- free(pRes);
- pRes = pB;
- *pbMustBeFreed = 1;
- }
- } else {
- /* we could not load regular expression support. This is quite unexpected at
- * this stage of processing (after all, the config parser found it), but so
- * it is. We return an error in that case. -- rgerhards, 2008-03-07
- */
- dbgprintf("could not get regexp object pointer, so regexp can not be evaluated\n");
- if (*pbMustBeFreed == 1) {
- free(pRes);
- *pbMustBeFreed = 0;
- }
- return "***REGEXP NOT AVAILABLE***";
- }
- }
-#endif /* #ifdef FEATURE_REGEXP */
- }
-
- /* now check if we need to do our "SP if first char is non-space" hack logic */
- if(*pRes && pTpe->data.field.options.bSPIffNo1stSP) {
- char *pB;
- uchar cFirst = *pRes;
-
- /* here, we always destruct the buffer and return a new one */
- pB = (char *) malloc(2 * sizeof(char));
- if(pB == NULL) {
- if(*pbMustBeFreed == 1)
- free(pRes);
- *pbMustBeFreed = 0;
- return "**OUT OF MEMORY**";
- }
- pRes = pB;
- *pbMustBeFreed = 1;
-
- if(cFirst == ' ') {
- /* if we have a SP, we must return an empty string */
- *pRes = '\0'; /* empty */
- } else {
- /* if it is no SP, we need to return one */
- *pRes = ' ';
- *(pRes+1) = '\0';
- }
- }
-
- if(*pRes) {
- /* case conversations (should go after substring, because so we are able to
- * work on the smallest possible buffer).
- */
- if(pTpe->data.field.eCaseConv != tplCaseConvNo) {
- /* we need to obtain a private copy */
- int iBufLen = strlen(pRes);
- char *pBStart;
- char *pB;
- char *pSrc;
- pBStart = pB = malloc((iBufLen + 1) * sizeof(char));
- if(pB == NULL) {
- if(*pbMustBeFreed == 1)
- free(pRes);
- *pbMustBeFreed = 0;
- return "**OUT OF MEMORY**";
- }
- pSrc = pRes;
- while(*pSrc) {
- *pB++ = (pTpe->data.field.eCaseConv == tplCaseConvUpper) ?
- (char)toupper((int)*pSrc) : (char)tolower((int)*pSrc);
- /* currently only these two exist */
- ++pSrc;
- }
- *pB = '\0';
- if(*pbMustBeFreed == 1)
- free(pRes);
- pRes = pBStart;
- *pbMustBeFreed = 1;
- }
-
- /* now do control character dropping/escaping/replacement
- * Only one of these can be used. If multiple options are given, the
- * result is random (though currently there obviously is an order of
- * preferrence, see code below. But this is NOT guaranteed.
- * RGerhards, 2006-11-17
- * We must copy the strings if we modify them, because they may either
- * point to static memory or may point into the message object, in which
- * case we would actually modify the original property (which of course
- * is wrong).
- * This was found and fixed by varmojefkoj on 2007-09-11
- */
- if(pTpe->data.field.options.bDropCC) {
- int iLenBuf = 0;
- char *pSrc = pRes;
- char *pDstStart;
- char *pDst;
- char bDropped = 0;
-
- while(*pSrc) {
- if(!iscntrl((int) *pSrc++))
- iLenBuf++;
- else
- bDropped = 1;
- }
-
- if(bDropped) {
- pDst = pDstStart = malloc(iLenBuf + 1);
- if(pDst == NULL) {
- if(*pbMustBeFreed == 1)
- free(pRes);
- *pbMustBeFreed = 0;
- return "**OUT OF MEMORY**";
- }
- for(pSrc = pRes; *pSrc; pSrc++) {
- if(!iscntrl((int) *pSrc))
- *pDst++ = *pSrc;
- }
- *pDst = '\0';
- if(*pbMustBeFreed == 1)
- free(pRes);
- pRes = pDstStart;
- *pbMustBeFreed = 1;
- }
- } else if(pTpe->data.field.options.bSpaceCC) {
- char *pSrc;
- char *pDstStart;
- char *pDst;
-
- if(*pbMustBeFreed == 1) {
- /* in this case, we already work on dynamic
- * memory, so there is no need to copy it - we can
- * modify it in-place without any harm. This is a
- * performance optiomization.
- */
- for(pDst = pRes; *pDst; pDst++) {
- if(iscntrl((int) *pDst))
- *pDst = ' ';
- }
- } else {
- pDst = pDstStart = malloc(strlen(pRes) + 1);
- if(pDst == NULL) {
- if(*pbMustBeFreed == 1)
- free(pRes);
- *pbMustBeFreed = 0;
- return "**OUT OF MEMORY**";
- }
- for(pSrc = pRes; *pSrc; pSrc++) {
- if(iscntrl((int) *pSrc))
- *pDst++ = ' ';
- else
- *pDst++ = *pSrc;
- }
- *pDst = '\0';
- pRes = pDstStart;
- *pbMustBeFreed = 1;
- }
- } else if(pTpe->data.field.options.bEscapeCC) {
- /* we must first count how many control charactes are
- * present, because we need this to compute the new string
- * buffer length. While doing so, we also compute the string
- * length.
- */
- int iNumCC = 0;
- int iLenBuf = 0;
- char *pB;
-
- for(pB = pRes ; *pB ; ++pB) {
- ++iLenBuf;
- if(iscntrl((int) *pB))
- ++iNumCC;
- }
-
- if(iNumCC > 0) { /* if 0, there is nothing to escape, so we are done */
- /* OK, let's do the escaping... */
- char *pBStart;
- char szCCEsc[8]; /* buffer for escape sequence */
- int i;
-
- iLenBuf += iNumCC * 4;
- pBStart = pB = malloc((iLenBuf + 1) * sizeof(char));
- if(pB == NULL) {
- if(*pbMustBeFreed == 1)
- free(pRes);
- *pbMustBeFreed = 0;
- return "**OUT OF MEMORY**";
- }
- while(*pRes) {
- if(iscntrl((int) *pRes)) {
- snprintf(szCCEsc, sizeof(szCCEsc), "#%3.3d", *pRes);
- for(i = 0 ; i < 4 ; ++i)
- *pB++ = szCCEsc[i];
- } else {
- *pB++ = *pRes;
- }
- ++pRes;
- }
- *pB = '\0';
- if(*pbMustBeFreed == 1)
- free(pRes);
- pRes = pBStart;
- *pbMustBeFreed = 1;
- }
- }
- }
-
- /* Take care of spurious characters to make the property safe
- * for a path definition
- */
- if(pTpe->data.field.options.bSecPathDrop || pTpe->data.field.options.bSecPathReplace) {
- if(pTpe->data.field.options.bSecPathDrop) {
- int iLenBuf = 0;
- char *pSrc = pRes;
- char *pDstStart;
- char *pDst;
- char bDropped = 0;
-
- while(*pSrc) {
- if(*pSrc++ != '/')
- iLenBuf++;
- else
- bDropped = 1;
- }
-
- if(bDropped) {
- pDst = pDstStart = malloc(iLenBuf + 1);
- if(pDst == NULL) {
- if(*pbMustBeFreed == 1)
- free(pRes);
- *pbMustBeFreed = 0;
- return "**OUT OF MEMORY**";
- }
- for(pSrc = pRes; *pSrc; pSrc++) {
- if(*pSrc != '/')
- *pDst++ = *pSrc;
- }
- *pDst = '\0';
- if(*pbMustBeFreed == 1)
- free(pRes);
- pRes = pDstStart;
- *pbMustBeFreed = 1;
- }
- } else {
- char *pSrc;
- char *pDstStart;
- char *pDst;
-
- if(*pbMustBeFreed == 1) {
- /* here, again, we can modify the string as we already obtained
- * a private buffer. As we do not change the size of that buffer,
- * in-place modification is possible. This is a performance
- * enhancement.
- */
- for(pDst = pRes; *pDst; pDst++) {
- if(*pDst == '/')
- *pDst++ = '_';
- }
- } else {
- pDst = pDstStart = malloc(strlen(pRes) + 1);
- if(pDst == NULL) {
- if(*pbMustBeFreed == 1)
- free(pRes);
- *pbMustBeFreed = 0;
- return "**OUT OF MEMORY**";
- }
- for(pSrc = pRes; *pSrc; pSrc++) {
- if(*pSrc == '/')
- *pDst++ = '_';
- else
- *pDst++ = *pSrc;
- }
- *pDst = '\0';
- /* we must NOT check if it needs to be freed, because we have done
- * this in the if above. So if we come to hear, the pSrc string needs
- * not to be freed (and we do not need to care about it).
- */
- pRes = pDstStart;
- *pbMustBeFreed = 1;
- }
- }
-
- /* check for "." and ".." (note the parenthesis in the if condition!) */
- if((*pRes == '.') && (*(pRes + 1) == '\0' || (*(pRes + 1) == '.' && *(pRes + 2) == '\0'))) {
- char *pTmp = pRes;
-
- if(*(pRes + 1) == '\0')
- pRes = "_";
- else
- pRes = "_.";;
- if(*pbMustBeFreed == 1)
- free(pTmp);
- *pbMustBeFreed = 0;
- } else if(*pRes == '\0') {
- if(*pbMustBeFreed == 1)
- free(pRes);
- pRes = "_";
- *pbMustBeFreed = 0;
- }
- }
-
- /* Now drop last LF if present (pls note that this must not be done
- * if bEscapeCC was set!
- */
- if(pTpe->data.field.options.bDropLastLF && !pTpe->data.field.options.bEscapeCC) {
- int iLn = strlen(pRes);
- char *pB;
- if(iLn > 0 && *(pRes + iLn - 1) == '\n') {
- /* we have a LF! */
- /* check if we need to obtain a private copy */
- if(*pbMustBeFreed == 0) {
- /* ok, original copy, need a private one */
- pB = malloc((iLn + 1) * sizeof(char));
- if(pB == NULL) {
- *pbMustBeFreed = 0;
- return "**OUT OF MEMORY**";
- }
- memcpy(pB, pRes, iLn - 1);
- pRes = pB;
- *pbMustBeFreed = 1;
- }
- *(pRes + iLn - 1) = '\0'; /* drop LF ;) */
- }
- }
-
- /*dbgprintf("MsgGetProp(\"%s\"): \"%s\"\n", pName, pRes); only for verbose debug logging */
- return(pRes);
-}
-
-
-/* The returns a message variable suitable for use with RainerScript. Most importantly, this means
- * that the value is returned in a var_t object. The var_t is constructed inside this function and
- * MUST be freed by the caller.
- * rgerhards, 2008-02-25
- */
-rsRetVal
-msgGetMsgVar(msg_t *pThis, cstr_t *pstrPropName, var_t **ppVar)
-{
- DEFiRet;
- var_t *pVar;
- uchar *pszProp = NULL;
- cstr_t *pstrProp;
- unsigned short bMustBeFreed = 0;
-
- ISOBJ_TYPE_assert(pThis, msg);
- ASSERT(pstrPropName != NULL);
- ASSERT(ppVar != NULL);
-
- /* make sure we have a var_t instance */
- CHKiRet(var.Construct(&pVar));
- CHKiRet(var.ConstructFinalize(pVar));
-
- /* always call MsgGetProp() without a template specifier */
- pszProp = (uchar*) MsgGetProp(pThis, NULL, pstrPropName, &bMustBeFreed);
-
- /* now create a string object out of it and hand that over to the var */
- CHKiRet(rsCStrConstructFromszStr(&pstrProp, pszProp));
- CHKiRet(var.SetString(pVar, pstrProp));
-
- /* finally store var */
- *ppVar = pVar;
-
-finalize_it:
- if(bMustBeFreed)
- free(pszProp);
-
- RETiRet;
-}
-
-
-/* This function can be used as a generic way to set properties.
- * We have to handle a lot of legacy, so our return value is not always
- * 100% correct (called functions do not always provide one, should
- * change over time).
- * rgerhards, 2008-01-07
- */
-#define isProp(name) !rsCStrSzStrCmp(pProp->pcsName, (uchar*) name, sizeof(name) - 1)
-rsRetVal MsgSetProperty(msg_t *pThis, var_t *pProp)
-{
- DEFiRet;
-
- ISOBJ_TYPE_assert(pThis, msg);
- assert(pProp != NULL);
-
- if(isProp("iProtocolVersion")) {
- setProtocolVersion(pThis, pProp->val.num);
- } else if(isProp("iSeverity")) {
- pThis->iSeverity = pProp->val.num;
- } else if(isProp("iFacility")) {
- pThis->iFacility = pProp->val.num;
- } else if(isProp("msgFlags")) {
- pThis->msgFlags = pProp->val.num;
- } else if(isProp("pszRawMsg")) {
- MsgSetRawMsg(pThis, (char*) rsCStrGetSzStrNoNULL(pProp->val.pStr));
- } else if(isProp("pszMSG")) {
- MsgSetMSG(pThis, (char*) rsCStrGetSzStrNoNULL(pProp->val.pStr));
- } else if(isProp("pszUxTradMsg")) {
- MsgSetUxTradMsg(pThis, (char*) rsCStrGetSzStrNoNULL(pProp->val.pStr));
- } else if(isProp("pszTAG")) {
- MsgSetTAG(pThis, (char*) rsCStrGetSzStrNoNULL(pProp->val.pStr));
- } else if(isProp("pszRcvFrom")) {
- MsgSetHOSTNAME(pThis, (char*) rsCStrGetSzStrNoNULL(pProp->val.pStr));
- } else if(isProp("pszHOSTNAME")) {
- MsgSetRcvFrom(pThis, (char*) rsCStrGetSzStrNoNULL(pProp->val.pStr));
- } else if(isProp("pCSStrucData")) {
- MsgSetStructuredData(pThis, (char*) rsCStrGetSzStrNoNULL(pProp->val.pStr));
- } else if(isProp("pCSAPPNAME")) {
- MsgSetAPPNAME(pThis, (char*) rsCStrGetSzStrNoNULL(pProp->val.pStr));
- } else if(isProp("pCSPROCID")) {
- MsgSetPROCID(pThis, (char*) rsCStrGetSzStrNoNULL(pProp->val.pStr));
- } else if(isProp("pCSMSGID")) {
- MsgSetMSGID(pThis, (char*) rsCStrGetSzStrNoNULL(pProp->val.pStr));
- } else if(isProp("tRcvdAt")) {
- memcpy(&pThis->tRcvdAt, &pProp->val.vSyslogTime, sizeof(struct syslogTime));
- } else if(isProp("tTIMESTAMP")) {
- memcpy(&pThis->tTIMESTAMP, &pProp->val.vSyslogTime, sizeof(struct syslogTime));
- }
-
- RETiRet;
-}
-#undef isProp
-
-
-/* This is a construction finalizer that must be called after all properties
- * have been set. It does some final work on the message object. After this
- * is done, the object is considered ready for full processing.
- * rgerhards, 2008-07-08
- */
-static rsRetVal msgConstructFinalizer(msg_t *pThis)
-{
- MsgPrepareEnqueue(pThis);
- return RS_RET_OK;
-}
-
-
-/* get the severity - this is an entry point that
- * satisfies the base object class getSeverity semantics.
- * rgerhards, 2008-01-14
- */
-static rsRetVal
-MsgGetSeverity(obj_t *pThis, int *piSeverity)
-{
- ISOBJ_TYPE_assert(pThis, msg);
- assert(piSeverity != NULL);
- *piSeverity = ((msg_t*) pThis)->iSeverity;
- return RS_RET_OK;
-}
-
-
-/* dummy */
-rsRetVal msgQueryInterface(void) { return RS_RET_NOT_IMPLEMENTED; }
-
-/* Initialize the message class. Must be called as the very first method
- * before anything else is called inside this class.
- * rgerhards, 2008-01-04
- */
-BEGINObjClassInit(msg, 1, OBJ_IS_CORE_MODULE)
- /* request objects we use */
- CHKiRet(objUse(var, CORE_COMPONENT));
- CHKiRet(objUse(datetime, CORE_COMPONENT));
-
- /* set our own handlers */
- OBJSetMethodHandler(objMethod_SERIALIZE, MsgSerialize);
- OBJSetMethodHandler(objMethod_SETPROPERTY, MsgSetProperty);
- OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, msgConstructFinalizer);
- OBJSetMethodHandler(objMethod_GETSEVERITY, MsgGetSeverity);
- /* initially, we have no need to lock message objects */
- funcLock = MsgLockingDummy;
- funcUnlock = MsgLockingDummy;
- funcDeleteMutex = MsgLockingDummy;
- funcMsgPrepareEnqueue = MsgLockingDummy;
-ENDObjClassInit(msg)
-
-/*
- * vi:set ai:
- */