summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog127
-rw-r--r--Makefile.am30
-rw-r--r--action.c23
-rw-r--r--action.h9
-rw-r--r--configure.ac72
-rw-r--r--doc/Makefile.am3
-rw-r--r--doc/build_from_repo.html29
-rw-r--r--doc/debug.html2
-rw-r--r--doc/imsolaris.html47
-rw-r--r--doc/imtcp.html28
-rw-r--r--doc/manual.html3
-rw-r--r--doc/module_workflow.pngbin0 -> 14749 bytes
-rw-r--r--doc/rsconf1_escape8bitcharsonreceive.html44
-rw-r--r--doc/rsyslog_conf_global.html11
-rw-r--r--doc/rsyslog_conf_modules.html55
-rw-r--r--doc/src/module_workflow.diabin0 -> 1700 bytes
-rw-r--r--doc/src/tls.diabin4656 -> 5201 bytes
-rw-r--r--doc/status.html39
-rw-r--r--doc/troubleshoot.html54
-rw-r--r--gss-misc.c25
-rw-r--r--plugins/imdiag/imdiag.c5
-rw-r--r--plugins/imgssapi/imgssapi.c20
-rw-r--r--plugins/imklog/solaris.c184
-rw-r--r--plugins/imklog/solaris_cddl.c293
-rw-r--r--plugins/imklog/solaris_cddl.h2
-rw-r--r--plugins/imsolaris/Makefile.am6
-rw-r--r--plugins/imsolaris/imsolaris.c399
-rw-r--r--plugins/imsolaris/imsolaris.h2
-rw-r--r--plugins/imsolaris/sun_cddl.c419
-rw-r--r--plugins/imsolaris/sun_cddl.h7
-rw-r--r--plugins/imtcp/imtcp.c7
-rw-r--r--plugins/imudp/imudp.c82
-rw-r--r--plugins/imuxsock/imuxsock.c33
-rw-r--r--plugins/omdbalerting/Makefile.am8
-rw-r--r--plugins/omdbalerting/omdbalerting.c144
-rw-r--r--plugins/omprog/omprog.c3
-rw-r--r--plugins/omstdout/omstdout.c2
-rw-r--r--runtime/Makefile.am12
-rw-r--r--runtime/atomic-posix-sem.c70
-rw-r--r--runtime/atomic.h122
-rw-r--r--runtime/cfsysline.c8
-rw-r--r--runtime/debug.c30
-rw-r--r--runtime/debug.h5
-rw-r--r--runtime/glbl.c12
-rw-r--r--runtime/glbl.h13
-rw-r--r--runtime/modules.c30
-rw-r--r--runtime/msg.c145
-rw-r--r--runtime/msg.h26
-rw-r--r--runtime/net.c69
-rw-r--r--runtime/net.h7
-rw-r--r--runtime/netstrms.c3
-rw-r--r--runtime/nsd.h9
-rw-r--r--runtime/nsd_ptcp.c12
-rw-r--r--runtime/nsdpoll_ptcp.c288
-rw-r--r--runtime/nsdpoll_ptcp.h60
-rw-r--r--runtime/nsdsel_ptcp.c51
-rw-r--r--runtime/nsdsel_ptcp.h5
-rw-r--r--runtime/nspoll.c198
-rw-r--r--runtime/nspoll.h65
-rw-r--r--runtime/nssel.c1
-rw-r--r--runtime/parser.c62
-rw-r--r--runtime/parser.h4
-rw-r--r--runtime/queue.h10
-rw-r--r--runtime/rsyslog.c14
-rw-r--r--runtime/rsyslog.h38
-rw-r--r--runtime/rule.h2
-rw-r--r--runtime/srutils.c27
-rw-r--r--runtime/stream.c7
-rw-r--r--runtime/stream.h16
-rw-r--r--runtime/unlimited_select.h45
-rw-r--r--runtime/wti.c4
-rw-r--r--runtime/wti.h6
-rw-r--r--runtime/wtp.c7
-rw-r--r--solaris/README38
-rw-r--r--solaris/cddllicense.txt242
-rw-r--r--tcps_sess.c2
-rw-r--r--tcpsrv.c164
-rw-r--r--tcpsrv.h10
-rw-r--r--template.c1
-rw-r--r--tests/Makefile.am38
-rwxr-xr-xtests/complex1.sh9
-rwxr-xr-xtests/diag.sh36
-rw-r--r--tests/diagtalker.c157
-rwxr-xr-xtests/dircreate_dflt.sh20
-rwxr-xr-xtests/dircreate_off.sh20
-rwxr-xr-xtests/dynfile_invalid2.sh4
-rwxr-xr-xtests/gzipwr_large_dynfile.sh4
-rw-r--r--tests/historical/DiagTalker.java (renamed from tests/DiagTalker.java)1
-rw-r--r--tests/historical/README2
-rw-r--r--tests/msleep.c51
-rw-r--r--tests/nettester.c85
-rwxr-xr-xtests/parsertest.sh4
-rwxr-xr-xtests/random.sh20
-rw-r--r--tests/randomgen.c130
-rw-r--r--tests/rt-init.c2
-rwxr-xr-xtests/tabescape_dflt.sh14
-rwxr-xr-xtests/tabescape_off.sh14
-rw-r--r--tests/tcpflood.c157
-rw-r--r--tests/testsuites/1.tabescape_dflt3
-rw-r--r--tests/testsuites/1.tabescape_off3
-rw-r--r--tests/testsuites/8bit.parse12
-rw-r--r--tests/testsuites/8bit.parse_8bit_escape2
-rw-r--r--tests/testsuites/dircreate_dflt.conf11
-rw-r--r--tests/testsuites/dircreate_off.conf12
-rw-r--r--tests/testsuites/empty.parse13
-rw-r--r--tests/testsuites/mark.parse17
-rw-r--r--tests/testsuites/parse_8bit_escape.conf9
-rw-r--r--tests/testsuites/random.conf13
-rw-r--r--tests/testsuites/tabescape_dflt.conf8
-rw-r--r--tests/testsuites/tabescape_off.conf10
-rwxr-xr-xtests/threadingmqaq.sh3
-rw-r--r--threads.c2
-rw-r--r--threads.h4
-rw-r--r--tools/omfile.c52
-rw-r--r--tools/ompipe.c3
-rw-r--r--tools/syncdemo.c318
-rw-r--r--tools/syslogd.c132
117 files changed, 5113 insertions, 409 deletions
diff --git a/ChangeLog b/ChangeLog
index a24a18ba..380bea50 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,69 @@
---------------------------------------------------------------------------
+Version 5.5.4 [DEVEL] (rgerhards), 2010-04-??
+- bugfix: netstream ptcp support class was not correctly build on systems
+ without epoll() support
+- bugfix: [NOT YET FIXED] segfault on Solaris/Sparc
+---------------------------------------------------------------------------
+Version 5.5.3 [DEVEL] (rgerhards), 2010-04-09
+- added basic but functional support for Solaris
+- imported many bugfixes from 3.6.2/4.6.1 (see ChangeLog below!)
+- added new property replacer option "date-rfc3164-buggyday" primarily
+ to ease migration from syslog-ng. See property replacer doc for
+ details.
+- added capability to turn off standard LF delimiter in TCP server
+ via new directive "$InputTCPServerDisableLFDelimiter on"
+- bugfix: failed to compile on systems without epoll support
+- bugfix: comment char ('#') in literal terminated script parsing
+ and thus could not be used.
+ but tracker: http://bugzilla.adiscon.com/show_bug.cgi?id=119
+ [merged in from v3.22.2]
+- imported patches from 4.6.0:
+ * improved testbench to contain samples for totally malformed messages
+ which miss parts of the message content
+ * bugfix: some malformed messages could lead to a missing LF inside files
+ or some other missing parts of the template content.
+ * bugfix: if a message ended immediately with a hostname, the hostname
+ was mistakenly interpreted as TAG, and localhost be used as hostname
+---------------------------------------------------------------------------
+Version 5.5.2 [DEVEL] (rgerhards), 2010-02-05
+- applied patches that make rsyslog compile under Apple OS X.
+ Thanks to trey for providing these.
+- replaced data type "bool" by "sbool" because this created some
+ portability issues.
+- added $Escape8BitCharactersOnReceive directive
+ Thanks to David Lang for suggesting it.
+- worked around an issue where omfile failed to compile on 32 bit platforms
+ under some circumstances (this smells like a gcc problem, but a simple
+ solution was available). Thanks to Kenneth Marshall for some advice.
+- extended testbench
+---------------------------------------------------------------------------
+Version 5.5.1 [DEVEL] (rgerhards), 2009-11-27
+- introduced the ablity for netstream drivers to utilize an epoll interface
+ This offers increased performance and removes the select() FDSET size
+ limit from imtcp. Note that we fall back to select() if there is no
+ epoll netstream drivers. So far, an epoll driver has only been
+ implemented for plain tcp syslog, the rest will follow once the code
+ proves well in practice AND there is demand.
+- re-implemented $EscapeControlCharacterTab config directive
+ Based on Jonathan Bond-Caron's patch for v4. This now also includes some
+ automatted tests.
+- bugfix: enabling GSSServer crashes rsyslog startup
+ Thanks to Tomas Kubina for the patch [imgssapi]
+- bugfix (kind of): check if TCP connection is still alive if using TLS
+ Thanks to Jonathan Bond-Caron for the patch.
+---------------------------------------------------------------------------
+Version 5.5.0 [DEVEL] (rgerhards), 2009-11-18
+- moved DNS resolution code out of imudp and into the backend processing
+ Most importantly, DNS resolution now never happens if the resolved name
+ is not required. Note that this applies to imudp - for the other inputs,
+ DNS resolution almost comes for free, so we do not do it there. However,
+ the new method has been implemented in a generic way and as such may
+ also be used by other modules in the future.
+- added option to use unlimited-size select() calls
+ Thanks to varmjofekoj for the patch
+ This is not done in imudp, as it natively supports epoll().
+- doc: improved description of what loadable modules can do
+---------------------------------------------------------------------------
Version 5.4.2 [v5-stable] (rgerhards), 2010-03-??
- bugfix(kind of): output plugin retry behaviour could cause engine to loop
The rsyslog engine did not guard itself against output modules that do
@@ -48,6 +113,16 @@ Version 5.3.7 [BETA] (rgerhards), 2010-01-27
a stack-based pointer which lead to destruction of the stack frame and
thus a segfault on function return.
Thanks to Michael Biebl for alerting us on this problem.
+- bugfix: hostname accidently set to IP address for some message sources,
+ for example imudp. Thanks to Anton for reporting this bug. [imported v4]
+- bugfix: ompgsql had problems with transaction support, what actually
+ rendered it unsuable. Thanks to forum user "horhe" for alerting me
+ on this bug and helping to debug/fix it! [imported from 5.3.6]
+- bugfix: $CreateDirs variable not properly initialized, default thus
+ was random (but most often "on") [imported from v3]
+- bugfix: potential segfaults during queue shutdown
+ (bugs require certain non-standard settings to appear)
+ Thanks to varmojfekoj for the patch [imported from 4.5.8]
[backport from 5.5.2]
- bugfix: wrong memory assignment for a config variable (probably
without causing any harm) [backport from 5.2.2]
@@ -349,7 +424,19 @@ increase.
- increased ompgsql performance by adapting to new transactional
output module interface
---------------------------------------------------------------------------
-Version 4.7.0 [v4-devel] (rgerhards), 2009-09-??
+Version 4.7.2 [v4-devel] (rgerhards), 2010-04-??
+- added new $Sleep directive to hold processing for a couple of seconds
+ during startup
+---------------------------------------------------------------------------
+Version 4.7.1 [v4-devel] (rgerhards), 2010-04-22
+- Solaris support much improved -- was not truely usable in 4.7.0
+ Solaris is no longer supported in imklog, but rather there is a new
+ plugin imsolaris, which is used to pull local log sources on a Solaris
+ machine.
+- testbench improvement: Java is no longer needed for testing tool creation
+---------------------------------------------------------------------------
+Version 4.7.0 [v4-devel] (rgerhards), 2010-04-14
+- new: support for Solaris added (but not yet the Solaris door API)
- added function getenv() to RainerScript
- added new config option $InputUnixListenSocketCreatePath
to permit the auto-creation of pathes to additional log sockets. This
@@ -362,11 +449,49 @@ Version 4.7.0 [v4-devel] (rgerhards), 2009-09-??
- added new config directive $omfileForceChown to (try to) fix some broken
system configs.
See ticket for details: http://bugzilla.adiscon.com/show_bug.cgi?id=150
+- added $EscapeControlCharacterTab config directive
+ Thanks to Jonathan Bond-Caron for the patch.
+- added option to use unlimited-size select() calls
+ Thanks to varmjofekoj for the patch
+- debugondemand mode caused backgrounding to fail - close to a bug, but I'd
+ consider the ability to background in this mode a new feature...
+- bugfix (kind of): check if TCP connection is still alive if using TLS
+ Thanks to Jonathan Bond-Caron for the patch.
+- imported changes from 4.5.7 and below
+- bugfix: potential segfault when -p command line option was used
+ Thanks for varmojfekoj for pointing me at this bug.
- imported changes from 4.5.6 and below
---------------------------------------------------------------------------
+Version 4.6.3 [v4-stable] (rgerhards), 2010-03-??
+- bugfix: potential segfaults during queue shutdown
+ (bugs require certain non-standard settings to appear)
+ Thanks to varmojfekoj for the patch [imported from 4.5.8]
+- improvded testbench
+ - added test with truly random data received via syslog to test
+ robustness
+ - added new configure option that permits to disable and enable an
+ extended testbench
+- bugfix: default for $OMFileFlushOnTXEnd was wrong ("off").
+ This, in default mode, caused buffered writing to be used, what
+ means that it looked like no output were written or partial
+ lines. Thanks to Michael Biebl for pointing out this bug.
+- bugfix: testbench failed when not executed in UTC+1 timezone
+ accidently, the time zone information was kept inside some
+ to-be-checked-for responses
+- temporary bugfix replaced by permanent one for
+ message-induced off-by-one error (potential segfault) (see 4.6.2)
+ The analysis has been completed and a better fix been crafted and
+ integrated.
+- bugfix: the T/P/E config size specifiers did not work properly under
+ all 32-bit platforms
+- bugfix: local unix system log socket was deleted even when it was
+ not configured
+---------------------------------------------------------------------------
Version 4.6.2 [v4-stable] (rgerhards), 2010-03-26
- new feature: "." action type added to support writing files to relative
pathes (this is primarily meant as a debug aid)
+- added replacements for atomic instructions on systems that do not
+ support them. [backport of Stefen Sledz' patch for v5)
- new feature: $OMFileAsyncWriting directive added
it permits to specifiy if asynchronous writing should be done or not
- bugfix(temporary): message-induced off-by-one error (potential segfault)
diff --git a/Makefile.am b/Makefile.am
index 5f9d35fe..41b2de73 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -59,6 +59,10 @@ if ENABLE_IMKLOG
SUBDIRS += plugins/imklog
endif
+if ENABLE_IMSOLARIS
+SUBDIRS += plugins/imsolaris
+endif
+
if ENABLE_GSSAPI
SUBDIRS += plugins/omgssapi plugins/imgssapi
endif
@@ -99,6 +103,10 @@ if ENABLE_OMRULESET
SUBDIRS += plugins/omruleset
endif
+if ENABLE_OMDBALERTING
+SUBDIRS += plugins/omdbalerting
+endif
+
if ENABLE_OMUDPSPOOF
SUBDIRS += plugins/omudpspoof
endif
@@ -146,5 +154,25 @@ SUBDIRS += tests
# temporarily be removed below. The intent behind forcing everthing to compile
# in a make distcheck is so that we detect code that accidently was not updated
# when some global update happened.
-DISTCHECK_CONFIGURE_FLAGS=--enable-gssapi_krb5 --enable-imfile --enable-snmp --enable-pgsql --enable-libdbi --enable-mysql --enable-omtemplate --enable-imtemplate --enable-relp --enable-rsyslogd --enable-mail --enable-klog --enable-diagtools --enable-gnutls --enable-omstdout --enable-omruleset --enable-omprog --enable-imdiag --enable-shave --enable-memcheck
+DISTCHECK_CONFIGURE_FLAGS= --enable-gssapi_krb5 \
+ --enable-imfile \
+ --enable-snmp \
+ --enable-pgsql \
+ --enable-libdbi \
+ --enable-mysql \
+ --enable-omtemplate \
+ --enable-imtemplate \
+ --enable-relp \
+ --enable-rsyslogd \
+ --enable-mail \
+ --enable-klog \
+ --enable-diagtools \
+ --enable-gnutls \
+ --enable-omstdout \
+ --enable-omruleset \
+ --enable-omprog \
+ --enable-imdiag \
+ --enable-shave \
+ --enable-extended-tests \
+ --enable-memcheck
ACLOCAL_AMFLAGS = -I m4
diff --git a/action.c b/action.c
index 305b6a5c..7751fe0a 100644
--- a/action.c
+++ b/action.c
@@ -208,7 +208,7 @@ rsRetVal actionDestruct(action_t *pThis)
/* message ptr cleanup */
for(i = 0 ; i < pThis->iNumTpls ; ++i) {
- if(pThis->ppMsgs[i] != NULL) {
+ if(((uchar**)pThis->ppMsgs)[i] != NULL) {
switch(pThis->eParamPassing) {
case ACT_ARRAY_PASSING:
#if 0 /* later, as an optimization. So far, we do the cleanup after each message */
@@ -222,7 +222,7 @@ rsRetVal actionDestruct(action_t *pThis)
#endif
break;
case ACT_STRING_PASSING:
- d_free(pThis->ppMsgs[i]);
+ d_free(((uchar**)pThis->ppMsgs)[i]);
break;
case ACT_MSG_PASSING:
/* No cleanup needed in this case */
@@ -649,16 +649,16 @@ static rsRetVal prepareDoActionParams(action_t *pAction, msg_t *pMsg)
for(i = 0 ; i < pAction->iNumTpls ; ++i) {
switch(pAction->eParamPassing) {
case ACT_STRING_PASSING:
- CHKiRet(tplToString(pAction->ppTpl[i], pMsg, &(pAction->ppMsgs[i]), &(pAction->lenMsgs[i])));
+ CHKiRet(tplToString(pAction->ppTpl[i], pMsg, &(((uchar**)pAction->ppMsgs)[i]), &(pAction->lenMsgs[i])));
break;
case ACT_ARRAY_PASSING:
- CHKiRet(tplToArray(pAction->ppTpl[i], pMsg, (uchar***) &(pAction->ppMsgs[i])));
+ CHKiRet(tplToArray(pAction->ppTpl[i], pMsg, (uchar***) &(((uchar**)pAction->ppMsgs)[i])));
break;
case ACT_MSG_PASSING:
/* we abuse the uchar* ptr, it now actually is a void*, but we can not
* change that other than by chaning the interface, what we don't like...
*/
- pAction->ppMsgs[i] = (uchar*) pMsg;
+ ((uchar**)pAction->ppMsgs)[i] = (uchar*) pMsg;
break;
default:assert(0); /* software bug if this happens! */
}
@@ -680,16 +680,16 @@ static rsRetVal cleanupDoActionParams(action_t *pAction)
ASSERT(pAction != NULL);
for(i = 0 ; i < pAction->iNumTpls ; ++i) {
- if(pAction->ppMsgs[i] != NULL) {
+ if(((uchar**)pAction->ppMsgs)[i] != NULL) {
switch(pAction->eParamPassing) {
case ACT_ARRAY_PASSING:
iArr = 0;
- while(((char **)pAction->ppMsgs[i])[iArr] != NULL) {
- d_free(((char **)pAction->ppMsgs[i])[iArr++]);
- ((char **)pAction->ppMsgs[i])[iArr++] = NULL;
+ while((((uchar***)pAction->ppMsgs)[i][iArr]) != NULL) {
+ d_free(((uchar ***)pAction->ppMsgs)[i][iArr++]);
+ ((uchar ***)pAction->ppMsgs)[i][iArr++] = NULL;
}
- d_free(pAction->ppMsgs[i]);
- pAction->ppMsgs[i] = NULL;
+ d_free(((uchar**)pAction->ppMsgs)[i]);
+ ((uchar**)pAction->ppMsgs)[i] = NULL;
break;
case ACT_MSG_PASSING:
case ACT_STRING_PASSING:
@@ -949,6 +949,7 @@ submitBatch(action_t *pAction, batch_t *pBatch, int nElem, int *pbShutdownImmedi
} else {
if(nElem == 1) {
pBatch->pElem[pBatch->iDoneUpTo++].state = BATCH_STATE_BAD;
+// TODO: This is a mark, remove when no longer needed - Here was the bug, postincrement needs to be used, not preinc
bDone = 1;
} else {
/* retry with half as much. Depth is log_2 batchsize, so recursion is not too deep */
diff --git a/action.h b/action.h
index 4a6c3c88..66b7316d 100644
--- a/action.h
+++ b/action.h
@@ -52,8 +52,8 @@ struct action_s {
time_t tActNow; /* the current time for an action execution. Initially set to -1 and
populated on an as-needed basis. This is a performance optimization. */
time_t tLastExec; /* time this action was last executed */
- bool bExecWhenPrevSusp;/* execute only when previous action is suspended? */
- bool bWriteAllMarkMsgs;/* should all mark msgs be written (not matter how recent the action was executed)? */
+ sbool bExecWhenPrevSusp;/* execute only when previous action is suspended? */
+ sbool bWriteAllMarkMsgs;/* should all mark msgs be written (not matter how recent the action was executed)? */
int iSecsExecOnceInterval; /* if non-zero, minimum seconds to wait until action is executed again */
action_state_t eState; /* current state of action */
bool bHadAutoCommit; /* did an auto-commit happen during doAction()? */
@@ -68,7 +68,7 @@ struct action_s {
time_t tLastOccur; /* time last occurence was seen (for timing them out) */
struct modInfo_s *pMod;/* pointer to output module handling this selector */
void *pModData; /* pointer to module data - content is module-specific */
- bool bRepMsgHasMsg; /* "message repeated..." has msg fragment in it (0-no, 1-yes) */
+ sbool bRepMsgHasMsg; /* "message repeated..." has msg fragment in it (0-no, 1-yes) */
short f_ReduceRepeated;/* reduce repeated lines 0 - no, 1 - yes */
int f_prevcount; /* repetition cnt of prevline */
int f_repeatcount; /* number of "repeated" msgs */
@@ -85,7 +85,8 @@ struct action_s {
SYNC_OBJ_TOOL; /* required for mutex support */
pthread_mutex_t mutActExec; /* mutex to guard actual execution of doAction for single-threaded modules */
uchar *pszName; /* action name (for documentation) */
- uchar **ppMsgs; /* pointer to action-calling parameters (kept in structure to save alloc() time!) */
+ //uchar **ppMsgs; /* pointer to action-calling parameters (kept in structure to save alloc() time!) */
+ void *ppMsgs; /* pointer to action-calling parameters (kept in structure to save alloc() time!) */
size_t *lenMsgs; /* length of message in ppMsgs */
};
typedef struct action_s action_t;
diff --git a/configure.ac b/configure.ac
index 030db218..a2434b78 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.61)
-AC_INIT([rsyslog],[5.4.0],[rsyslog@lists.adiscon.com])
+AC_INIT([rsyslog],[5.5.3],[rsyslog@lists.adiscon.com])
AM_INIT_AUTOMAKE
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
@@ -87,6 +87,7 @@ AC_TYPE_UINT8_T
AC_HEADER_TIME
AC_STRUCT_TM
AC_C_VOLATILE
+AC_C_TYPEOF
sa_includes="\
$ac_includes_default
@@ -130,6 +131,9 @@ AC_TRY_COMPILE([
RS_ATOMIC_OPERATIONS
RS_ATOMIC_OPERATIONS_64BIT
+# fall back to POSIX sems for atomic operations (cpu expensive)
+AC_CHECK_HEADERS([semaphore.h])
+
# Additional module directories
AC_ARG_WITH(moddirs,
@@ -279,6 +283,7 @@ AC_ARG_ENABLE(klog,
AM_CONDITIONAL(ENABLE_IMKLOG, test x$enable_klog = xyes)
AM_CONDITIONAL(ENABLE_IMKLOG_BSD, test x$os_type = xbsd)
AM_CONDITIONAL(ENABLE_IMKLOG_LINUX, test x$os_type = xlinux)
+AM_CONDITIONAL(ENABLE_IMKLOG_SOLARIS, test x$os_type = xsolaris)
#
@@ -340,6 +345,21 @@ AC_ARG_ENABLE([fsstnd],
])
+# support for unlimited select() syscall
+AC_ARG_ENABLE(unlimited_select,
+ [AS_HELP_STRING([--enable-unlimited-select],[Enable unlimited select() syscall @<:@default=no@:>@])],
+ [case "${enableval}" in
+ yes) enable_unlimited_select="yes" ;;
+ no) enable_unlimited_select="no" ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for --enable-unlimited-select) ;;
+ esac],
+ [enable_unlimited_select="no"]
+)
+if test "$enable_unlimited_select" = "yes"; then
+ AC_DEFINE(USE_UNLIMITED_SELECT, 1, [If defined, the select() syscall won't be limited to a particular number of file descriptors.])
+fi
+
+
# debug
AC_ARG_ENABLE(debug,
[AS_HELP_STRING([--enable-debug],[Enable debug mode @<:@default=no@:>@])],
@@ -632,6 +652,23 @@ AC_ARG_ENABLE(rsyslogd,
AM_CONDITIONAL(ENABLE_RSYSLOGD, test x$enable_rsyslogd = xyes)
+# capability to enable an extended testbench. By default, this is off. The reason
+# for this switch is that some test simply take too long to execute them on a regular
+# basis. So we enable to skip them, while the majority of tests can still be used. The
+# idea is that at least "make distcheck" executes the extended testbench, and also
+# developers should explicitely enable it after important changes. -- rgerhards, 2010-04-12
+AC_ARG_ENABLE(extended_tests,
+ [AS_HELP_STRING([--enable-extended-tests],[extended testbench @<:@default=no@:>@])],
+ [case "${enableval}" in
+ yes) enable_rsyslogd="yes" ;;
+ no) enable_rsyslogd="no" ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for --enable-extended-tests) ;;
+ esac],
+ [enable_extended_tests=no]
+)
+AM_CONDITIONAL(ENABLE_EXTENDED_TESTS, test x$enable_extended_tests = xyes)
+
+
# Mail support (so far we do not need a library, but we need to turn this on and off)
AC_ARG_ENABLE(mail,
[AS_HELP_STRING([--enable-mail],[Enable mail support @<:@default=no@:>@])],
@@ -730,6 +767,19 @@ AC_ARG_ENABLE(imfile,
AM_CONDITIONAL(ENABLE_IMFILE, test x$enable_imfile = xyes)
+# settings for the door input module (under solaris, thus default off)
+AC_ARG_ENABLE(imsolaris,
+ [AS_HELP_STRING([--enable-imsolaris],[door input module enabled @<:@default=no@:>@])],
+ [case "${enableval}" in
+ yes) enable_imsolaris="yes" ;;
+ no) enable_imsolaris="no" ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for --enable-imsolaris) ;;
+ esac],
+ [enable_imsolaris=no]
+)
+AM_CONDITIONAL(ENABLE_IMSOLARIS, test x$enable_imsolaris = xyes)
+
+
# settings for the omprog output module
AC_ARG_ENABLE(omprog,
[AS_HELP_STRING([--enable-omprog],[Compiles omprog module @<:@default=no@:>@])],
@@ -799,6 +849,20 @@ AC_ARG_ENABLE(omruleset,
AM_CONDITIONAL(ENABLE_OMRULESET, test x$enable_omruleset = xyes)
+# settings for omdbalerting
+AC_ARG_ENABLE(omdbalerting,
+ [AS_HELP_STRING([--enable-omdbalerting],[Compiles omdbalerting module @<:@default=no@:>@])],
+ [case "${enableval}" in
+ yes) enable_omdbalerting="yes" ;;
+ no) enable_omdbalerting="no" ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for --enable-omdbalerting) ;;
+ esac],
+ [enable_omdbalerting=no]
+)
+AM_CONDITIONAL(ENABLE_OMDBALERTING, test x$enable_omdbalerting = xyes)
+
+
+
# building the GUI (mostly for diagnostic reasons)
AC_ARG_ENABLE(gui,
[AS_HELP_STRING([--enable-gui],[Enable GUI programs @<:@default=no@:>@])],
@@ -890,7 +954,9 @@ AC_CONFIG_FILES([Makefile \
plugins/omprog/Makefile \
plugins/omstdout/Makefile \
plugins/omruleset/Makefile \
+ plugins/omdbalerting/Makefile \
plugins/imfile/Makefile \
+ plugins/imsolaris/Makefile \
plugins/imrelp/Makefile \
plugins/imdiag/Makefile \
plugins/omtesting/Makefile \
@@ -919,11 +985,13 @@ echo " rsyslog runtime will be built: $enable_rsyslogrt"
echo " rsyslogd will be built: $enable_rsyslogd"
echo " GUI components will be built: $enable_gui"
echo " custom module 1 will be built: $enable_cust1"
+echo " Unlimited select() support enabled: $enable_unlimited_select"
echo
echo "---{ input plugins }---"
echo " Klog functionality enabled: $enable_klog ($os_type)"
echo " imdiag enabled: $enable_imdiag"
echo " file input module enabled: $enable_imfile"
+echo " Solaris input module enabled: $enable_imsolaris"
echo " input template module will be compiled: $enable_imtemplate"
echo
echo "---{ output plugins }---"
@@ -931,6 +999,7 @@ echo " Mail support enabled: $enable_mail"
echo " omprog module will be compiled: $enable_omprog"
echo " omstdout module will be compiled: $enable_omstdout"
echo " omruleset module will be compiled: $enable_omruleset"
+echo " omdbalerting module will be compiled: $enable_omdbalerting"
echo " omudpspoof module will be compiled: $enable_omudpspoof"
echo " output template module will be compiled: $enable_omtemplate"
echo
@@ -948,6 +1017,7 @@ echo " SNMP support enabled: $enable_snmp"
echo
echo "---{ debugging support }---"
echo " Testbench enabled: $enable_testbench"
+echo " Extended Testbench enabled: $enable_extended_tests"
echo " Debug mode enabled: $enable_debug"
echo " Runtime Instrumentation enabled: $enable_rtinst"
echo " Diagnostic tools enabled: $enable_diagtools"
diff --git a/doc/Makefile.am b/doc/Makefile.am
index f1c3f871..3d900cac 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -41,6 +41,7 @@ html_files = \
imtcp.html \
imgssapi.html \
imrelp.html \
+ imsolaris.html \
imuxsock.html \
imklog.html \
professional_support.html \
@@ -66,6 +67,7 @@ html_files = \
rsconf1_actionresumeinterval.html \
rsconf1_allowedsender.html \
rsconf1_controlcharacterescapeprefix.html \
+ rsconf1_escape8bitcharsonreceive.html \
rsconf1_debugprintcfsyslinehandlerlist.html \
rsconf1_debugprintmodulelist.html \
rsconf1_debugprinttemplatelist.html \
@@ -123,6 +125,7 @@ html_files = \
grfx_files = \
rsyslog_confgraph_complex.png\
rsyslog_confgraph_std.png \
+ module_workflow.png \
direct_queue0.png \
direct_queue1.png \
direct_queue2.png \
diff --git a/doc/build_from_repo.html b/doc/build_from_repo.html
index 8d3b20fe..a06863e1 100644
--- a/doc/build_from_repo.html
+++ b/doc/build_from_repo.html
@@ -43,12 +43,37 @@ you downloaded an official distribution tarball (see the
<a href="install.html">rsyslog install guide</a>, starting at step 2,
for further details about that).
+<h2>Special Compile-Time Options</h2>
+<p>On some platforms, compile-time issues occur, like the one shown below:
+<p><pre><code>
+make[2]: Entering directory `/home/az/RSyslog/rsyslog-5.5.0/tools'
+ CCLD rsyslogd
+rsyslogd-omfile.o: In function `getClockFileAccess':
+/home/az/RSyslog/rsyslog-5.5.0/tools/omfile.c:91: undefined reference to `__sync_fetch_and_add_8'
+/home/az/RSyslog/rsyslog-5.5.0/tools/omfile.c:91: undefined reference to `__sync_fetch_and_add_8'
+/home/az/RSyslog/rsyslog-5.5.0/tools/omfile.c:91: undefined reference to `__sync_fetch_and_add_8'
+</code></pre>
+<p>Note that the exact error messages can be different. These type of errors stem down to
+atomic instruction support in GCC, which is somewhat depending on the machine architecture it
+compiles code for. Very old machines (like the original i386) do not even at all provide support
+for these instructions.
+<p>The availability of atomic instructions is vital for rsyslog - it can not be built without them.
+Consequently, there is a configure check included for them. But under some circumstances,
+GCC seems to report they are available, but does not provide implementations for
+all of them (at least this is my observation...). The simple cure is to make sure that
+GCC generates code for a modern-enough architecture. This, for example, can be done as
+follows:
+<p><pre><code>
+./configure CFLAGS="-march=i586 -mcpu=i686" --enable-imfile ... (whatever you need)
+</code></pre>
+<p>These settings should resolve the issue .
+
<p>[<a href="manual.html">manual index</a>]
[<a href="http://www.rsyslog.com/">rsyslog site</a>]</p>
<p><font size="2">This documentation is part of the
<a href="http://www.rsyslog.com/">rsyslog</a> project.<br>
-Copyright &copy; 2008 by <a href="http://www.gerhards.net/rainer">Rainer Gerhards</a> and
+Copyright &copy; 2008, 2009 by <a href="http://www.gerhards.net/rainer">Rainer Gerhards</a> and
<a href="http://www.adiscon.com/">Adiscon</a>. Released under the GNU GPL
-version 1.2 or higher.</font></p>
+version 3 or higher.</font></p>
</body>
</html>
diff --git a/doc/debug.html b/doc/debug.html
index 46759986..6aeb7975 100644
--- a/doc/debug.html
+++ b/doc/debug.html
@@ -138,7 +138,7 @@ instance of rsyslogd can be aborted by pressing ctl-c.
<p>[<a href="manual.html">manual index</a>] [<a href="http://www.rsyslog.com/">rsyslog site</a>]</p>
<p><font size="2">This documentation is part of the
<a href="http://www.rsyslog.com/">rsyslog</a> project.<br>
-Copyright &copy; 2008, 2009 by <a href="http://www.gerhards.net/rainer">Rainer Gerhards</a> and
+Copyright &copy; 2008-2010 by <a href="http://www.gerhards.net/rainer">Rainer Gerhards</a> and
<a href="http://www.adiscon.com/">Adiscon</a>.
Released under the GNU GPL version 3 or higher.</font></p>
</body>
diff --git a/doc/imsolaris.html b/doc/imsolaris.html
new file mode 100644
index 00000000..ce0e7e84
--- /dev/null
+++ b/doc/imsolaris.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head>
+<meta http-equiv="Content-Language" content="en">
+<title>Solaris Input Module (imsolaris)</title>
+
+</head>
+<body>
+<a href="rsyslog_conf_modules.html">back</a>
+
+<h1>Solaris Input Module</h1>
+<p><b>Module Name:&nbsp;&nbsp;&nbsp; imsolaris</b></p>
+<p><b>Author: </b>Rainer Gerhards
+&lt;rgerhards@adiscon.com&gt;</p>
+<p><b>Description</b>:</p>
+<p>Reads local Solaris log messages including the kernel log.</p>
+<p>This module is specifically tailored for Solaris. Under Solaris, there
+is no special kernel input device. Instead, both kernel messages as well as
+messages emitted via syslog() are received from a single source.
+<p>This module obeys the Solaris door() mechanism to detect a running syslogd
+instance. As such, only one can be active at one time. If it detects another
+active intance at startup, the module disables itself, but rsyslog will
+continue to run.
+<p><b>Configuration Directives</b>:</p>
+<ul>
+<li><strong>$IMSolarisLogSocketName &lt;name&gt;</strong><br>
+This is the name of the log socket (stream) to read. If not given, /dev/log
+is read.
+</li>
+</ul>
+<b>Caveats/Known Bugs:</b>
+<p>None currently known. For obvious reasons, works on Solaris, only (and compilation
+will most probably fail on any other platform).
+<p><b>Sample:</b></p>
+<p>The following sample pulls messages from the default log source
+<br>
+</p>
+<textarea rows="15" cols="60">$ModLoad imsolaris
+</textarea>
+<p>[<a href="rsyslog_conf.html">rsyslog.conf overview</a>]
+[<a href="manual.html">manual index</a>] [<a href="http://www.rsyslog.com/">rsyslog site</a>]</p>
+<p><font size="2">This documentation is part of the
+<a href="http://www.rsyslog.com/">rsyslog</a>
+project.<br>
+Copyright &copy; 2010 by <a href="http://www.gerhards.net/rainer">Rainer Gerhards</a> and
+<a href="http://www.adiscon.com/">Adiscon</a>.
+Released under the GNU GPL version 3 or higher.</font></p>
+</body></html>
diff --git a/doc/imtcp.html b/doc/imtcp.html
index 434b3903..422bbd55 100644
--- a/doc/imtcp.html
+++ b/doc/imtcp.html
@@ -23,7 +23,7 @@ versions do NOT support it.
</p>
<p><b>Configuration Directives</b>:</p>
<ul>
-<li>$InputTCPServerAddtlFrameDelimiter &lt;Delimiter&gt;<br>
+<li><b>$InputTCPServerAddtlFrameDelimiter &lt;Delimiter&gt;</b><br>
This directive permits to specify an additional frame delimiter for plain tcp syslog.
The industry-standard specifies using the LF character as frame delimiter. Some vendors,
notable Juniper in their NetScreen products, use an invalid frame delimiter, in Juniper's
@@ -43,28 +43,36 @@ very limited interest in fixing this issue. This directive <b>can not</b> fix th
That would require much more code changes, which I was unable to do so far. Full details
can be found at the <a href="http://www.rsyslog.com/Article321.phtml">Cisco tcp syslog anomaly</a>
page.
-<li>$InputTCPServerNotifyOnConnectionClose [on/<b>off</b>] (available since 4.5.5)<br>
+<li><b>$InputTCPServerDisableLFDelimiter</b> &lt;on/<b>off</b>&gt; (available since 5.5.3)<br>
+Industry-strandard plain text tcp syslog uses the LF to delimit syslog frames. However,
+some users brought up the case that it may be useful to define a different delimiter and
+totally disable LF as a delimiter (the use case named were multi-line messages). This mode
+is non-standard and will probably come with a lot of problems. However, as there is need
+for it and it is relatively easy to support, we do so. Be sure to turn this setting to
+"on" only if you exactly know what you are doing. You may run into all sorts of troubles,
+so be prepared to wrangle with that!
+<li><b>$InputTCPServerNotifyOnConnectionClose</b> [on/<b>off</b>] (available since 4.5.5)<br>
instructs imtcp to emit a message if the remote peer closes a connection.<br>
<b>Important:</b> This directive is global to all listeners and must be given right
after loading imtcp, otherwise it may have no effect.</li>
-<li>$InputTCPServerRun &lt;port&gt;<br>
+<li><b>$InputTCPServerRun</b> &lt;port&gt;<br>
Starts a TCP server on selected port</li>
-<li>$InputTCPMaxListeners &lt;number&gt;<br>
+<li><b>$InputTCPMaxListeners</b> &lt;number&gt;<br>
Sets the maximum number of listeners (server ports) supported. Default is 20. This must be set before the first $InputTCPServerRun directive.</li>
-<li>$InputTCPMaxSessions &lt;number&gt;<br> Sets the maximum number of sessions supported. Default is 200. This must be set before the first $InputTCPServerRun directive</li>
-<li>$InputTCPServerStreamDriverMode &lt;number&gt;<br>
+<li><b>$InputTCPMaxSessions</b> &lt;number&gt;<br> Sets the maximum number of sessions supported. Default is 200. This must be set before the first $InputTCPServerRun directive</li>
+<li><b>$InputTCPServerStreamDriverMode</b> &lt;number&gt;<br>
Sets the driver mode for the currently selected <a href="netstream.html">network stream driver</a>. &lt;number&gt; is driver specifc.</li>
-<li>$InputTCPServerInputName &lt;name&gt;<br>
+<li><b>$InputTCPServerInputName</b> &lt;name&gt;<br>
Sets a name for the inputname property. If no name is set "imtcp" is used by default. Setting a
name is not strictly necessary, but can be useful to apply filtering based on which input
the message was received from.
-<li>$InputTCPServerStreamDriverAuthMode &lt;mode-string&gt;<br>
+<li><b>$InputTCPServerStreamDriverAuthMode</b> &lt;mode-string&gt;<br>
Sets the authentication mode for the currently selected <a href="netstream.html">network stream driver</a>. &lt;mode-string&gt; is driver specifc.</li>
-<li>$InputTCPServerStreamDriverPermittedPeer &lt;id-string&gt;<br>
+<li><b>$InputTCPServerStreamDriverPermittedPeer</b> &lt;id-string&gt;<br>
Sets permitted peer IDs. Only these peers are able to connect to the
listener. &lt;id-string&gt; semantics depend on the currently selected
AuthMode and&nbsp; <a href="netstream.html">network stream driver</a>. PermittedPeers may not be set in anonymous modes.</li>
-<li>$InputTCPServerBindRuleset &lt;ruleset&gt;<br>
+<li><b>$InputTCPServerBindRuleset</b> &lt;ruleset&gt;<br>
Binds the listener to a specific <a href="multi_ruleset.html">ruleset</a>.</li>
</ul>
<b>Caveats/Known Bugs:</b>
diff --git a/doc/manual.html b/doc/manual.html
index c744c3fa..8ab61609 100644
--- a/doc/manual.html
+++ b/doc/manual.html
@@ -19,7 +19,7 @@ rsyslog support</a> available directly from the source!</p>
<p><b>Please visit the <a href="http://www.rsyslog.com/sponsors">rsyslog sponsor's page</a>
to honor the project sponsors or become one yourself!</b> We are very grateful for any help towards the
project goals.</p>
-<p><b>This documentation is for version 5.4.0 (v5-stable branch) of rsyslog.</b>
+<p><b>This documentation is for version 5.5.3 (devel branch) of rsyslog.</b>
Visit the <i><a href="http://www.rsyslog.com/doc-status.html">rsyslog status page</a></i></b>
to obtain current version information and project status.
</p><p><b>If you like rsyslog, you might
@@ -71,6 +71,7 @@ syslog sender over NAT</a> (online only)</li>
<li><a href="debug.html">debug support in rsyslog</a></li>
<li>Developer Documentation
<ul>
+ <li><a href="build_from_repo.html">building rsyslog from the source repository</a></li>
<li><a href="dev_oplugins.html">writing rsyslog output plugins</a></li>
<li><a href="dev_queue.html">the rsyslog message queue object (developer's view)</a></li>
</ul></li>
diff --git a/doc/module_workflow.png b/doc/module_workflow.png
new file mode 100644
index 00000000..e1a72e96
--- /dev/null
+++ b/doc/module_workflow.png
Binary files differ
diff --git a/doc/rsconf1_escape8bitcharsonreceive.html b/doc/rsconf1_escape8bitcharsonreceive.html
new file mode 100644
index 00000000..408851c1
--- /dev/null
+++ b/doc/rsconf1_escape8bitcharsonreceive.html
@@ -0,0 +1,44 @@
+<html>
+<head>
+<title>rsyslog.conf file</title>
+</head>
+<body>
+<a href="rsyslog_conf_global.html">back</a>
+
+<h2>$Escape8BitCharactersOnReceive</h2>
+<p><b>Type:</b> global configuration directive</p>
+<p><b>Default:</b> off</p>
+<p><b>Available Since:</b> 5.5.2</p>
+<p><b>Description:</b></p>
+<p>This directive instructs rsyslogd to replace non US-ASCII characters (those that
+have the 8th bit set) during reception of the message.
+This may be useful for some systems.
+Please note that this escaping breaks Unicode and many other encodings. Most importantly,
+it can be assumed that Asian and European characters will be rendered hardly readable by
+this settings. However, it may still be useful when the logs themself are primarily
+in English and only occasionally contain local script.
+If this option is turned on, all control-characters are converted to a 3-digit octal number and be prefixed with the $ControlCharacterEscapePrefix character (being '#' by default).
+<p><b>Warning:</b></p>
+<ul>
+ <li>turning on this option most probably destroys non-western character sets
+ (like Japanese, Chinese and Korean) as well as European character sets.</li>
+ <li>turning on this option destroys digital signatures if such exists inside
+ the message</li>
+ <li>if turned on, the drop-cc, space-cc and escape-cc
+ <a href="property_replacer.html">property replacer</a> options do not work
+ as expected because control characters are already removed upon message
+ reception. If you intend to use these property replacer options, you must
+ turn off $Escape8BitCharactersOnReceive.</li>
+</ul>
+<p><b>Sample:</b></p>
+<p><code><b>$Escape8BitCharactersOnReceive on</b></code></p>
+
+<p>[<a href="rsyslog_conf.html">rsyslog.conf overview</a>] [<a href="manual.html">manual
+index</a>] [<a href="http://www.rsyslog.com/">rsyslog site</a>]</p>
+<p><font size="2">This documentation is part of the
+<a href="http://www.rsyslog.com/">rsyslog</a> project.<br>
+Copyright &copy; 2010 by <a href="http://www.gerhards.net/rainer">Rainer Gerhards</a> and
+<a href="http://www.adiscon.com/">Adiscon</a>. Released under the GNU GPL
+version 3 or higher.</font></p>
+</body>
+</html>
diff --git a/doc/rsyslog_conf_global.html b/doc/rsyslog_conf_global.html
index 7d223c1b..b71fc761 100644
--- a/doc/rsyslog_conf_global.html
+++ b/doc/rsyslog_conf_global.html
@@ -140,7 +140,9 @@ our paper on <a href="multi_ruleset.html">using multiple rule sets in rsyslog</a
<li><a href="rsconf1_dropmsgswithmaliciousdnsptrrecords.html">$DropMsgsWithMaliciousDnsPTRRecords</a></li>
<li><a href="rsconf1_droptrailinglfonreception.html">$DropTrailingLFOnReception</a></li>
<li><a href="rsconf1_dynafilecachesize.html">$DynaFileCacheSize</a></li>
+<li><a href="rsconf1_escape8bitcharsonreceive.html">$Escape8BitCharactersOnReceive</a></li>
<li><a href="rsconf1_escapecontrolcharactersonreceive.html">$EscapeControlCharactersOnReceive</a></li>
+<li><b>$EscapeControlCharactersOnReceive</b> [<b>on</b>|off] - escape USASCII HT character</li>
<li>$ErrorMessagesToStderr [<b>on</b>|off] - direct rsyslogd error message to stderr (in addition to other targets)</li>
<li><a href="rsconf1_failonchownfailure.html">$FailOnChownFailure</a></li>
<li><a href="rsconf1_filecreatemode.html">$FileCreateMode</a></li>
@@ -236,7 +238,7 @@ in that case by sending rsyslogd a HUP signal.
of the output file. The higher the number, the better the compression, but also the
more CPU is required for zipping.</li>
<li><b>$OMFileIOBufferSize</b> &lt;size_nbr&gt;, default 4k, size of the buffer used to writing output data. The larger the buffer, the potentially better performance is. The default of 4k is quite conservative, it is useful to go up to 64k, and 128K if you used gzip compression (then, even higher sizes may make sense)</li>
-<li><b>$OMFileFlushOnTXEnd</b> &lt;[on/<b>off</b>]&gt;, default ff. Omfile has the
+<li><b>$OMFileFlushOnTXEnd</b> &lt;[<b>on</b>/off]&gt;, default on. Omfile has the
capability to
write output using a buffered writer. Disk writes are only done when the buffer is
full. So if an error happens during that write, data is potentially lost. In cases where
@@ -244,7 +246,7 @@ this is unacceptable, set $OMFileFlushOnTXEnd to on. Then, data is written at th
of each transaction (for pre-v5 this means after <b>each</b> log message) and the usual
error recovery thus can handle write errors without data loss. Note that this option
severely reduces the effect of zip compression and should be switched to off
-for that use case. Note that the default -off- is primarily an aid to preserve
+for that use case. Note that the default -on- is primarily an aid to preserve
the traditional syslogd behaviour.</li>
<li><a href="rsconf1_omfileforcechown.html">$omfileForceChown</a> - force ownership change for all files</li>
<li><b>$RepeatedMsgContainsOriginalMsg</b> [on/<b>off</b>] - "last message repeated n times" messages, if generated,
@@ -276,6 +278,9 @@ system is stripped. If set to on, full names are always used.</li>
<li><a href="droppriv.html">$PrivDropToGroupID</a></li>
<li><a href="droppriv.html">$PrivDropToUser</a></li>
<li><a href="droppriv.html">$PrivDropToUserID</a></li>
+<li><b>$Sleep</b> &lt;seconds&gt; - puts the rsyslog main thread to sleep for the specified
+number of seconds immediately when the directive is encountered. You should have a
+good reason for using this directive!</li>
<li><a href="rsconf1_umask.html">$UMASK</a></li>
</ul>
<p><b>Where &lt;size_nbr&gt; is specified above,</b>
@@ -294,7 +299,7 @@ point of view, "1,,0.0.,.,0" also has the value 1000. </p>
[<a href="http://www.rsyslog.com/">rsyslog site</a>]</p>
<p><font size="2">This documentation is part of the
<a href="http://www.rsyslog.com/">rsyslog</a> project.<br>
-Copyright &copy; 2008, 2009 by <a href="http://www.gerhards.net/rainer">Rainer Gerhards</a> and
+Copyright &copy; 2008-2010 by <a href="http://www.gerhards.net/rainer">Rainer Gerhards</a> and
<a href="http://www.adiscon.com/">Adiscon</a>. Released under the GNU GPL
version 3 or higher.</font></p>
</body>
diff --git a/doc/rsyslog_conf_modules.html b/doc/rsyslog_conf_modules.html
index 4ce62b38..b721c935 100644
--- a/doc/rsyslog_conf_modules.html
+++ b/doc/rsyslog_conf_modules.html
@@ -19,8 +19,16 @@ modules solve your need, you may consider writing one or have one written
for you by
<a href="http://www.rsyslog.com/professional-services">Adiscon's professional services for rsyslog</a>
</b>(this often is a very cost-effective and efficient way of getting what you need).
+<p>There exist different classes of loadable modules:
+<ul>
+<li><a href="rsyslog_conf_modules.html#im">Input Modules</a>
+<li><a href="rsyslog_conf_modules.html#om">Output Modules</a>
+<li><a href="rsyslog_conf_modules.html#pm">Parser Modules</a>
+<li><a href="rsyslog_conf_modules.html#mm">Message Modification Modules</a>
+<li><a href="rsyslog_conf_modules.html#lm">Library Modules</a>
+</ul>
-<h2>Input Modules</h2>
+<a name"im"></a><h2>Input Modules</h2>
<p>Input modules are used to gather messages from various sources. They interface
to message generators.
<ul>
@@ -32,10 +40,11 @@ to message generators.
<li>immark - support for mark messages</li>
<li><a href="imklog.html">imklog</a> - kernel logging</li>
<li><a href="imuxsock.html">imuxsock</a> - unix sockets, including the system log socket</li>
+<li><a href="imsolaris.html">imsolaris</a> - input for the Sun Solaris system log source</li>
<li><a href="im3195.html">im3195</a> - accepts syslog messages via RFC 3195</li>
</ul>
-<h2>Output Modules</h2>
+<a name"om"></a><h2>Output Modules</h2>
<p>Output modules process messages. With them, message formats can be transformed
and messages be transmitted to various different targets.
<ul>
@@ -52,14 +61,54 @@ SQLLite, Ingres, Oracle, mSQL)</li>
<li><a href="ommail.html">ommail</a> -
permits rsyslog to alert folks by mail if something important happens</li>
<li><a href="omoracle.html">omoracle</a> - output module for Oracle (native OCI interface)</li>
+<li><a href="omudpspoof.html">omudpspoof</a> - output module sending UDP syslog messages with a spoofed address</li>
+</ul>
+
+<a name="pm"></a><h2>Parser Modules</h2>
+<p>Parser modules are used to parse message content, once the message has been
+received. They can be used to process custom message formats or invalidly formatted
+messages. For details, please see the <a href="messageparser.html">rsyslog
+message parser documentation</a>.
+<p>The current modules are currently provided as part of rsyslog:
+<ul>
+<li>pmrfc5424 - parses RFC5424-formatted messages (the new syslog standard)
+<li>pmrfc3164 - the traditional/legacy syslog parser
</ul>
-<h2>Library Modules</h2>
+<a name="mm"></a><h2>Message Modification Modules</h2>
+<p>Message modification modules are used to change the content of messages being processed.
+They can be implemented using either the output module or the parser module interface.
+From the rsyslog core's point of view, they actually are output or parser modules, it is their
+implementation that makes them special.
+<p>Currently, there do not exist any such modules, but could be written with
+the methods the engine provides. They could be used, for example, to:
+<ul>
+<li>anonymize message content
+<li>add dynamically computed content to message (fields)
+</ul>
+
+<a name="lm"></a><h2>Library Modules</h2>
<p>Library modules provide dynamically loadable functionality for parts of rsyslog,
most often for other loadable modules. They can not be user-configured and are loaded
automatically by some components. They are just mentioned so that error messages that
point to library moduls can be understood. No module list is provided.
+<h2>Where are the modules integrated into the Message Flow?</h2>
+<p>Depending on their module type, modules may access and/or modify messages at
+various stages during rsyslog's processing. Note that only the "core type" (e.g. input,
+output) but not any type derived from it (message modification module) specifies when
+a module is called.
+<p>The simplified workflow is as follows:
+<p align="center">
+<img src="module_workflow.png" alt"rsyslog: loadable modules and message flow">
+<p>As can be seen, messages are received by input modules, then passed to one or many
+parser modules, which generate the in-memory representation of the message and may
+also modify the message itself. The, the internal representation is passed to
+output modules, which may output a message and (with the interfaces newly introduced
+in v5) may also modify messageo object content.
+<p>Note that the actual flow is much more complex and depends a lot on queue and
+filter settings. This graphic above is a high-level message flow diagram.
+
<p>[<a href="manual.html">manual index</a>]
[<a href="rsyslog_conf.html">rsyslog.conf</a>]
[<a href="http://www.rsyslog.com/">rsyslog site</a>]</p>
diff --git a/doc/src/module_workflow.dia b/doc/src/module_workflow.dia
new file mode 100644
index 00000000..178571f4
--- /dev/null
+++ b/doc/src/module_workflow.dia
Binary files differ
diff --git a/doc/src/tls.dia b/doc/src/tls.dia
index 77e5d185..d7c9811d 100644
--- a/doc/src/tls.dia
+++ b/doc/src/tls.dia
Binary files differ
diff --git a/doc/status.html b/doc/status.html
index ff056489..6231593b 100644
--- a/doc/status.html
+++ b/doc/status.html
@@ -2,37 +2,30 @@
<html><head><title>rsyslog status page</title></head>
<body>
<h2>rsyslog status page</h2>
-<p>This page reflects the status as of 2009-11-05.</p>
+<p>This page reflects the status as of 2010-04-22.</p>
<h2>Current Releases</h2>
-<p><b>v5 development:</b> 5.3.4 [2009-11-04] -
-<a href="http://www.rsyslog.com/Article423.phtml">change log</a> -
-<a href="http://www.rsyslog.com/Downloads-req-viewdownloaddetails-lid-185.phtml">download</a>
+<p><b>development:</b> 5.5.3 [2010-04-08] -
+<a href="http://www.rsyslog.com/Article450.phtml">change log</a> -
+<a href="http://www.rsyslog.com/Downloads-req-viewdownloaddetails-lid-199.phtml">download</a>
<br>
-<!-- not at the moment!
-<b>v4 development:</b> 4.5.1 [2009-07-15] -
-<a href="http://www.rsyslog.com/Article388.phtml">change log</a> -
-<a href="http://www.rsyslog.com/Downloads-req-viewdownloaddetails-lid-167.phtml">download</a></p>
--->
+<b>v4 development:</b> 4.7.1 [2010-04-22] -
+<a href="http://www.rsyslog.com/Article455.phtml">change log</a> -
+<a href="http://www.rsyslog.com/Downloads-req-viewdownloaddetails-lid-201.phtml">download</a></p>
<!-- not at the moment!
-<br><b>v5-beta:</b> 5.1.6 [2009-10-15] -
-<a href="http://www.rsyslog.com/Article413.phtml">change log</a> -
-<a href="http://www.rsyslog.com/Downloads-req-viewdownloaddetails-lid-180.phtml">download</a>
+<p><b>beta:</b> 5.3.7 [2010-01-27] -
+<a href="http://www.rsyslog.com/Article437.phtml">change log</a> -
+<a href="http://www.rsyslog.com/Downloads-req-viewdownloaddetails-lid-192.phtml">download</a></p>
-->
-<br><b>v4-beta:</b> 4.5.6 [2009-11-05] -
-<a href="http://www.rsyslog.com/Article425.phtml">change log</a> -
-<a href="http://www.rsyslog.com/Downloads-req-viewdownloaddetails-lid-186.phtml">download</a></p>
-
-<p><b>v5 stable:</b> 5.2.0 [2009-11-02] (recommended to use
-<a href="http://www.rsyslog.com/Downloads-req-viewdownloaddetails-lid-183.phtml">5.3.3</a> instead) -
-<a href="http://www.rsyslog.com/Article421.phtml">change log</a> -
-<a href="http://www.rsyslog.com/Downloads-req-viewdownloaddetails-lid-184.phtml">download</a>
+<p><b>v5 stable:</b> 5.4.0 [2010-03-08] -
+<a href="http://www.rsyslog.com/Article447.phtml">change log</a> -
+<a href="http://www.rsyslog.com/Downloads-req-viewdownloaddetails-lid-197.phtml">download</a>
-<br><b>v4 stable:</b> 4.4.2 [2009-10-09] -
-<a href="http://www.rsyslog.com/Article409.phtml">change log</a> -
-<a href="http://www.rsyslog.com/Downloads-req-viewdownloaddetails-lid-179.phtml">download</a>
+<br><b>v4 stable:</b> 4.6.2 [2010-03-26] -
+<a href="http://www.rsyslog.com/Article449.phtml">change log</a> -
+<a href="http://www.rsyslog.com/Downloads-req-viewdownloaddetails-lid-198.phtml">download</a>
<br><b>v3 stable:</b> 3.22.1 [2009-07-02] -
<a href="http://www.rsyslog.com/Article381.phtml">change log</a> -
diff --git a/doc/troubleshoot.html b/doc/troubleshoot.html
index a8855fd4..16b2754b 100644
--- a/doc/troubleshoot.html
+++ b/doc/troubleshoot.html
@@ -102,13 +102,63 @@ comes without any guarantees, include no guarantee on confidentiality
[aka "we don't want to be sued for work were are not even paid for ;)].
<b>So if you submit debug logs, do so at your sole risk</b>. By submitting them, you accept
this policy.
+<p><b>Segmentation Faults</b>
+<p>Rsyslog has a very rapid development process, complex capabilities and now gradually gets
+more and more exposure. While we are happy about this, it also has some bad effects: some
+deployment scenarios have probably never been tested and it may be impossible to test
+them for the development team because of resources needed. So while we try to avoid this,
+you may see a serious problem during deployments in demanding, non-standard, environments
+(hopefully not with a stable version, but chances are good you'll run into troubles with
+the development versions).
+<p>Active support from the user base is very important to help us track down those things.
+Most often, serious problems are the result of some memory misadressing. During development,
+we routinely use valgrind, a very well and capable memory debugger. This helps us to create
+pretty clean code. But valgrind can not detect anything, most importantly not code pathes
+that are never executed. So of most use for us is information about aborts and abort locations.
+<p>Unforutnately, faults rooted in adressing errors typically show up only later, so the
+actual abort location is in an unrelated spot. To help track down the original spot,
+<a href="http://www.gnu.org/software/hello/manual/libc/Heap-Consistency-Checking.html">libc
+later than 5.4.23 offers support</a> for finding, and possible temporary relief from it,
+by means of the MALLOC_CHECK_ environment variable. Setting it to 2 is a useful troubleshooting
+aid for us. It will make the program abort as soon as the check routines detect anything
+suspicious (unfortunately, this may still not be the root cause, but hopefully closer to it).
+Setting it to 0 may even make some problems disappear (but it will NOT fix them!).
+With functionality comes cost, and so exporting MALLOC_CHECK_ without need comes at
+a performance penalty. However, we strongly recommend adding this instrumentation to your
+test environment should you see any serious problems. Chances are good it will help us
+interpret a dump better, and thus be able to quicker craft a fix.
+<p>In order to get useful information, we need some backtrace of the abort. First, you need
+to make sure that a core file is created. Under Fedora, for example, that means you need
+to have an "ulimit -c unlimited" in place.
+<p>Now let's assume you got a core file (e.g. in /core.1234). So what to do next? Sending a
+core file to us is most often pointless - we need to have the exact same system configuration in
+order to interpret it correctly. Obviously, chances are extremely slim for this to be. So we would
+appreciate if you could extract the most important information. This is done as follows:
+<ul>
+<li>$gdb /path/to/rsyslogd
+<li>$info thread
+<li>you'll see a number of threads (in the range 0 to n with n being the highest number). For
+ <b>each</b> of them, do the following (let's assume that i is the thread number):
+ <ul>
+ <li>$ thread i (e.g. thread 0, thread 1, ...)
+ <li>$bt
+ </ul>
+<li>then you can quit gdb with "$q"
+</ul>
+<p>Then please send all information that gdb spit out to the development team. It is best to first
+ask on the forum or mailing list on how to do that. The developers will keep in contact with you
+and, I fear, will probably ask for other things as well ;)
+<p>Note that we strive for highest reliability of the engine even in unusual deployment scenarios.
+Unfortunately, this is hard to achieve, especially with limited resources. So we are depending on
+cooperation from users. This is your chance to make a big contribution to the project without the
+need to program or do anything else except get a problem solved ;)
<p>[<a href="manual.html">manual index</a>]
[<a href="http://www.rsyslog.com/">rsyslog site</a>]</p>
<p><font size="2">This documentation is part of the
<a href="http://www.rsyslog.com/">rsyslog</a> project.<br>
-Copyright &copy; 2008 by <a href="http://www.gerhards.net/rainer">Rainer Gerhards</a> and
+Copyright &copy; 2008-2010 by <a href="http://www.gerhards.net/rainer">Rainer Gerhards</a> and
<a href="http://www.adiscon.com/">Adiscon</a>. Released under the GNU GPL
-version 2 or higher.</font></p>
+version 3 or higher.</font></p>
</body>
</html>
diff --git a/gss-misc.c b/gss-misc.c
index d67c344d..a5e161de 100644
--- a/gss-misc.c
+++ b/gss-misc.c
@@ -52,11 +52,14 @@
#include "errmsg.h"
#include "gss-misc.h"
#include "debug.h"
+#include "glbl.h"
+#include "unlimited_select.h"
MODULE_TYPE_LIB
/* static data */
DEFobjStaticHelpers
+DEFobjCurrIf(glbl)
DEFobjCurrIf(errmsg)
static void display_status_(char *m, OM_uint32 code, int type)
@@ -109,28 +112,38 @@ static int read_all(int fd, char *buf, unsigned int nbyte)
{
int ret;
char *ptr;
- fd_set rfds;
struct timeval tv;
+#ifdef USE_UNLIMITED_SELECT
+ fd_set *pRfds = malloc(glbl.GetFdSetSize());
+#else
+ fd_set rfds;
+ fd_set *pRfds = &rfds;
+#endif
for (ptr = buf; nbyte; ptr += ret, nbyte -= ret) {
- FD_ZERO(&rfds);
- FD_SET(fd, &rfds);
+ FD_ZERO(pRfds);
+ FD_SET(fd, pRfds);
tv.tv_sec = 1;
tv.tv_usec = 0;
- if ((ret = select(FD_SETSIZE, &rfds, NULL, NULL, &tv)) <= 0
- || !FD_ISSET(fd, &rfds))
+ if ((ret = select(FD_SETSIZE, pRfds, NULL, NULL, &tv)) <= 0
+ || !FD_ISSET(fd, pRfds)) {
+ freeFdSet(pRfds);
return ret;
+ }
ret = recv(fd, ptr, nbyte, 0);
if (ret < 0) {
if (errno == EINTR)
continue;
+ freeFdSet(pRfds);
return (ret);
} else if (ret == 0) {
+ freeFdSet(pRfds);
return (ptr - buf);
}
}
+ freeFdSet(pRfds);
return (ptr - buf);
}
@@ -265,6 +278,7 @@ BEGINObjClassExit(gssutil, OBJ_IS_LOADABLE_MODULE) /* CHANGE class also in END M
CODESTARTObjClassExit(gssutil)
/* release objects we no longer need */
objRelease(errmsg, CORE_COMPONENT);
+ objRelease(glbl, CORE_COMPONENT);
ENDObjClassExit(gssutil)
@@ -275,6 +289,7 @@ ENDObjClassExit(gssutil)
BEGINAbstractObjClassInit(gssutil, 1, OBJ_IS_LOADABLE_MODULE) /* class, version - CHANGE class also in END MACRO! */
/* request objects we use */
CHKiRet(objUse(errmsg, CORE_COMPONENT));
+ CHKiRet(objUse(glbl, CORE_COMPONENT));
ENDObjClassInit(gssutil)
diff --git a/plugins/imdiag/imdiag.c b/plugins/imdiag/imdiag.c
index 2f7e5fee..81b357ef 100644
--- a/plugins/imdiag/imdiag.c
+++ b/plugins/imdiag/imdiag.c
@@ -270,6 +270,11 @@ waitMainQEmpty(tcps_sess_t *pSess)
dbgprintf("imdiag sleeping, wait mainq drain, curr size %d\n", iMsgQueueSize);
srSleep(0,2); /* wait a little bit */
CHKiRet(diagGetMainMsgQSize(&iMsgQueueSize));
+ if(iMsgQueueSize == 0) {
+ /* verify that queue is still empty (else it could just be a race!) */
+ srSleep(1,5); /* wait a little bit */
+ CHKiRet(diagGetMainMsgQSize(&iMsgQueueSize));
+ }
}
CHKiRet(sendResponse(pSess, "mainqueue empty\n"));
diff --git a/plugins/imgssapi/imgssapi.c b/plugins/imgssapi/imgssapi.c
index 1d4e3b4f..dd3d67e3 100644
--- a/plugins/imgssapi/imgssapi.c
+++ b/plugins/imgssapi/imgssapi.c
@@ -58,6 +58,7 @@
#include "netstrm.h"
#include "glbl.h"
#include "debug.h"
+#include "unlimited_select.h"
MODULE_TYPE_INPUT
@@ -178,10 +179,10 @@ isPermittedHost(struct sockaddr *addr, char *fromHostFQDN, void *pUsrSrv, void*p
pGSess = (gss_sess_t*) pUsrSess;
if((pGSrv->allowedMethods & ALLOWEDMETHOD_TCP) &&
- net.isAllowedSender((uchar*)"TCP", addr, (char*)fromHostFQDN))
+ net.isAllowedSender2((uchar*)"TCP", addr, (char*)fromHostFQDN, 1))
allowedMethods |= ALLOWEDMETHOD_TCP;
if((pGSrv->allowedMethods & ALLOWEDMETHOD_GSS) &&
- net.isAllowedSender((uchar*)"GSS", addr, (char*)fromHostFQDN))
+ net.isAllowedSender2((uchar*)"GSS", addr, (char*)fromHostFQDN, 1))
allowedMethods |= ALLOWEDMETHOD_GSS;
if(allowedMethods && pGSess != NULL)
pGSess->allowedMethods = allowedMethods;
@@ -417,15 +418,20 @@ OnSessAcceptGSS(tcpsrv_t *pThis, tcps_sess_t *pSess)
CHKiRet(netstrm.GetSock(pSess->pStrm, &fdSess)); // TODO: method access!
if (allowedMethods & ALLOWEDMETHOD_TCP) {
int len;
- fd_set fds;
struct timeval tv;
+#ifdef USE_UNLIMITED_SELECT
+ fd_set *pFds = malloc(glbl.GetFdSetSize());
+#else
+ fd_set fds;
+ fd_set *pFds = &fds;
+#endif
do {
- FD_ZERO(&fds);
- FD_SET(fdSess, &fds);
+ FD_ZERO(pFds);
+ FD_SET(fdSess, pFds);
tv.tv_sec = 1;
tv.tv_usec = 0;
- ret = select(fdSess + 1, &fds, NULL, NULL, &tv);
+ ret = select(fdSess + 1, pFds, NULL, NULL, &tv);
} while (ret < 0 && errno == EINTR);
if (ret < 0) {
errmsg.LogError(0, RS_RET_ERR, "TCP session %p will be closed, error ignored\n", pSess);
@@ -478,6 +484,8 @@ OnSessAcceptGSS(tcpsrv_t *pThis, tcps_sess_t *pSess)
pGSess->allowedMethods = ALLOWEDMETHOD_TCP;
ABORT_FINALIZE(RS_RET_OK); // TODO: define good error codes
}
+
+ freeFdSet(pFds);
}
context = &pGSess->gss_context;
diff --git a/plugins/imklog/solaris.c b/plugins/imklog/solaris.c
new file mode 100644
index 00000000..8a6d5af1
--- /dev/null
+++ b/plugins/imklog/solaris.c
@@ -0,0 +1,184 @@
+/* klog driver for solaris
+ *
+ * This contains OS-specific functionality to read the
+ * kernel log. For a general overview, see head comment in
+ * imklog.c.
+ *
+ * This file relies on Sun code in solaris_cddl.c. We have split
+ * it from Sun's code to keep the copyright issue as simple as possible.
+ *
+ * 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.
+ *
+ * If that may be required, an exception is granted to permit linking
+ * this code to the code in solaris_cddl.c that is under the cddl license.
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/socket.h>
+
+
+
+#include "rsyslog.h"
+#include "imklog.h"
+#include "srUtils.h"
+#include "unicode-helper.h"
+#include "solaris_cddl.h"
+
+/* globals */
+static int fklog; // TODO: remove
+#ifndef _PATH_KLOG
+# define _PATH_KLOG "/dev/log"
+#endif
+
+
+static uchar *GetPath(void)
+{
+ return pszPath ? pszPath : UCHAR_CONSTANT(_PATH_KLOG);
+}
+
+/* open the kernel log - will be called inside the willRun() imklog
+ * entry point. -- rgerhards, 2008-04-09
+ */
+rsRetVal
+klogWillRun(void)
+{
+ DEFiRet;
+
+ fklog = sun_openklog((char*) GetPath(), O_RDONLY);
+ if (fklog < 0) {
+ char errStr[1024];
+ int err = errno;
+ rs_strerror_r(err, errStr, sizeof(errStr));
+ DBGPRINTF("error %s opening log socket: %s\n",
+ errStr, GetPath());
+ iRet = RS_RET_ERR; // TODO: better error code
+ }
+
+ RETiRet;
+}
+
+
+#if 0
+/* Read /dev/klog while data are available, split into lines.
+ * Contrary to standard BSD syslogd, we do a blocking read. We can
+ * afford this as imklog is running on its own threads. So if we have
+ * a single file, it really doesn't matter if we wait inside a 1-file
+ * select or the read() directly.
+ */
+static void
+readklog(void)
+{
+ char *p, *q;
+ int len, i;
+ int iMaxLine;
+ uchar bufRcv[4096+1];
+ uchar *pRcv = NULL; /* receive buffer */
+
+ iMaxLine = klog_getMaxLine();
+
+ /* we optimize performance: if iMaxLine is below 4K (which it is in almost all
+ * cases, we use a fixed buffer on the stack. Only if it is higher, heap memory
+ * is used. We could use alloca() to achive a similar aspect, but there are so
+ * many issues with alloca() that I do not want to take that route.
+ * rgerhards, 2008-09-02
+ */
+ if((size_t) iMaxLine < sizeof(bufRcv) - 1) {
+ pRcv = bufRcv;
+ } else {
+ if((pRcv = (uchar*) malloc(sizeof(uchar) * (iMaxLine + 1))) == NULL)
+ iMaxLine = sizeof(bufRcv) - 1; /* better this than noting */
+ }
+
+ len = 0;
+ for (;;) {
+ dbgprintf("----------imklog(BSD) waiting for kernel log line\n");
+ i = read(fklog, pRcv + len, iMaxLine - len);
+ if (i > 0) {
+ pRcv[i + len] = '\0';
+ } else {
+ if (i < 0 && errno != EINTR && errno != EAGAIN) {
+ imklogLogIntMsg(LOG_ERR,
+ "imklog error %d reading kernel log - shutting down imklog",
+ errno);
+ fklog = -1;
+ }
+ break;
+ }
+
+ for(p = pRcv; (q = strchr(p, '\n')) != NULL; p = q + 1) {
+ *q = '\0';
+ Syslog(LOG_INFO, (uchar*) p);
+ }
+ len = strlen(p);
+ if (len >= iMaxLine - 1) {
+ Syslog(LOG_INFO, (uchar*)p);
+ len = 0;
+ }
+ if (len > 0)
+ memmove(pRcv, p, len + 1);
+ }
+ if (len > 0)
+ Syslog(LOG_INFO, pRcv);
+
+ if(pRcv != NULL && (size_t) iMaxLine >= sizeof(bufRcv) - 1)
+ free(pRcv);
+}
+#endif
+
+
+/* to be called in the module's AfterRun entry point
+ * rgerhards, 2008-04-09
+ */
+rsRetVal klogAfterRun(void)
+{
+ DEFiRet;
+ if(fklog != -1)
+ close(fklog);
+ RETiRet;
+}
+
+
+
+/* to be called in the module's WillRun entry point, this is the main
+ * "message pull" mechanism.
+ * rgerhards, 2008-04-09
+ */
+rsRetVal klogLogKMsg(void)
+{
+ DEFiRet;
+ sun_sys_poll();
+ RETiRet;
+}
+
+
+/* provide the (system-specific) default facility for internal messages
+ * rgerhards, 2008-04-14
+ */
+int
+klogFacilIntMsg(void)
+{
+ return LOG_SYSLOG;
+}
+
diff --git a/plugins/imklog/solaris_cddl.c b/plugins/imklog/solaris_cddl.c
new file mode 100644
index 00000000..7e86c68c
--- /dev/null
+++ b/plugins/imklog/solaris_cddl.c
@@ -0,0 +1,293 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Portions Copyright 2010 by Rainer Gerhards and Adiscon
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
+ * All Rights Reserved
+ */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+#include "config.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <pthread.h>
+#include <sys/poll.h>
+#include <pthread.h>
+#include <fcntl.h>
+#include <stropts.h>
+#include <assert.h>
+#include <sys/strlog.h>
+
+#include "rsyslog.h"
+#include "imklog.h"
+
+/* TODO: this define should be changed over time to the more generic
+ * system-provided (configurable) upper limit. However, it is quite
+ * unexpected that Solaris-emitted messages are so long, so it seems
+ * acceptable to set a fixed (relatively high) limit for the time
+ * being -- and gain some experience with it. -- rgerhars, 2010-04-12
+ */
+#define MAXLINE 4096
+
+static struct pollfd Pfd; /* Pollfd for local the log device */
+
+
+/* findnl_bkwd:
+ * Scans each character in buf until it finds the last newline in buf,
+ * or the scanned character becomes the last COMPLETE character in buf.
+ * Returns the number of scanned bytes.
+ *
+ * buf - pointer to a buffer containing the message string
+ * len - the length of the buffer
+ */
+size_t
+findnl_bkwd(const char *buf, const size_t len)
+{
+ const char *p;
+ size_t mb_cur_max;
+
+ if (len == 0) {
+ return (0);
+ }
+
+ mb_cur_max = MB_CUR_MAX;
+
+ if (mb_cur_max == 1) {
+ /* single-byte locale */
+ for (p = buf + len - 1; p != buf; p--) {
+ if (*p == '\n') {
+ return ((size_t)(p - buf));
+ }
+ }
+ return ((size_t)len);
+ } else {
+ /* multi-byte locale */
+ int mlen;
+ const char *nl;
+ size_t rem;
+
+ p = buf;
+ nl = NULL;
+ for (rem = len; rem >= mb_cur_max; ) {
+ mlen = mblen(p, mb_cur_max);
+ if (mlen == -1) {
+ /*
+ * Invalid character found.
+ */
+ dbgprintf("klog:findnl_bkwd: Invalid MB sequence\n");
+ /*
+ * handle as a single byte character.
+ */
+ p++;
+ rem--;
+ } else {
+ /*
+ * It's guaranteed that *p points to
+ * the 1st byte of a multibyte character.
+ */
+ if (*p == '\n') {
+ nl = p;
+ }
+ p += mlen;
+ rem -= mlen;
+ }
+ }
+ if (nl) {
+ return ((size_t)(nl - buf));
+ }
+ /*
+ * no newline nor null byte found.
+ * Also it's guaranteed that *p points to
+ * the 1st byte of a (multibyte) character
+ * at this point.
+ */
+ return (len - rem);
+ }
+}
+//___ end
+
+
+/* Attempts to open the local log device
+ * and return a file descriptor.
+ */
+int
+sun_openklog(char *name, int mode)
+{
+ int fd;
+ struct strioctl str;
+
+ if ((fd = open(name, mode)) < 0) {
+ dbgprintf("klog:openklog: cannot open %s (%d)\n",
+ name, errno);
+ return (-1);
+ }
+ str.ic_cmd = I_CONSLOG;
+ str.ic_timout = 0;
+ str.ic_len = 0;
+ str.ic_dp = NULL;
+ if (ioctl(fd, I_STR, &str) < 0) {
+ dbgprintf("klog:openklog: cannot register to log "
+ "console messages (%d)\n", errno);
+ return (-1);
+ }
+ Pfd.fd = fd;
+ Pfd.events = POLLIN;
+ return (fd);
+}
+
+
+/*
+ * Pull up one message from log driver.
+ */
+void
+sun_getkmsg()
+{
+ int flags = 0, i;
+ char *lastline;
+ struct strbuf ctl, dat;
+ struct log_ctl hdr;
+ char buf[MAXLINE+1];
+ size_t buflen;
+ size_t len;
+ char tmpbuf[MAXLINE+1];
+
+ dat.maxlen = MAXLINE;
+ dat.buf = buf;
+ ctl.maxlen = sizeof (struct log_ctl);
+ ctl.buf = (caddr_t)&hdr;
+
+ while ((i = getmsg(Pfd.fd, &ctl, &dat, &flags)) == MOREDATA) {
+ lastline = &dat.buf[dat.len];
+ *lastline = '\0';
+
+ dbgprintf("klog:sys_poll: getmsg: dat.len = %d\n", dat.len);
+ buflen = strlen(buf);
+ len = findnl_bkwd(buf, buflen);
+
+ (void) memcpy(tmpbuf, buf, len);
+ tmpbuf[len] = '\0';
+
+ Syslog(LOG_INFO, (uchar*) buf);
+
+ if (len != buflen) {
+ /* If anything remains in buf */
+ size_t remlen;
+
+ if (buf[len] == '\n') {
+ /* skip newline */
+ len++;
+ }
+
+ /* Move the remaining bytes to
+ * the beginnning of buf.
+ */
+
+ remlen = buflen - len;
+ (void) memcpy(buf, &buf[len], remlen);
+ dat.maxlen = MAXLINE - remlen;
+ dat.buf = &buf[remlen];
+ } else {
+ dat.maxlen = MAXLINE;
+ dat.buf = buf;
+ }
+ }
+
+ if (i == 0 && dat.len > 0) {
+ dat.buf[dat.len] = '\0';
+ /* Format sys will enqueue the log message.
+ * Set the sync flag if timeout != 0, which
+ * means that we're done handling all the
+ * initial messages ready during startup.
+ */
+ dbgprintf("klog:getkmsg: getmsg: dat.maxlen = %d\n", dat.maxlen);
+ dbgprintf("klog:getkmsg: getmsg: dat.len = %d\n", dat.len);
+ dbgprintf("klog:getkmsg: getmsg: strlen(dat.buf) = %d\n", strlen(dat.buf));
+ dbgprintf("klog:getkmsg: getmsg: dat.buf = \"%s\"\n", dat.buf);
+ dbgprintf("klog:getkmsg: buf len = %d\n", strlen(buf));
+ Syslog(LOG_INFO, (uchar*) buf);
+ } else if (i < 0 && errno != EINTR) {
+ if(1){ /* V5-TODO: rsyslog-like termination! (!shutting_down) { */
+ dbgprintf("klog:kernel log driver read error");
+ }
+ // TODO trigger retry logic
+ //(void) close(Pfd.fd);
+ //Pfd.fd = -1;
+ }
+}
+
+
+/* this thread listens to the local stream log driver for log messages
+ * generated by this host, formats them, and queues them to the logger
+ * thread.
+ */
+/*ARGSUSED*/
+void *
+sun_sys_poll()
+{
+ int nfds;
+
+ dbgprintf("klog:sys_poll: sys_thread started\n");
+
+ for (;;) {
+ errno = 0;
+
+ nfds = poll(&Pfd, 1, INFTIM);
+
+ if (nfds == 0)
+ continue;
+
+ if (nfds < 0) {
+ if (errno != EINTR)
+ dbgprintf("klog:poll error");
+ continue;
+ }
+ if (Pfd.revents & POLLIN) {
+ sun_getkmsg();
+ } else {
+ /* TODO: shutdown, the rsyslog way (in v5!) -- check shutdown flag */
+ if (Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) {
+ // TODO: trigger retry logic
+/* logerror("kernel log driver poll error");
+ (void) close(Pfd.fd);
+ Pfd.fd = -1;
+ */
+ }
+ }
+
+ }
+ /*NOTREACHED*/
+ return (NULL);
+}
diff --git a/plugins/imklog/solaris_cddl.h b/plugins/imklog/solaris_cddl.h
new file mode 100644
index 00000000..d48ef628
--- /dev/null
+++ b/plugins/imklog/solaris_cddl.h
@@ -0,0 +1,2 @@
+void *sun_sys_poll();
+int sun_openklog(char *name, int mode);
diff --git a/plugins/imsolaris/Makefile.am b/plugins/imsolaris/Makefile.am
new file mode 100644
index 00000000..b4ee1c29
--- /dev/null
+++ b/plugins/imsolaris/Makefile.am
@@ -0,0 +1,6 @@
+pkglib_LTLIBRARIES = imsolaris.la
+
+imsolaris_la_SOURCES = imsolaris.c sun_cddl.c sun_cddl.h imsolaris.h
+imsolaris_la_CPPFLAGS = -I$(top_srcdir) $(PTHREADS_CFLAGS) $(RSRT_CFLAGS)
+imsolaris_la_LDFLAGS = -module -avoid-version
+imsolaris_la_LIBADD = -ldoor -lpthread
diff --git a/plugins/imsolaris/imsolaris.c b/plugins/imsolaris/imsolaris.c
new file mode 100644
index 00000000..f801833b
--- /dev/null
+++ b/plugins/imsolaris/imsolaris.c
@@ -0,0 +1,399 @@
+/* imsolaris.c
+ * This input module is used to gather local log data under Solaris. This
+ * includes messages from local applications AS WELL AS the kernel log.
+ * I first considered to make all of this available via imklog, but that
+ * did not lock appropriately on second thought. So I created this module
+ * that does anything for local message recption.
+ *
+ * This module is not meant to be used on plaforms other than Solaris. As
+ * such, trying to compile it elswhere will probably fail with all sorts
+ * of errors.
+ *
+ * Some notes on the Solaris syslog mechanism:
+ * Both system (kernel) and application log messages are provided via
+ * a single message stream.
+ *
+ * Solaris checks if the syslogd is running. If so, syslog() emits messages
+ * to the log socket, only. Otherwise, it emits messages to the console.
+ * It is possible to gather these console messages as well. However, then
+ * we clutter the console.
+ * Solaris does this "syslogd alive check" in a somewhat unexpected way
+ * (at least unexpected for me): it uses the so-called "door" mechanism, a
+ * fast RPC facility. I first thought that the door API was used to submit
+ * the actual syslog messages. But this is not the case. Instead, a door
+ * call is done, and the server process inside rsyslog simply does NOTHING
+ * but return. All that Solaris sylsogd() is interested in is if the door
+ * server (we) responds and thus can be considered alive. The actual message
+ * is then submitted via the usual stream. I have to admit I do not
+ * understand why the message itself is not passed via this high-performance
+ * API. But anyhow, that's nothing I can change, so the most important thing
+ * is to note how Solaris does this thing ;)
+ * The syslog() library call checks syslogd state for *each* call (what a
+ * waste of time...) and decides each time if the message should go to the
+ * console or not. According to OpenSolaris sources, it looks like there is
+ * message loss potential when the door file is created before all data has
+ * been pulled from the stream. While I have to admit that I do not fully
+ * understand that problem, I will follow the original code advise and do
+ * one complete pull cycle on the log socket (until it has no further data
+ * available) and only thereafter create the door file and start the "regular"
+ * pull cycle. As of my understanding, there is a minimal race between the
+ * point where the intial pull cycle has ended and the door file is created,
+ * but that race is also present in OpenSolaris syslogd code, so it should
+ * not matter that much (plus, I do not know how to avoid it...)
+ *
+ * File begun on 2010-04-15 by RGerhards
+ *
+ * Copyright 2010 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 "rsyslog.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <assert.h>
+#include <string.h>
+#include <stropts.h>
+#include <sys/strlog.h>
+#include <errno.h>
+#include "dirty.h"
+#include "cfsysline.h"
+#include "unicode-helper.h"
+#include "module-template.h"
+#include "srUtils.h"
+#include "errmsg.h"
+#include "net.h"
+#include "glbl.h"
+#include "msg.h"
+#include "prop.h"
+#include "sun_cddl.h"
+
+MODULE_TYPE_INPUT
+
+/* defines */
+#define PATH_LOG "/dev/log"
+
+
+/* Module static data */
+DEF_IMOD_STATIC_DATA
+DEFobjCurrIf(errmsg)
+DEFobjCurrIf(glbl)
+DEFobjCurrIf(prop)
+
+
+/* config settings */
+static prop_t *pInputName = NULL; /* our inputName currently is always "imuxsock", and this will hold it */
+static char *LogName = NULL; /* the log socket name TODO: make configurable! */
+
+
+/* a function to replace the sun logerror() function.
+ * It generates an error message from the supplied string. The main
+ * reason for not calling logError directly is that sun_cddl.c does not
+ * know or has acces to rsyslog objects (namely errmsg) -- and we do not
+ * want to do this effort. -- rgerhards, 2010-04-19
+ */
+void
+imsolaris_logerror(int err, char *errStr)
+{
+ errmsg.LogError(err, RS_RET_ERR_DOOR, "%s", errStr);
+}
+
+
+/* we try to recover a failed file by closing and re-opening
+ * it. We loop until the re-open works, but wait between each
+ * failure. If the open succeeds, we assume all is well. If it is
+ * not, we will run into the retry process with the next
+ * iteration.
+ * rgerhards, 2010-04-19
+ */
+static void
+tryRecover(void)
+{
+ int tryNum = 1;
+ int waitsecs;
+ int waitusecs;
+ rsRetVal iRet;
+
+ close(sun_Pfd.fd);
+ sun_Pfd.fd = -1;
+
+ while(1) { /* loop broken inside */
+ iRet = sun_openklog((LogName == NULL) ? PATH_LOG : LogName);
+ if(iRet == RS_RET_OK) {
+ if(tryNum > 1) {
+ errmsg.LogError(0, iRet, "failure on system log socket recovered.");
+ }
+ break;
+ }
+ /* failure, so sleep a bit. We wait try*10 ms, with a max of 15 seconds */
+ if(tryNum == 1) {
+ errmsg.LogError(0, iRet, "failure on system log socket, trying to recover...");
+ }
+ waitusecs = tryNum * 10000;
+ waitsecs = waitusecs / 1000000;
+ DBGPRINTF("imsolaris: try %d to recover system log socket in %d.%d seconds\n",
+ tryNum, waitsecs, waitusecs);
+ if(waitsecs > 15) {
+ waitsecs = 15;
+ waitusecs = 0;
+ } else {
+ waitusecs = waitusecs % 1000000;
+ }
+ srSleep(waitsecs, waitusecs);
+ ++tryNum;
+ }
+}
+
+
+/* This function receives data from a socket indicated to be ready
+ * to receive and submits the message received for processing.
+ * rgerhards, 2007-12-20
+ * Interface changed so that this function is passed the array index
+ * of the socket which is to be processed. This eases access to the
+ * growing number of properties. -- rgerhards, 2008-08-01
+ */
+static rsRetVal
+readLog(int fd, uchar *pRcv, int iMaxLine)
+{
+ DEFiRet;
+ struct strbuf data;
+ struct strbuf ctl;
+ struct log_ctl hdr;
+ int flags;
+ msg_t *pMsg;
+ int ret;
+ char errStr[1024];
+
+ data.buf = (char*)pRcv;
+ data.maxlen = iMaxLine;
+ ctl.maxlen = sizeof (struct log_ctl);
+ ctl.buf = (caddr_t)&hdr;
+ flags = 0;
+ ret = getmsg(fd, &ctl, &data, &flags);
+ if(ret < 0) {
+ if(errno == EINTR) {
+ FINALIZE;
+ } else {
+ int en = errno;
+ rs_strerror_r(errno, errStr, sizeof(errStr));
+ DBGPRINTF("imsolaris: stream input error on fd %d: %s.\n", fd, errStr);
+ errmsg.LogError(en, NO_ERRCODE, "imsolaris: stream input error: %s", errStr);
+ tryRecover();
+ }
+ } else {
+ DBGPRINTF("imsolaris: message from log stream %d: %s\n", fd, pRcv);
+ pRcv[data.len] = '\0'; /* make sure it is a valid C-String */
+ CHKiRet(msgConstruct(&pMsg));
+ MsgSetInputName(pMsg, pInputName);
+ MsgSetRawMsg(pMsg, (char*)pRcv, strlen((char*)pRcv));
+ MsgSetHOSTNAME(pMsg, glbl.GetLocalHostName(), ustrlen(glbl.GetLocalHostName()));
+ pMsg->iFacility = LOG_FAC(hdr.pri);
+ pMsg->iSeverity = LOG_PRI(hdr.pri);
+ pMsg->msgFlags = NEEDS_PARSING | NO_PRI_IN_RAW;
+ CHKiRet(submitMsg(pMsg));
+ }
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* once the system is fully initialized, we wait for new messages.
+ * We may think about replacing this with a read-loop, thus saving
+ * us the overhead of the poll.
+ * The timeout variable is the timeout to use for poll. During startup,
+ * it should be set to 0 (non-blocking) and later to -1 (infinit, blocking).
+ * This mimics the (strange) behaviour of the original syslogd.
+ * rgerhards, 2010-04-19
+ */
+static inline rsRetVal
+getMsgs(thrdInfo_t *pThrd, int timeout)
+{
+ DEFiRet;
+ int nfds;
+ int iMaxLine;
+ uchar *pRcv = NULL; /* receive buffer */
+ uchar bufRcv[4096+1];
+ char errStr[1024];
+
+ iMaxLine = glbl.GetMaxLine();
+
+ /* we optimize performance: if iMaxLine is below 4K (which it is in almost all
+ * cases, we use a fixed buffer on the stack. Only if it is higher, heap memory
+ * is used. We could use alloca() to achive a similar aspect, but there are so
+ * many issues with alloca() that I do not want to take that route.
+ * rgerhards, 2008-09-02
+ */
+ if((size_t) iMaxLine < sizeof(bufRcv) - 1) {
+ pRcv = bufRcv;
+ } else {
+ CHKmalloc(pRcv = (uchar*) malloc(sizeof(uchar) * (iMaxLine + 1)));
+ }
+
+ while(pThrd->bShallStop != TRUE) {
+ DBGPRINTF("imsolaris: waiting for next message (timeout %d)...\n", timeout);
+ if(timeout == 0) {
+ nfds = poll(&sun_Pfd, 1, timeout); /* wait without timeout */
+
+ if(pThrd->bShallStop == TRUE) {
+ break;
+ }
+
+ if(nfds == 0) {
+ if(timeout == 0) {
+ DBGPRINTF("imsolaris: no more messages, getMsgs() terminates\n");
+ FINALIZE;
+ } else {
+ continue;
+ }
+ }
+
+ if(nfds < 0) {
+ if(errno != EINTR) {
+ int en = errno;
+ rs_strerror_r(en, errStr, sizeof(errStr));
+ DBGPRINTF("imsolaris: poll error: %d = %s.\n", errno, errStr);
+ errmsg.LogError(en, NO_ERRCODE, "imsolaris: poll error: %s",
+ errStr);
+ }
+ continue;
+ }
+ if(sun_Pfd.revents & POLLIN) {
+ readLog(sun_Pfd.fd, pRcv, iMaxLine);
+ } else if(sun_Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) {
+ tryRecover();
+ }
+ } else {
+ /* if we have an infinite wait, we do not use poll at all
+ * I'd consider this a waste of time. However, I do not totally
+ * remove the code, as it may be useful if we decide at some
+ * point to provide a capability to support multiple input streams
+ * at once (this may be useful for a jail). In that case, the poll()
+ * loop would be needed, and so it doesn't make much sense to change
+ * the code to not support it. -- rgerhards, 2010-04-20
+ */
+ readLog(sun_Pfd.fd, pRcv, iMaxLine);
+ }
+
+ }
+
+finalize_it:
+ if(pRcv != NULL && (size_t) iMaxLine >= sizeof(bufRcv) - 1)
+ free(pRcv);
+
+ RETiRet;
+}
+
+
+/* This function is called to gather input. */
+BEGINrunInput
+CODESTARTrunInput
+ /* this is an endless loop - it is terminated when the thread is
+ * signalled to do so. This, however, is handled by the framework,
+ * right into the sleep below.
+ */
+
+ DBGPRINTF("imsolaris: doing startup poll before openeing door()\n");
+ CHKiRet(getMsgs(pThrd, 0));
+
+ /* note: sun's syslogd code claims that the door should only
+ * be opened when the log stream has been polled. So file header
+ * comment of this file for more details.
+ */
+ sun_open_door();
+ DBGPRINTF("imsolaris: starting regular poll loop\n");
+ iRet = getMsgs(pThrd, -1); /* this is the primary poll loop, infinite timeout */
+
+ DBGPRINTF("imsolaris: terminating (bShallStop=%d)\n", pThrd->bShallStop);
+finalize_it:
+ RETiRet;
+ENDrunInput
+
+
+BEGINwillRun
+CODESTARTwillRun
+ /* we need to create the inputName property (only once during our lifetime) */
+ CHKiRet(prop.Construct(&pInputName));
+ CHKiRet(prop.SetString(pInputName, UCHAR_CONSTANT("imsolaris"), sizeof("imsolaris") - 1));
+ CHKiRet(prop.ConstructFinalize(pInputName));
+
+ iRet = sun_openklog((LogName == NULL) ? PATH_LOG : LogName);
+ if(iRet != RS_RET_OK) {
+ errmsg.LogError(0, iRet, "error opening system log socket");
+ }
+finalize_it:
+ENDwillRun
+
+
+BEGINafterRun
+CODESTARTafterRun
+ /* do cleanup here */
+ if(pInputName != NULL)
+ prop.Destruct(&pInputName);
+ free(LogName);
+ENDafterRun
+
+
+BEGINmodExit
+CODESTARTmodExit
+ sun_delete_doorfiles();
+ objRelease(glbl, CORE_COMPONENT);
+ objRelease(errmsg, CORE_COMPONENT);
+ objRelease(prop, CORE_COMPONENT);
+ENDmodExit
+
+
+BEGINisCompatibleWithFeature
+CODESTARTisCompatibleWithFeature
+ if(eFeat == sFEATURENonCancelInputTermination)
+ iRet = RS_RET_OK;
+ENDisCompatibleWithFeature
+
+
+BEGINqueryEtryPt
+CODESTARTqueryEtryPt
+CODEqueryEtryPt_STD_IMOD_QUERIES
+CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES
+ENDqueryEtryPt
+
+static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp,
+ void __attribute__((unused)) *pVal)
+{
+ return RS_RET_OK;
+}
+
+
+BEGINmodInit()
+CODESTARTmodInit
+ *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
+CODEmodInit_QueryRegCFSLineHdlr
+ CHKiRet(objUse(errmsg, CORE_COMPONENT));
+ CHKiRet(objUse(glbl, CORE_COMPONENT));
+ CHKiRet(objUse(prop, CORE_COMPONENT));
+
+ DBGPRINTF("imsolaris version %s initializing\n", PACKAGE_VERSION);
+
+ /* register config file handlers */
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler,
+ resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"imsolarislogsocketname", 0, eCmdHdlrGetWord,
+ NULL, &LogName, STD_LOADABLE_MODULE_ID));
+ENDmodInit
+/* vim:set ai:
+ */
diff --git a/plugins/imsolaris/imsolaris.h b/plugins/imsolaris/imsolaris.h
new file mode 100644
index 00000000..e73380fa
--- /dev/null
+++ b/plugins/imsolaris/imsolaris.h
@@ -0,0 +1,2 @@
+rsRetVal solaris_readLog(int fd);
+void imsolaris_logerror(int err, char *errStr);
diff --git a/plugins/imsolaris/sun_cddl.c b/plugins/imsolaris/sun_cddl.c
new file mode 100644
index 00000000..6d49c8bc
--- /dev/null
+++ b/plugins/imsolaris/sun_cddl.c
@@ -0,0 +1,419 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Portions Copyright 2010 by Rainer Gerhards and Adiscon
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
+ * All Rights Reserved
+ */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <pthread.h>
+#include <fcntl.h>
+#include <stropts.h>
+#include <assert.h>
+
+#include <sys/param.h>
+#include <sys/strlog.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/poll.h>
+#include <door.h>
+#include <sys/door.h>
+
+#include "rsyslog.h"
+#include "srUtils.h"
+#include "debug.h"
+#include "imsolaris.h"
+
+#define DOORFILE "/var/run/syslog_door"
+#define RELATIVE_DOORFILE "../var/run/syslog_door"
+#define OLD_DOORFILE "/etc/.syslog_door"
+
+/* Buffer to allocate for error messages: */
+#define ERRMSG_LEN 1024
+
+/* Max number of door server threads for syslogd. Since door is used
+ * to check the health of syslogd, we don't need large number of
+ * server threads.
+ */
+#define MAX_DOOR_SERVER_THR 3
+
+
+struct pollfd sun_Pfd; /* Pollfd for local log device */
+
+static int DoorFd = -1;
+static int DoorCreated = 0;
+static char *DoorFileName = DOORFILE;
+
+/* for managing door server threads */
+static pthread_mutex_t door_server_cnt_lock = PTHREAD_MUTEX_INITIALIZER;
+static uint_t door_server_cnt = 0;
+static pthread_attr_t door_thr_attr;
+
+/* the 'server' function that we export via the door. It does
+ * nothing but return.
+ */
+/*ARGSUSED*/
+static void
+server( void __attribute__((unused)) *cookie,
+ char __attribute__((unused)) *argp,
+ size_t __attribute__((unused)) arg_size,
+ door_desc_t __attribute__((unused)) *dp,
+ __attribute__((unused)) uint_t n )
+{
+ (void) door_return(NULL, 0, NULL, 0);
+ /* NOTREACHED */
+}
+
+/*ARGSUSED*/
+static void *
+create_door_thr(void __attribute__((unused)) *arg)
+{
+ (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+ (void) door_return(NULL, 0, NULL, 0);
+
+ /* If there is an error in door_return(), it will return here and
+ * the thread will exit. Hence we need to decrement door_server_cnt.
+ */
+ (void) pthread_mutex_lock(&door_server_cnt_lock);
+ door_server_cnt--;
+ (void) pthread_mutex_unlock(&door_server_cnt_lock);
+ return (NULL);
+}
+
+/*
+ * Manage door server thread pool.
+ */
+/*ARGSUSED*/
+static void
+door_server_pool(door_info_t __attribute__((unused)) *dip)
+{
+ (void) pthread_mutex_lock(&door_server_cnt_lock);
+ if (door_server_cnt <= MAX_DOOR_SERVER_THR &&
+ pthread_create(NULL, &door_thr_attr, create_door_thr, NULL) == 0) {
+ door_server_cnt++;
+ (void) pthread_mutex_unlock(&door_server_cnt_lock);
+ return;
+ }
+
+ (void) pthread_mutex_unlock(&door_server_cnt_lock);
+}
+
+void
+sun_delete_doorfiles(void)
+{
+ struct stat sb;
+ int err;
+ char line[ERRMSG_LEN+1];
+
+ if (lstat(DoorFileName, &sb) == 0 && !S_ISDIR(sb.st_mode)) {
+ if (unlink(DoorFileName) < 0) {
+ err = errno;
+ (void) snprintf(line, sizeof (line),
+ "unlink() of %s failed - fatal", DoorFileName);
+ imsolaris_logerror(err, line);
+ DBGPRINTF("delete_doorfiles: error: %s, "
+ "errno=%d\n", line, err);
+ exit(1);
+ }
+
+ DBGPRINTF("delete_doorfiles: deleted %s\n", DoorFileName);
+ }
+
+ if (strcmp(DoorFileName, DOORFILE) == 0) {
+ if (lstat(OLD_DOORFILE, &sb) == 0 && !S_ISDIR(sb.st_mode)) {
+ if (unlink(OLD_DOORFILE) < 0) {
+ err = errno;
+ (void) snprintf(line, sizeof (line),
+ "unlink() of %s failed", OLD_DOORFILE);
+ DBGPRINTF("delete_doorfiles: %s\n", line);
+
+ if (err != EROFS) {
+ errno = err;
+ (void) strlcat(line, " - fatal",
+ sizeof (line));
+ imsolaris_logerror(err, line);
+ DBGPRINTF("delete_doorfiles: "
+ "error: %s, errno=%d\n",
+ line, err);
+ exit(1);
+ }
+
+ DBGPRINTF("delete_doorfiles: unlink() "
+ "failure OK on RO file system\n");
+ }
+
+ DBGPRINTF("delete_doorfiles: deleted %s\n",
+ OLD_DOORFILE);
+ }
+ }
+
+ if (DoorFd != -1) {
+ (void) door_revoke(DoorFd);
+ }
+
+ DBGPRINTF("delete_doorfiles: revoked door: DoorFd=%d\n",
+ DoorFd);
+}
+
+
+/* Create the door file. If the filesystem
+ * containing /etc is writable, create symlinks /etc/.syslog_door
+ * to them. On systems that do not support /var/run, create
+ * /etc/.syslog_door directly.
+ */
+void
+sun_open_door(void)
+{
+ struct stat buf;
+ door_info_t info;
+ char line[ERRMSG_LEN+1];
+ int err;
+
+ /* first see if another instance of imsolaris OR another
+ * syslogd is running by trying a door call - if it succeeds,
+ * there is already one active.
+ */
+
+ if (!DoorCreated) {
+ int door;
+
+ if ((door = open(DoorFileName, O_RDONLY)) >= 0) {
+ DBGPRINTF("open_door: %s opened "
+ "successfully\n", DoorFileName);
+
+ if (door_info(door, &info) >= 0) {
+ DBGPRINTF("open_door: "
+ "door_info:info.di_target = %ld\n",
+ info.di_target);
+
+ if (info.di_target > 0) {
+ (void) sprintf(line, "syslogd pid %ld"
+ " already running. Cannot "
+ "start another syslogd pid %ld",
+ info.di_target, getpid());
+ DBGPRINTF("open_door: error: "
+ "%s\n", line);
+ imsolaris_logerror(0, line);
+ exit(1);
+ }
+ }
+
+ (void) close(door);
+ } else {
+ if (lstat(DoorFileName, &buf) < 0) {
+ err = errno;
+
+ DBGPRINTF("open_door: lstat() of %s "
+ "failed, errno=%d\n",
+ DoorFileName, err);
+
+ if ((door = creat(DoorFileName, 0644)) < 0) {
+ err = errno;
+ (void) snprintf(line, sizeof (line),
+ "creat() of %s failed - fatal",
+ DoorFileName);
+ DBGPRINTF("open_door: error: %s, "
+ "errno=%d\n", line,
+ err);
+ imsolaris_logerror(err, line);
+ sun_delete_doorfiles();
+ exit(1);
+ }
+
+ (void) fchmod(door,
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+
+ DBGPRINTF("open_door: creat() of %s "
+ "succeeded\n",
+ DoorFileName);
+
+ (void) close(door);
+ }
+ }
+
+ if (strcmp(DoorFileName, DOORFILE) == 0) {
+ if (lstat(OLD_DOORFILE, &buf) == 0) {
+ DBGPRINTF("open_door: lstat() of %s "
+ "succeeded\n", OLD_DOORFILE);
+
+ if (S_ISDIR(buf.st_mode)) {
+ (void) snprintf(line, sizeof (line),
+ "%s is a directory - fatal",
+ OLD_DOORFILE);
+ DBGPRINTF("open_door: error: "
+ "%s\n", line);
+ imsolaris_logerror(0, line);
+ sun_delete_doorfiles();
+ exit(1);
+ }
+
+ DBGPRINTF("open_door: %s is not a "
+ "directory\n", OLD_DOORFILE);
+ if (unlink(OLD_DOORFILE) < 0) {
+ err = errno;
+ (void) snprintf(line, sizeof (line),
+ "unlink() of %s failed",
+ OLD_DOORFILE);
+ DBGPRINTF("open_door: %s\n",
+ line);
+
+ if (err != EROFS) {
+ DBGPRINTF("open_door: "
+ "error: %s, "
+ "errno=%d\n",
+ line, err);
+ (void) strcat(line, " - fatal");
+ imsolaris_logerror(err, line);
+ sun_delete_doorfiles();
+ exit(1);
+ }
+
+ DBGPRINTF("open_door: unlink "
+ "failure OK on RO file "
+ "system\n");
+ }
+ } else {
+ DBGPRINTF("open_door: file %s doesn't "
+ "exist\n", OLD_DOORFILE);
+ }
+
+ if (symlink(RELATIVE_DOORFILE, OLD_DOORFILE) < 0) {
+ err = errno;
+ (void) snprintf(line, sizeof (line),
+ "symlink %s -> %s failed", OLD_DOORFILE,
+ RELATIVE_DOORFILE);
+ DBGPRINTF("open_door: %s\n",
+ line);
+
+ if (err != EROFS) {
+ DBGPRINTF("open_door: error: %s, "
+ "errno=%d\n", line,
+ err);
+ (void) strcat(line, " - fatal");
+ imsolaris_logerror(err, line);
+ sun_delete_doorfiles();
+ exit(1);
+ }
+
+ DBGPRINTF("open_door: symlink failure OK "
+ "on RO file system\n");
+ } else {
+ DBGPRINTF("open_door: symlink %s -> %s "
+ "succeeded\n",
+ OLD_DOORFILE, RELATIVE_DOORFILE);
+ }
+ }
+
+ if ((DoorFd = door_create(server, 0,
+ DOOR_REFUSE_DESC)) < 0) {
+ //???? DOOR_NO_CANEL requires newer libs??? DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) < 0) {
+ err = errno;
+ (void) sprintf(line, "door_create() failed - fatal");
+ DBGPRINTF("open_door: error: %s, errno=%d\n",
+ line, err);
+ imsolaris_logerror(err, line);
+ sun_delete_doorfiles();
+ exit(1);
+ }
+ //???? (void) door_setparam(DoorFd, DOOR_PARAM_DATA_MAX, 0);
+ DBGPRINTF("open_door: door_create() succeeded, "
+ "DoorFd=%d\n", DoorFd);
+
+ DoorCreated = 1;
+ }
+
+ (void) fdetach(DoorFileName); /* just in case... */
+
+ (void) door_server_create(door_server_pool);
+
+ if (fattach(DoorFd, DoorFileName) < 0) {
+ err = errno;
+ (void) snprintf(line, sizeof (line), "fattach() of fd"
+ " %d to %s failed - fatal", DoorFd, DoorFileName);
+ DBGPRINTF("open_door: error: %s, errno=%d\n",
+ line, err);
+ imsolaris_logerror(err, line);
+ sun_delete_doorfiles();
+ exit(1);
+ }
+
+ DBGPRINTF("open_door: attached server() to %s\n",
+ DoorFileName);
+
+}
+
+
+/* Attempts to open the local log device
+ * and return a file descriptor.
+ */
+rsRetVal
+sun_openklog(char *name)
+{
+ DEFiRet;
+ int fd;
+ struct strioctl str;
+ char errBuf[1024];
+
+ if((fd = open(name, O_RDONLY)) < 0) {
+ rs_strerror_r(errno, errBuf, sizeof(errBuf));
+ DBGPRINTF("imsolaris:openklog: cannot open %s: %s\n",
+ name, errBuf);
+ ABORT_FINALIZE(RS_RET_ERR_OPEN_KLOG);
+ }
+ str.ic_cmd = I_CONSLOG;
+ str.ic_timout = 0;
+ str.ic_len = 0;
+ str.ic_dp = NULL;
+ if (ioctl(fd, I_STR, &str) < 0) {
+ rs_strerror_r(errno, errBuf, sizeof(errBuf));
+ DBGPRINTF("imsolaris:openklog: cannot register to log "
+ "console messages: %s\n", errBuf);
+ ABORT_FINALIZE(RS_RET_ERR_AQ_CONLOG);
+ }
+ sun_Pfd.fd = fd;
+ sun_Pfd.events = POLLIN;
+ DBGPRINTF("imsolaris/openklog: opened '%s' as fd %d.\n", name, fd);
+
+finalize_it:
+ RETiRet;
+}
diff --git a/plugins/imsolaris/sun_cddl.h b/plugins/imsolaris/sun_cddl.h
new file mode 100644
index 00000000..42e4b799
--- /dev/null
+++ b/plugins/imsolaris/sun_cddl.h
@@ -0,0 +1,7 @@
+rsRetVal sun_openklog(char *name);
+void prepare_sys_poll(void);
+void sun_sys_poll(void);
+void sun_open_door(void);
+void sun_delete_doorfiles(void);
+
+extern struct pollfd sun_Pfd; /* Pollfd for local log device */
diff --git a/plugins/imtcp/imtcp.c b/plugins/imtcp/imtcp.c
index 176b5b18..0cfae057 100644
--- a/plugins/imtcp/imtcp.c
+++ b/plugins/imtcp/imtcp.c
@@ -86,6 +86,7 @@ static int iTCPLstnMax = 20; /* max number of sessions */
static int iStrmDrvrMode = 0; /* mode for stream driver, driver-dependent (0 mostly means plain tcp) */
static int bEmitMsgOnClose = 0; /* emit an informational message on close by remote peer */
static int iAddtlFrameDelim = TCPSRV_NO_ADDTL_DELIMITER; /* addtl frame delimiter, e.g. for netscreen, default none */
+static int bDisableLFDelim = 0; /* disbale standard LF delimiter */
static uchar *pszStrmDrvrAuthMode = NULL; /* authentication mode to use */
static uchar *pszInputName = NULL; /* value for inputname property, NULL is OK and handled by core engine */
static ruleset_t *pBindRuleset = NULL; /* ruleset to bind listener to (use system default if unspecified) */
@@ -97,7 +98,7 @@ static int
isPermittedHost(struct sockaddr *addr, char *fromHostFQDN, void __attribute__((unused)) *pUsrSrv,
void __attribute__((unused)) *pUsrSess)
{
- return net.isAllowedSender(UCHAR_CONSTANT("TCP"), addr, fromHostFQDN);
+ return net.isAllowedSender2(UCHAR_CONSTANT("TCP"), addr, fromHostFQDN, 1);
}
@@ -198,6 +199,7 @@ static rsRetVal addTCPListener(void __attribute__((unused)) *pVal, uchar *pNewVa
CHKiRet(tcpsrv.SetCBOnErrClose(pOurTcpsrv, onErrClose));
CHKiRet(tcpsrv.SetDrvrMode(pOurTcpsrv, iStrmDrvrMode));
CHKiRet(tcpsrv.SetAddtlFrameDelim(pOurTcpsrv, iAddtlFrameDelim));
+ CHKiRet(tcpsrv.SetbDisableLFDelim(pOurTcpsrv, bDisableLFDelim));
CHKiRet(tcpsrv.SetNotificationOnRemoteClose(pOurTcpsrv, bEmitMsgOnClose));
/* now set optional params, but only if they were actually configured */
if(pszStrmDrvrAuthMode != NULL) {
@@ -288,6 +290,7 @@ resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unus
iStrmDrvrMode = 0;
bEmitMsgOnClose = 0;
iAddtlFrameDelim = TCPSRV_NO_ADDTL_DELIMITER;
+ bDisableLFDelim = 0;
free(pszInputName);
pszInputName = NULL;
free(pszStrmDrvrAuthMode);
@@ -334,6 +337,8 @@ CODEmodInit_QueryRegCFSLineHdlr
eCmdHdlrGetWord, setPermittedPeer, NULL, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserveraddtlframedelimiter"), 0, eCmdHdlrInt,
NULL, &iAddtlFrameDelim, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserverdisablelfdelimiter"), 0, eCmdHdlrBinary,
+ NULL, &bDisableLFDelim, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserverinputname"), 0,
eCmdHdlrGetWord, NULL, &pszInputName, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserverbindruleset"), 0,
diff --git a/plugins/imudp/imudp.c b/plugins/imudp/imudp.c
index 96d18372..99b69731 100644
--- a/plugins/imudp/imudp.c
+++ b/plugins/imudp/imudp.c
@@ -63,6 +63,7 @@ DEFobjCurrIf(datetime)
DEFobjCurrIf(prop)
DEFobjCurrIf(ruleset)
+static int bDoACLCheck; /* are ACL checks neeed? Cached once immediately before listener startup */
static int iMaxLine; /* maximum UDP message size supported */
static time_t ttLastDiscard = 0; /* timestamp when a message from a non-permitted sender was last discarded
* This shall prevent remote DoS when the "discard on disallowed sender"
@@ -117,7 +118,6 @@ static rsRetVal addListner(void __attribute__((unused)) *pVal, uchar *pNewVal)
if(udpLstnSocks == NULL) {
/* esay, we can just replace it */
udpLstnSocks = newSocks;
-RUNLOG_VAR("%d", newSocks[0]);
CHKmalloc(udpRulesets = (ruleset_t**) MALLOC(sizeof(ruleset_t*) * (newSocks[0] + 1)));
for(iDst = 1 ; iDst <= newSocks[0] ; ++iDst)
udpRulesets[iDst] = pBindRuleset;
@@ -200,7 +200,7 @@ finalize_it:
*/
static inline rsRetVal
processSocket(thrdInfo_t *pThrd, int fd, struct sockaddr_storage *frominetPrev, int *pbIsPermitted,
- uchar *fromHost, uchar *fromHostFQDN, uchar *fromHostIP, ruleset_t *pRuleset)
+ ruleset_t *pRuleset)
{
DEFiRet;
int iNbrTimeUsed;
@@ -235,37 +235,39 @@ processSocket(thrdInfo_t *pThrd, int fd, struct sockaddr_storage *frominetPrev,
/* if we reach this point, we had a good receive and can process the packet received */
/* check if we have a different sender than before, if so, we need to query some new values */
- if(net.CmpHost(&frominet, frominetPrev, socklen) != 0) {
- CHKiRet(net.cvthname(&frominet, fromHost, fromHostFQDN, fromHostIP));
- memcpy(frominetPrev, &frominet, socklen); /* update cache indicator */
- /* Here we check if a host is permitted to send us
- * syslog messages. If it isn't, we do not further
- * process the message but log a warning (if we are
- * configured to do this).
- * rgerhards, 2005-09-26
- */
- *pbIsPermitted = net.isAllowedSender((uchar*)"UDP",
- (struct sockaddr *)&frominet, (char*)fromHostFQDN);
-
- if(!*pbIsPermitted) {
- DBGPRINTF("%s is not an allowed sender\n", (char*)fromHostFQDN);
- if(glbl.GetOption_DisallowWarning) {
- time_t tt;
-
- datetime.GetTime(&tt);
- if(tt > ttLastDiscard + 60) {
- ttLastDiscard = tt;
- errmsg.LogError(0, NO_ERRCODE,
- "UDP message from disallowed sender %s discarded",
- (char*)fromHost);
+ if(bDoACLCheck) {
+ if(net.CmpHost(&frominet, frominetPrev, socklen) != 0) {
+ memcpy(frominetPrev, &frominet, socklen); /* update cache indicator */
+ /* Here we check if a host is permitted to send us syslog messages. If it isn't,
+ * we do not further process the message but log a warning (if we are
+ * configured to do this). However, if the check would require name resolution,
+ * it is postponed to the main queue. See also my blog post at
+ * http://blog.gerhards.net/2009/11/acls-imudp-and-accepting-messages.html
+ * rgerhards, 2009-11-16
+ */
+ *pbIsPermitted = net.isAllowedSender2((uchar*)"UDP",
+ (struct sockaddr *)&frominet, "", 0);
+
+ if(*pbIsPermitted == 0) {
+ DBGPRINTF("msg is not from an allowed sender\n");
+ if(glbl.GetOption_DisallowWarning) {
+ time_t tt;
+ datetime.GetTime(&tt);
+ if(tt > ttLastDiscard + 60) {
+ ttLastDiscard = tt;
+ errmsg.LogError(0, NO_ERRCODE,
+ "UDP message from disallowed sender discarded");
+ }
}
}
}
+ } else {
+ *pbIsPermitted = 1; /* no check -> everything permitted */
}
- DBGPRINTF("recv(%d,%d)/%s,acl:%d,msg:%s\n", fd, (int) lenRcvBuf, fromHost, *pbIsPermitted, pRcvBuf);
+ DBGPRINTF("recv(%d,%d),acl:%d,msg:%s\n", fd, (int) lenRcvBuf, *pbIsPermitted, pRcvBuf);
- if(*pbIsPermitted) {
+ if(*pbIsPermitted != 0) {
if((iTimeRequery == 0) || (iNbrTimeUsed++ % iTimeRequery) == 0) {
datetime.getCurrTime(&stTime, &ttGenTime);
}
@@ -275,9 +277,10 @@ processSocket(thrdInfo_t *pThrd, int fd, struct sockaddr_storage *frominetPrev,
MsgSetInputName(pMsg, pInputName);
MsgSetRuleset(pMsg, pRuleset);
MsgSetFlowControlType(pMsg, eFLOWCTL_NO_DELAY);
- pMsg->msgFlags = NEEDS_PARSING | PARSE_HOSTNAME;
- MsgSetRcvFromStr(pMsg, fromHost, ustrlen(fromHost), &propFromHost);
- CHKiRet(MsgSetRcvFromIPStr(pMsg, fromHostIP, ustrlen(fromHostIP), &propFromHostIP));
+ pMsg->msgFlags = NEEDS_PARSING | PARSE_HOSTNAME | NEEDS_DNSRESOL;
+ if(*pbIsPermitted == 2)
+ pMsg->msgFlags |= NEEDS_ACLCHK_U; /* request ACL check after resolution */
+ CHKiRet(msgSetFromSockinfo(pMsg, &frominet));
CHKiRet(submitMsg(pMsg));
}
}
@@ -307,9 +310,6 @@ rsRetVal rcvMainLoop(thrdInfo_t *pThrd)
int i;
struct sockaddr_storage frominetPrev;
int bIsPermitted;
- uchar fromHost[NI_MAXHOST];
- uchar fromHostIP[NI_MAXHOST];
- uchar fromHostFQDN[NI_MAXHOST];
struct epoll_event *udpEPollEvt = NULL;
struct epoll_event currEvt[NUM_EPOLL_EVENTS];
char errStr[1024];
@@ -359,7 +359,7 @@ rsRetVal rcvMainLoop(thrdInfo_t *pThrd)
for(i = 0 ; i < nfds ; ++i) {
processSocket(pThrd, udpLstnSocks[currEvt[i].data.u64], &frominetPrev, &bIsPermitted,
- fromHost, fromHostFQDN, fromHostIP, udpRulesets[currEvt[i].data.u64]);
+ udpRulesets[currEvt[i].data.u64]);
}
}
@@ -380,9 +380,6 @@ rsRetVal rcvMainLoop(thrdInfo_t *pThrd)
fd_set readfds;
struct sockaddr_storage frominetPrev;
int bIsPermitted;
- uchar fromHost[NI_MAXHOST];
- uchar fromHostIP[NI_MAXHOST];
- uchar fromHostFQDN[NI_MAXHOST];
/* start "name caching" algo by making sure the previous system indicator
* is invalidated.
@@ -399,7 +396,7 @@ rsRetVal rcvMainLoop(thrdInfo_t *pThrd)
* is given without -a, we do not need to listen at all..
*/
maxfds = 0;
- FD_ZERO (&readfds);
+ FD_ZERO(&readfds);
/* Add the UDP listen sockets to the list of read descriptors. */
for (i = 0; i < *udpLstnSocks; i++) {
@@ -413,7 +410,7 @@ rsRetVal rcvMainLoop(thrdInfo_t *pThrd)
if(Debug) {
dbgprintf("--------imUDP calling select, active file descriptors (max %d): ", maxfds);
for (nfds = 0; nfds <= maxfds; ++nfds)
- if ( FD_ISSET(nfds, &readfds) )
+ if(FD_ISSET(nfds, &readfds))
dbgprintf("%d ", nfds);
dbgprintf("\n");
}
@@ -426,7 +423,7 @@ rsRetVal rcvMainLoop(thrdInfo_t *pThrd)
for(i = 0; nfds && i < *udpLstnSocks; i++) {
if(FD_ISSET(udpLstnSocks[i+1], &readfds)) {
processSocket(pThrd, udpLstnSocks[i+1], &frominetPrev, &bIsPermitted,
- fromHost, fromHostFQDN, fromHostIP, udpRulesets[i+1]);
+ udpRulesets[i+1]);
--nfds; /* indicate we have processed one descriptor */
}
}
@@ -443,10 +440,6 @@ rsRetVal rcvMainLoop(thrdInfo_t *pThrd)
*/
BEGINrunInput
CODESTARTrunInput
- /* this is an endless loop - it is terminated when the thread is
- * signalled to do so. This, however, is handled by the framework,
- * right into the sleep below.
- */
iRet = rcvMainLoop(pThrd);
ENDrunInput
@@ -460,6 +453,7 @@ CODESTARTwillRun
CHKiRet(prop.ConstructFinalize(pInputName));
net.PrintAllowedSenders(1); /* UDP */
+ net.HasRestrictions(UCHAR_CONSTANT("UDP"), &bDoACLCheck); /* UDP */
/* if we could not set up any listners, there is no point in running... */
if(udpLstnSocks == NULL)
diff --git a/plugins/imuxsock/imuxsock.c b/plugins/imuxsock/imuxsock.c
index 17c85afb..046f12f0 100644
--- a/plugins/imuxsock/imuxsock.c
+++ b/plugins/imuxsock/imuxsock.c
@@ -46,6 +46,7 @@
#include "msg.h"
#include "prop.h"
#include "debug.h"
+#include "unlimited_select.h"
MODULE_TYPE_INPUT
@@ -294,7 +295,13 @@ BEGINrunInput
int nfds;
int i;
int fd;
- fd_set readfds;
+#ifdef USE_UNLIMITED_SELECT
+ fd_set *pReadfds = malloc(glbl.GetFdSetSize());
+#else
+ fd_set readfds;
+ fd_set *pReadfds = &readfds;
+#endif
+
CODESTARTrunInput
/* this is an endless loop - it is terminated when the thread is
* signalled to do so. This, however, is handled by the framework,
@@ -308,11 +315,11 @@ CODESTARTrunInput
* is given without -a, we do not need to listen at all..
*/
maxfds = 0;
- FD_ZERO (&readfds);
+ FD_ZERO (pReadfds);
/* Copy master connections */
for (i = startIndexUxLocalSockets; i < nfunix; i++) {
if (funix[i] != -1) {
- FD_SET(funix[i], &readfds);
+ FD_SET(funix[i], pReadfds);
if (funix[i]>maxfds) maxfds=funix[i];
}
}
@@ -320,20 +327,20 @@ CODESTARTrunInput
if(Debug) {
dbgprintf("--------imuxsock calling select, active file descriptors (max %d): ", maxfds);
for (nfds= 0; nfds <= maxfds; ++nfds)
- if ( FD_ISSET(nfds, &readfds) )
+ if ( FD_ISSET(nfds, pReadfds) )
dbgprintf("%d ", nfds);
dbgprintf("\n");
}
/* wait for io to become ready */
- nfds = select(maxfds+1, (fd_set *) &readfds, NULL, NULL, NULL);
+ nfds = select(maxfds+1, (fd_set *) pReadfds, NULL, NULL, NULL);
if(glbl.GetGlobalInputTermState() == 1)
break; /* terminate input! */
for (i = 0; i < nfunix && nfds > 0; i++) {
if(glbl.GetGlobalInputTermState() == 1)
ABORT_FINALIZE(RS_RET_FORCE_TERM); /* terminate input! */
- if ((fd = funix[i]) != -1 && FD_ISSET(fd, &readfds)) {
+ if ((fd = funix[i]) != -1 && FD_ISSET(fd, pReadfds)) {
readSocket(fd, i);
--nfds; /* indicate we have processed one */
}
@@ -341,6 +348,7 @@ CODESTARTrunInput
}
finalize_it:
+ freeFdSet(pReadfds);
RETiRet;
ENDrunInput
@@ -350,7 +358,16 @@ CODESTARTwillRun
register int i;
/* first apply some config settings */
- startIndexUxLocalSockets = bOmitLocalLogging ? 1 : 0;
+# ifdef OS_SOLARIS
+ /* under solaris, we must NEVER process the local log socket, because
+ * it is implemented there differently. If we used it, we would actually
+ * delete it and render the system partly unusable. So don't do that.
+ * rgerhards, 2010-03-26
+ */
+ startIndexUxLocalSockets = 1;
+# else
+ startIndexUxLocalSockets = bOmitLocalLogging ? 1 : 0;
+# endif
if(pLogSockName != NULL)
funixn[0] = pLogSockName;
@@ -379,7 +396,7 @@ CODESTARTafterRun
close(funix[i]);
/* Clean-up files. */
- for (i = 0; i < nfunix; i++)
+ for(i = startIndexUxLocalSockets; i < nfunix; i++)
if (funixn[i] && funix[i] != -1)
unlink((char*) funixn[i]);
/* free no longer needed string */
diff --git a/plugins/omdbalerting/Makefile.am b/plugins/omdbalerting/Makefile.am
new file mode 100644
index 00000000..becf29b0
--- /dev/null
+++ b/plugins/omdbalerting/Makefile.am
@@ -0,0 +1,8 @@
+pkglib_LTLIBRARIES = omdbalerting.la
+
+omdbalerting_la_SOURCES = omdbalerting.c
+omdbalerting_la_CPPFLAGS = $(RSRT_CFLAGS) $(PTHREADS_CFLAGS)
+omdbalerting_la_LDFLAGS = -module -avoid-version
+omdbalerting_la_LIBADD =
+
+EXTRA_DIST =
diff --git a/plugins/omdbalerting/omdbalerting.c b/plugins/omdbalerting/omdbalerting.c
new file mode 100644
index 00000000..2e04391c
--- /dev/null
+++ b/plugins/omdbalerting/omdbalerting.c
@@ -0,0 +1,144 @@
+/* omdbalerting.c
+ * generate alerts based on database contents - so far a skeleton
+ * left for implementation by somebody else (skeleton created on request).
+ *
+ * NOTE: read comments in module-template.h for more specifics!
+ *
+ * File begun on 2009-11-17 by RGerhards
+ *
+ * Copyright 2009 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 "rsyslog.h"
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <signal.h>
+#include <errno.h>
+#include <unistd.h>
+#include "conf.h"
+#include "syslogd-types.h"
+#include "srUtils.h"
+#include "template.h"
+#include "module-template.h"
+#include "errmsg.h"
+#include "cfsysline.h"
+
+MODULE_TYPE_OUTPUT
+
+/* internal structures
+ */
+DEF_OMOD_STATIC_DATA
+
+/* config variables */
+
+
+typedef struct _instanceData {
+} instanceData;
+
+BEGINcreateInstance
+CODESTARTcreateInstance
+ENDcreateInstance
+
+
+BEGINisCompatibleWithFeature
+CODESTARTisCompatibleWithFeature
+ if(eFeat == sFEATURERepeatedMsgReduction)
+ iRet = RS_RET_OK;
+ENDisCompatibleWithFeature
+
+
+BEGINfreeInstance
+CODESTARTfreeInstance
+ENDfreeInstance
+
+
+BEGINdbgPrintInstInfo
+CODESTARTdbgPrintInstInfo
+ENDdbgPrintInstInfo
+
+
+BEGINtryResume
+CODESTARTtryResume
+ENDtryResume
+
+BEGINdoAction
+CODESTARTdoAction
+ENDdoAction
+
+
+BEGINparseSelectorAct
+CODESTARTparseSelectorAct
+CODE_STD_STRING_REQUESTparseSelectorAct(1)
+ /* first check if this config line is actually for us */
+ if(strncmp((char*) p, ":omdbalerting:", sizeof(":dbalerting:") - 1)) {
+ ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED);
+ }
+
+ /* ok, if we reach this point, we have something for us */
+ p += sizeof(":omdbalerting:") - 1; /* eat indicator sequence (-1 because of '\0'!) */
+ CHKiRet(createInstance(&pData));
+
+ /* check if a non-standard template is to be applied */
+ if(*(p-1) == ';')
+ --p;
+ /* we request the standard interface via template, others may be more useful
+ * here.
+ */
+ CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, 0, (uchar*) "RSYSLOG_FileFormat"));
+CODE_STD_FINALIZERparseSelectorAct
+ENDparseSelectorAct
+
+
+BEGINmodExit
+CODESTARTmodExit
+ENDmodExit
+
+
+BEGINqueryEtryPt
+CODESTARTqueryEtryPt
+CODEqueryEtryPt_STD_OMOD_QUERIES
+ENDqueryEtryPt
+
+
+
+/* Reset config variables for this module to default values.
+ */
+static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
+{
+ DEFiRet;
+ RETiRet;
+}
+
+
+BEGINmodInit()
+CODESTARTmodInit
+ *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
+CODEmodInit_QueryRegCFSLineHdlr
+ // SAMPLE! CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionomdbalertingensurelfending", 0, eCmdHdlrBinary, NULL,
+ // &bEnsureLFEnding, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler,
+ resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
+ENDmodInit
+
+/* vi:set ai:
+ */
diff --git a/plugins/omprog/omprog.c b/plugins/omprog/omprog.c
index 01fa7cea..2687e7a3 100644
--- a/plugins/omprog/omprog.c
+++ b/plugins/omprog/omprog.c
@@ -169,7 +169,7 @@ openPipe(instanceData *pData)
/*NO CODE HERE - WILL NEVER BE REACHED!*/
}
- DBGPRINTF("child has pid %d\n", cpid);
+ DBGPRINTF("child has pid %d\n", (int) cpid);
pData->fdPipe = pipefd[1];
pData->pid = cpid;
close(pipefd[0]);
@@ -191,7 +191,6 @@ cleanup(instanceData *pData)
assert(pData != NULL);
assert(pData->bIsRunning == 1);
-RUNLOG_VAR("%d", pData->pid);
ret = waitpid(pData->pid, &status, 0);
if(ret != pData->pid) {
/* if waitpid() fails, we can not do much - try to ignore it... */
diff --git a/plugins/omstdout/omstdout.c b/plugins/omstdout/omstdout.c
index b3ec6287..929de703 100644
--- a/plugins/omstdout/omstdout.c
+++ b/plugins/omstdout/omstdout.c
@@ -103,7 +103,7 @@ CODESTARTdoAction
* So this code here is also more or less an example of how to do that.
* rgerhards, 2009-04-03
*/
- szParams = (char**) (ppString[0]);
+ szParams = (char**)(void*) (ppString[0]);
/* In array-passing mode, ppString[] contains a NULL-terminated array
* of char *pointers.
*/
diff --git a/runtime/Makefile.am b/runtime/Makefile.am
index caf7c5ca..2e85d846 100644
--- a/runtime/Makefile.am
+++ b/runtime/Makefile.am
@@ -9,13 +9,16 @@ librsyslog_la_SOURCES = \
rsyslog.h \
unicode-helper.h \
atomic.h \
+ atomic-posix-sem.c \
batch.h \
+ atomic-posix-sem.c \
syslogd-types.h \
module-template.h \
obj-types.h \
nsd.h \
glbl.h \
glbl.c \
+ unlimited_select.h \
conf.c \
conf.h \
parser.h \
@@ -136,7 +139,10 @@ lmnet_la_LDFLAGS = -module -avoid-version
lmnet_la_LIBADD =
# network stream master class and stream factory
-lmnetstrms_la_SOURCES = netstrms.c netstrms.h netstrm.c netstrm.h nssel.c nssel.h
+lmnetstrms_la_SOURCES = netstrms.c netstrms.h \
+ netstrm.c netstrm.h \
+ nssel.c nssel.h \
+ nspoll.c nspoll.h
lmnetstrms_la_CPPFLAGS = $(PTHREADS_CFLAGS) $(RSRT_CFLAGS)
lmnetstrms_la_LDFLAGS = -module -avoid-version
lmnetstrms_la_LIBADD =
@@ -152,7 +158,9 @@ lmstrmsrv_la_LIBADD =
# plain tcp driver - main driver
pkglib_LTLIBRARIES += lmnsd_ptcp.la
-lmnsd_ptcp_la_SOURCES = nsd_ptcp.c nsd_ptcp.h nsdsel_ptcp.c nsdsel_ptcp.h
+lmnsd_ptcp_la_SOURCES = nsd_ptcp.c nsd_ptcp.h \
+ nsdsel_ptcp.c nsdsel_ptcp.h \
+ nsdpoll_ptcp.c nsdpoll_ptcp.h
lmnsd_ptcp_la_CPPFLAGS = $(PTHREADS_CFLAGS) $(RSRT_CFLAGS)
lmnsd_ptcp_la_LDFLAGS = -module -avoid-version
lmnsd_ptcp_la_LIBADD =
diff --git a/runtime/atomic-posix-sem.c b/runtime/atomic-posix-sem.c
new file mode 100644
index 00000000..979fae02
--- /dev/null
+++ b/runtime/atomic-posix-sem.c
@@ -0,0 +1,70 @@
+/* atomic_posix_sem.c: This file supplies an emulation for atomic operations using
+ * POSIX semaphores.
+ *
+ * Copyright 2010 DResearch Digital Media Systems GmbH
+ *
+ * This file is part of the rsyslog runtime library.
+ *
+ * The rsyslog runtime library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The rsyslog runtime library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the rsyslog runtime library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * A copy of the GPL can be found in the file "COPYING" in this distribution.
+ * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution.
+ */
+
+#include "config.h"
+#ifndef HAVE_ATOMIC_BUILTINS
+#ifdef HAVE_SEMAPHORE_H
+#include <semaphore.h>
+#include <errno.h>
+
+#include "atomic.h"
+#include "rsyslog.h"
+#include "srUtils.h"
+
+sem_t atomicSem;
+
+rsRetVal
+atomicSemInit(void)
+{
+ DEFiRet;
+
+ dbgprintf("init posix semaphore for atomics emulation\n");
+ if(sem_init(&atomicSem, 0, 1) == -1)
+ {
+ char errStr[1024];
+ rs_strerror_r(errno, errStr, sizeof(errStr));
+ dbgprintf("init posix semaphore for atomics emulation failed: %s\n", errStr);
+ iRet = RS_RET_SYS_ERR; /* the right error code ??? */
+ }
+
+ RETiRet;
+}
+
+void
+atomicSemExit(void)
+{
+ dbgprintf("destroy posix semaphore for atomics emulation\n");
+ if(sem_destroy(&atomicSem) == -1)
+ {
+ char errStr[1024];
+ rs_strerror_r(errno, errStr, sizeof(errStr));
+ dbgprintf("destroy posix semaphore for atomics emulation failed: %s\n", errStr);
+ }
+}
+
+#endif /* HAVE_SEMAPHORE_H */
+#endif /* !defined(HAVE_ATOMIC_BUILTINS) */
+
+/* vim:set ai:
+ */
diff --git a/runtime/atomic.h b/runtime/atomic.h
index b507b769..cdcb1410 100644
--- a/runtime/atomic.h
+++ b/runtime/atomic.h
@@ -31,8 +31,6 @@
* A copy of the GPL can be found in the file "COPYING" in this distribution.
* A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution.
*/
-#include "config.h" /* autotools! */
-
#ifndef INCLUDED_ATOMIC_H
#define INCLUDED_ATOMIC_H
@@ -54,6 +52,122 @@
# define ATOMIC_CAS(data, oldVal, newVal) __sync_bool_compare_and_swap(&(data), (oldVal), (newVal));
# define ATOMIC_CAS_VAL(data, oldVal, newVal) __sync_val_compare_and_swap(&(data), (oldVal), (newVal));
#else
+#ifdef HAVE_SEMAPHORE_H
+ /* we use POSIX semaphores instead */
+
+#include "rsyslog.h"
+#include <semaphore.h>
+
+extern sem_t atomicSem;
+rsRetVal atomicSemInit(void);
+void atomicSemExit(void);
+
+#if HAVE_TYPEOF
+#define my_typeof(x) typeof(x)
+#else /* sorry, can't determine types, using 'int' */
+#define my_typeof(x) int
+#endif
+
+# define ATOMIC_SUB(data, val) \
+({ \
+ my_typeof(data) tmp; \
+ sem_wait(&atomicSem); \
+ tmp = data; \
+ data -= val; \
+ sem_post(&atomicSem); \
+ tmp; \
+})
+
+# define ATOMIC_ADD(data, val) \
+({ \
+ my_typeof(data) tmp; \
+ sem_wait(&atomicSem); \
+ tmp = data; \
+ data += val; \
+ sem_post(&atomicSem); \
+ tmp; \
+})
+
+# define ATOMIC_INC_AND_FETCH(data) \
+({ \
+ my_typeof(data) tmp; \
+ sem_wait(&atomicSem); \
+ tmp = data; \
+ data += 1; \
+ sem_post(&atomicSem); \
+ tmp; \
+})
+
+# define ATOMIC_INC(data) ((void) ATOMIC_INC_AND_FETCH(data))
+
+# define ATOMIC_DEC_AND_FETCH(data) \
+({ \
+ sem_wait(&atomicSem); \
+ data -= 1; \
+ sem_post(&atomicSem); \
+ data; \
+})
+
+# define ATOMIC_DEC(data) ((void) ATOMIC_DEC_AND_FETCH(data))
+
+# define ATOMIC_FETCH_32BIT(data) ((unsigned) ATOMIC_ADD((data), 0xffffffff))
+
+# define ATOMIC_STORE_1_TO_32BIT(data) \
+({ \
+ my_typeof(data) tmp; \
+ sem_wait(&atomicSem); \
+ tmp = data; \
+ data = 1; \
+ sem_post(&atomicSem); \
+ tmp; \
+})
+
+# define ATOMIC_STORE_0_TO_INT(data) \
+({ \
+ my_typeof(data) tmp; \
+ sem_wait(&atomicSem); \
+ tmp = data; \
+ data = 0; \
+ sem_post(&atomicSem); \
+ tmp; \
+})
+
+# define ATOMIC_STORE_1_TO_INT(data) \
+({ \
+ my_typeof(data) tmp; \
+ sem_wait(&atomicSem); \
+ tmp = data; \
+ data = 1; \
+ sem_post(&atomicSem); \
+ tmp; \
+})
+
+# define ATOMIC_CAS(data, oldVal, newVal) \
+({ \
+ int ret; \
+ sem_wait(&atomicSem); \
+ if(data != oldVal) ret = 0; \
+ else \
+ { \
+ data = newVal; \
+ ret = 1; \
+ } \
+ sem_post(&atomicSem); \
+ ret; \
+})
+
+# define ATOMIC_CAS_VAL(data, oldVal, newVal) \
+({ \
+ sem_wait(&atomicSem); \
+ if(data == oldVal) \
+ { \
+ data = newVal; \
+ } \
+ sem_post(&atomicSem); \
+ data; \
+})
+
+#else /* not HAVE_SEMAPHORE_H */
/* note that we gained parctical proof that theoretical problems DO occur
* if we do not properly address them. See this blog post for details:
* http://blog.gerhards.net/2009/01/rsyslog-data-race-analysis.html
@@ -67,6 +181,10 @@
# define ATOMIC_DEC_AND_FETCH(data) (--(data))
# define ATOMIC_FETCH_32BIT(data) (data)
# define ATOMIC_STORE_1_TO_32BIT(data) (data) = 1
+# define ATOMIC_STORE_1_TO_INT(data) (data) = 1
+# define ATOMIC_STORE_0_TO_INT(data) (data) = 0
+# define ATOMIC_CAS_VAL(data, oldVal, newVal) (data) = (newVal)
+#endif
#endif
#endif /* #ifndef INCLUDED_ATOMIC_H */
diff --git a/runtime/cfsysline.c b/runtime/cfsysline.c
index 184c0d87..5df8e64c 100644
--- a/runtime/cfsysline.c
+++ b/runtime/cfsysline.c
@@ -217,9 +217,11 @@ static rsRetVal doGetSize(uchar **pp, rsRetVal (*pSetHdlr)(void*, uid_t), void *
case 'K': i *= 1000; ++(*pp); break;
case 'M': i *= 1000000; ++(*pp); break;
case 'G': i *= 1000000000; ++(*pp); break;
- case 'T': i *= 1000000000000; ++(*pp); break; /* tera */
- case 'P': i *= 1000000000000000; ++(*pp); break; /* peta */
- case 'E': i *= 1000000000000000000; ++(*pp); break; /* exa */
+ /* we need to use the multiplication below because otherwise
+ * the compiler gets an error during constant parsing */
+ case 'T': i *= (int64) 1000 * 1000000000; ++(*pp); break; /* tera */
+ case 'P': i *= (int64) 1000000 * 1000000000; ++(*pp); break; /* peta */
+ case 'E': i *= (int64) 1000000000 * 1000000000; ++(*pp); break; /* exa */
}
/* done */
diff --git a/runtime/debug.c b/runtime/debug.c
index 8b4950a1..899d05da 100644
--- a/runtime/debug.c
+++ b/runtime/debug.c
@@ -46,6 +46,9 @@
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
+#if _POSIX_TIMERS <= 0
+#include <sys/time.h>
+#endif
#include "rsyslog.h"
#include "debug.h"
@@ -154,7 +157,9 @@ static pthread_key_t keyCallStack;
*/
static void dbgMutexCancelCleanupHdlr(void *pmut)
{
- pthread_mutex_unlock((pthread_mutex_t*) pmut);
+ int ret;
+ ret = pthread_mutex_unlock((pthread_mutex_t*) pmut);
+ assert(ret == 0);
}
@@ -844,6 +849,9 @@ do_dbgprint(uchar *pszObjName, char *pszMsg, size_t lenMsg)
char pszWriteBuf[32*1024];
size_t lenWriteBuf;
struct timespec t;
+# if _POSIX_TIMERS <= 0
+ struct timeval tv;
+# endif
/* The bWasNL handler does not really work. It works if no thread
* switching occurs during non-NL messages. Else, things are messed
@@ -869,7 +877,14 @@ do_dbgprint(uchar *pszObjName, char *pszMsg, size_t lenMsg)
if(bWasNL) {
if(bPrintTime) {
+# if _POSIX_TIMERS > 0
+ /* this is the "regular" code */
clock_gettime(CLOCK_REALTIME, &t);
+# else
+ gettimeofday(&tv, NULL);
+ t.tv_sec = tv.tv_sec;
+ t.tv_nsec = tv.tv_usec * 1000;
+# endif
lenWriteBuf = snprintf(pszWriteBuf, sizeof(pszWriteBuf),
"%4.4ld.%9.9ld:", (long) (t.tv_sec % 10000), t.tv_nsec);
if(stddbg != -1) write(stddbg, pszWriteBuf, lenWriteBuf);
@@ -950,6 +965,15 @@ dbgoprint(obj_t *pObj, char *fmt, ...)
va_start(ap, fmt);
lenWriteBuf = vsnprintf(pszWriteBuf, sizeof(pszWriteBuf), fmt, ap);
va_end(ap);
+ if(lenWriteBuf >= sizeof(pszWriteBuf)) {
+ /* prevent buffer overrruns and garbagge display */
+ pszWriteBuf[sizeof(pszWriteBuf) - 5] = '.';
+ pszWriteBuf[sizeof(pszWriteBuf) - 4] = '.';
+ pszWriteBuf[sizeof(pszWriteBuf) - 3] = '.';
+ pszWriteBuf[sizeof(pszWriteBuf) - 2] = '\n';
+ pszWriteBuf[sizeof(pszWriteBuf) - 1] = '\0';
+ lenWriteBuf = sizeof(pszWriteBuf);
+ }
dbgprint(pObj, pszWriteBuf, lenWriteBuf);
}
@@ -1307,11 +1331,11 @@ dbgGetRuntimeOptions(void)
/* this is earlier in the process than the -d option, as such it
* allows us to spit out debug messages from the very beginning.
*/
- Debug = 1;
+ Debug = DEBUG_FULL;
debugging_on = 1;
} else if(!strcasecmp((char*)optname, "debugondemand")) {
/* Enables debugging, but turns off debug output */
- Debug = 1;
+ Debug = DEBUG_ONDEMAND;
debugging_on = 1;
dbgprintf("Note: debug on demand turned on via configuraton file, "
"use USR1 signal to activate.\n");
diff --git a/runtime/debug.h b/runtime/debug.h
index 8d9c1ceb..c011dd2d 100644
--- a/runtime/debug.h
+++ b/runtime/debug.h
@@ -29,6 +29,11 @@
#include <pthread.h>
#include "obj-types.h"
+/* some settings for various debug modes */
+#define DEBUG_OFF 0
+#define DEBUG_ONDEMAND 1
+#define DEBUG_FULL 2
+
/* external static data elements (some time to be replaced) */
extern int Debug; /* debug flag - read-only after startup */
extern int debugging_on; /* read-only, except on sig USR1 */
diff --git a/runtime/glbl.c b/runtime/glbl.c
index 71c2ed0d..ac08791f 100644
--- a/runtime/glbl.c
+++ b/runtime/glbl.c
@@ -74,6 +74,9 @@ static uchar *pszDfltNetstrmDrvrCAF = NULL; /* default CA file for the netstrm d
static uchar *pszDfltNetstrmDrvrKeyFile = NULL; /* default key file for the netstrm driver (server) */
static uchar *pszDfltNetstrmDrvrCertFile = NULL; /* default cert file for the netstrm driver (server) */
static int bTerminateInputs = 0; /* global switch that inputs shall terminate ASAP (1=> terminate) */
+#ifdef USE_UNLIMITED_SELECT
+static int iFdSetSize = howmany(FD_SETSIZE, __NFDBITS) * sizeof (fd_mask); /* size of select() bitmask in bytes */
+#endif
/* define a macro for the simple properties' set and get functions
@@ -106,6 +109,9 @@ SIMP_PROP(DisableDNS, bDisableDNS, int)
SIMP_PROP(LocalDomain, LocalDomain, uchar*)
SIMP_PROP(StripDomains, StripDomains, char**)
SIMP_PROP(LocalHosts, LocalHosts, char**)
+#ifdef USE_UNLIMITED_SELECT
+SIMP_PROP(FdSetSize, iFdSetSize, int)
+#endif
SIMP_PROP_SET(LocalFQDNName, LocalFQDNName, uchar*)
SIMP_PROP_SET(LocalHostName, LocalHostName, uchar*)
@@ -284,6 +290,9 @@ CODESTARTobjQueryInterface(glbl)
SIMP_PROP(DfltNetstrmDrvrCAF)
SIMP_PROP(DfltNetstrmDrvrKeyFile)
SIMP_PROP(DfltNetstrmDrvrCertFile)
+#ifdef USE_UNLIMITED_SELECT
+ SIMP_PROP(FdSetSize)
+#endif
#undef SIMP_PROP
finalize_it:
ENDobjQueryInterface(glbl)
@@ -317,6 +326,9 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a
bDropMalPTRMsgs = 0;
bOptimizeUniProc = 1;
bPreserveFQDN = 0;
+#ifdef USE_UNLIMITED_SELECT
+ iFdSetSize = howmany(FD_SETSIZE, __NFDBITS) * sizeof (fd_mask);
+#endif
return RS_RET_OK;
}
diff --git a/runtime/glbl.h b/runtime/glbl.h
index 7506f16b..4b4bdf83 100644
--- a/runtime/glbl.h
+++ b/runtime/glbl.h
@@ -66,9 +66,20 @@ BEGINinterface(glbl) /* name must also be changed in ENDinterface macro! */
void (*SetGlobalInputTermination)(void);
/* added v5, 2009-11-03 */
SIMP_PROP(ParseHOSTNAMEandTAG, int)
+ /* note: v4, v5 are already used by more recent versions, so we need to skip them! */
+ /* added v6, 2009-11-16 as part of varmojfekoj's "unlimited select()" patch
+ * Note that it must be always present, otherwise the interface would have different
+ * versions depending on compile settings, what is not acceptable.
+ * Use this property with care, it is only truly available if UNLIMITED_SELECT is enabled
+ * (I did not yet further investigate the details, because that code hopefully can be removed
+ * at some later stage).
+ */
+ SIMP_PROP(FdSetSize, int)
+ /* v7: was neeeded to mean v5+v6 - do NOT add anything else for that version! */
+ /* next change is v8! */
#undef SIMP_PROP
ENDinterface(glbl)
-#define glblCURR_IF_VERSION 5 /* increment whenever you change the interface structure! */
+#define glblCURR_IF_VERSION 7 /* increment whenever you change the interface structure! */
/* version 2 had PreserveFQDN added - rgerhards, 2008-12-08 */
/* the remaining prototypes */
diff --git a/runtime/modules.c b/runtime/modules.c
index fd3468d8..1af94abc 100644
--- a/runtime/modules.c
+++ b/runtime/modules.c
@@ -472,7 +472,6 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_
localRet = (*pNew->modQueryEtryPt)((uchar*)"endTransaction", &pNew->mod.om.endTransaction);
if(localRet == RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) {
pNew->mod.om.endTransaction = dummyEndTransaction;
- //pNew->mod.om.beginTransaction = dummyEndTransaction;
} else if(localRet != RS_RET_OK) {
ABORT_FINALIZE(localRet);
}
@@ -559,10 +558,35 @@ static void modPrintList(void)
dbgprintf(" module.\n");
dbgprintf("Entry points:\n");
dbgprintf("\tqueryEtryPt: 0x%lx\n", (unsigned long) pMod->modQueryEtryPt);
- dbgprintf("\tdoAction: 0x%lx\n", (unsigned long) pMod->mod.om.doAction);
- dbgprintf("\tparseSelectorAct: 0x%lx\n", (unsigned long) pMod->mod.om.parseSelectorAct);
dbgprintf("\tdbgPrintInstInfo: 0x%lx\n", (unsigned long) pMod->dbgPrintInstInfo);
dbgprintf("\tfreeInstance: 0x%lx\n", (unsigned long) pMod->freeInstance);
+ switch(pMod->eType) {
+ case eMOD_OUT:
+ dbgprintf("Output Module Entry Points:\n");
+ dbgprintf("\tdoAction: 0x%lx\n", (unsigned long) pMod->mod.om.doAction);
+ dbgprintf("\tparseSelectorAct: 0x%lx\n", (unsigned long) pMod->mod.om.parseSelectorAct);
+ dbgprintf("\ttryResume: 0x%lx\n", (unsigned long) pMod->tryResume);
+ dbgprintf("\tdoHUP: 0x%lx\n", (unsigned long) pMod->doHUP);
+ dbgprintf("\tBeginTransaction: 0x%lx\n", (unsigned long)
+ ((pMod->mod.om.beginTransaction == dummyBeginTransaction) ?
+ 0 : pMod->mod.om.beginTransaction));
+ dbgprintf("\tEndTransaction: 0x%lx\n", (unsigned long)
+ ((pMod->mod.om.endTransaction == dummyEndTransaction) ?
+ 0 : pMod->mod.om.endTransaction));
+ break;
+ case eMOD_IN:
+ dbgprintf("Input Module Entry Points\n");
+ dbgprintf("\trunInput: 0x%lx\n", (unsigned long) pMod->mod.im.runInput);
+ dbgprintf("\twillRun: 0x%lx\n", (unsigned long) pMod->mod.im.willRun);
+ dbgprintf("\tafterRun: 0x%lx\n", (unsigned long) pMod->mod.im.afterRun);
+ break;
+ case eMOD_LIB:
+ break;
+ case eMOD_PARSER:
+ dbgprintf("Parser Module Entry Points\n");
+ dbgprintf("\tparse: 0x%lx\n", (unsigned long) pMod->mod.pm.parse);
+ break;
+ }
dbgprintf("\n");
pMod = GetNxt(pMod); /* done, go next */
}
diff --git a/runtime/msg.c b/runtime/msg.c
index 6424b03a..5885cada 100644
--- a/runtime/msg.c
+++ b/runtime/msg.c
@@ -35,6 +35,8 @@
#include <string.h>
#include <assert.h>
#include <ctype.h>
+#include <sys/socket.h>
+#include <netdb.h>
#if HAVE_MALLOC_H
# include <malloc.h>
#endif
@@ -51,6 +53,7 @@
#include "unicode-helper.h"
#include "ruleset.h"
#include "prop.h"
+#include "net.h"
/* static data */
DEFobjStaticHelpers
@@ -59,6 +62,7 @@ DEFobjCurrIf(datetime)
DEFobjCurrIf(glbl)
DEFobjCurrIf(regexp)
DEFobjCurrIf(prop)
+DEFobjCurrIf(net)
static struct {
uchar *pszName;
@@ -275,7 +279,7 @@ static char *syslog_number_names[24] = { "0", "1", "2", "3", "4", "5", "6", "7",
"15", "16", "17", "18", "19", "20", "21", "22", "23" };
/* some forward declarations */
-static int getAPPNAMELen(msg_t *pM, bool bLockMutex);
+static int getAPPNAMELen(msg_t *pM, sbool bLockMutex);
static inline int getProtocolVersion(msg_t *pM)
@@ -284,6 +288,41 @@ static inline int getProtocolVersion(msg_t *pM)
}
+/* do a DNS reverse resolution, if not already done, reflect status
+ * rgerhards, 2009-11-16
+ */
+static inline rsRetVal
+resolveDNS(msg_t *pMsg) {
+ rsRetVal localRet;
+ prop_t *propFromHost = NULL;
+ prop_t *propFromHostIP = NULL;
+ uchar fromHost[NI_MAXHOST];
+ uchar fromHostIP[NI_MAXHOST];
+ uchar fromHostFQDN[NI_MAXHOST];
+ DEFiRet;
+
+ CHKiRet(objUse(net, CORE_COMPONENT));
+ if(pMsg->msgFlags & NEEDS_DNSRESOL) {
+ localRet = net.cvthname(pMsg->rcvFrom.pfrominet, fromHost, fromHostFQDN, fromHostIP);
+ if(localRet == RS_RET_OK) {
+ MsgSetRcvFromStr(pMsg, fromHost, ustrlen(fromHost), &propFromHost);
+ CHKiRet(MsgSetRcvFromIPStr(pMsg, fromHostIP, ustrlen(fromHostIP), &propFromHostIP));
+ }
+ }
+finalize_it:
+ if(iRet != RS_RET_OK) {
+ /* best we can do: remove property */
+ MsgSetRcvFromStr(pMsg, UCHAR_CONSTANT(""), 0, &propFromHost);
+ prop.Destruct(&propFromHost);
+ }
+ if(propFromHost != NULL)
+ prop.Destruct(&propFromHost);
+ if(propFromHostIP != NULL)
+ prop.Destruct(&propFromHostIP);
+ RETiRet;
+}
+
+
static inline void
getInputName(msg_t *pM, uchar **ppsz, int *plen)
{
@@ -307,6 +346,7 @@ getRcvFromIP(msg_t *pM)
if(pM == NULL) {
psz = UCHAR_CONSTANT("");
} else {
+ resolveDNS(pM); /* make sure we have a resolved entry */
if(pM->pRcvFromIP == NULL)
psz = UCHAR_CONSTANT("");
else
@@ -660,7 +700,7 @@ static inline rsRetVal msgBaseConstruct(msg_t **ppThis)
pM->pCSMSGID = NULL;
pM->pInputName = NULL;
pM->pRcvFromIP = NULL;
- pM->pRcvFrom = NULL;
+ pM->rcvFrom.pRcvFrom = NULL;
pM->pRuleset = NULL;
memset(&pM->tRcvdAt, 0, sizeof(pM->tRcvdAt));
memset(&pM->tTIMESTAMP, 0, sizeof(pM->tTIMESTAMP));
@@ -761,8 +801,12 @@ CODESTARTobjDestruct(msg)
freeHOSTNAME(pThis);
if(pThis->pInputName != NULL)
prop.Destruct(&pThis->pInputName);
- if(pThis->pRcvFrom != NULL)
- prop.Destruct(&pThis->pRcvFrom);
+ if((pThis->msgFlags & NEEDS_DNSRESOL) == 0) {
+ if(pThis->rcvFrom.pRcvFrom != NULL)
+ prop.Destruct(&pThis->rcvFrom.pRcvFrom);
+ } else {
+ free(pThis->rcvFrom.pfrominet);
+ }
if(pThis->pRcvFromIP != NULL)
prop.Destruct(&pThis->pRcvFromIP);
free(pThis->pszRcvdAt3164);
@@ -848,6 +892,7 @@ ENDobjDestruct(msg)
msg_t* MsgDup(msg_t* pOld)
{
msg_t* pNew;
+ rsRetVal localRet;
assert(pOld != NULL);
@@ -868,9 +913,19 @@ msg_t* MsgDup(msg_t* pOld)
pNew->iLenMSG = pOld->iLenMSG;
pNew->iLenTAG = pOld->iLenTAG;
pNew->iLenHOSTNAME = pOld->iLenHOSTNAME;
- if(pOld->pRcvFrom != NULL) {
- pNew->pRcvFrom = pOld->pRcvFrom;
- prop.AddRef(pNew->pRcvFrom);
+ if((pOld->msgFlags & NEEDS_DNSRESOL) == 1) {
+ localRet = msgSetFromSockinfo(pNew, pOld->rcvFrom.pfrominet);
+ if(localRet != RS_RET_OK) {
+ /* if something fails, we accept loss of this property, it is
+ * better than losing the whole message.
+ */
+ pNew->msgFlags &= ~NEEDS_DNSRESOL;
+ }
+ } else {
+ if(pOld->rcvFrom.pRcvFrom != NULL) {
+ pNew->rcvFrom.pRcvFrom = pOld->rcvFrom.pRcvFrom;
+ prop.AddRef(pNew->rcvFrom.pRcvFrom);
+ }
}
if(pOld->pRcvFromIP != NULL) {
pNew->pRcvFromIP = pOld->pRcvFromIP;
@@ -1492,7 +1547,7 @@ finalize_it:
* This must be called WITHOUT the message lock being held.
* rgerhards, 2009-06-26
*/
-static inline void preparePROCID(msg_t *pM, bool bLockMutex)
+static inline void preparePROCID(msg_t *pM, sbool bLockMutex)
{
if(pM->pCSPROCID == NULL) {
if(bLockMutex == LOCK_MUTEX)
@@ -1509,7 +1564,7 @@ static inline void preparePROCID(msg_t *pM, bool bLockMutex)
#if 0
/* rgerhards, 2005-11-24
*/
-static inline int getPROCIDLen(msg_t *pM, bool bLockMutex)
+static inline int getPROCIDLen(msg_t *pM, sbool bLockMutex)
{
assert(pM != NULL);
preparePROCID(pM, bLockMutex);
@@ -1520,7 +1575,7 @@ static inline int getPROCIDLen(msg_t *pM, bool bLockMutex)
/* rgerhards, 2005-11-24
*/
-char *getPROCID(msg_t *pM, bool bLockMutex)
+char *getPROCID(msg_t *pM, sbool bLockMutex)
{
ISOBJ_TYPE_assert(pM, msg);
preparePROCID(pM, bLockMutex);
@@ -1599,7 +1654,7 @@ void MsgSetTAG(msg_t *pMsg, uchar* pszBuf, size_t lenBuf)
* if there is a TAG and, if not, if it can emulate it.
* rgerhards, 2005-11-24
*/
-static inline void tryEmulateTAG(msg_t *pM, bool bLockMutex)
+static inline void tryEmulateTAG(msg_t *pM, sbool bLockMutex)
{
size_t lenTAG;
uchar bufTAG[CONF_TAG_MAXSIZE];
@@ -1652,12 +1707,13 @@ int getHOSTNAMELen(msg_t *pM)
if(pM == NULL)
return 0;
else
- if(pM->pszHOSTNAME == NULL)
- if(pM->pRcvFrom == NULL)
+ if(pM->pszHOSTNAME == NULL) {
+ resolveDNS(pM);
+ if(pM->rcvFrom.pRcvFrom == NULL)
return 0;
else
- return prop.GetStringLen(pM->pRcvFrom);
- else
+ return prop.GetStringLen(pM->rcvFrom.pRcvFrom);
+ } else
return pM->iLenHOSTNAME;
}
@@ -1668,12 +1724,13 @@ char *getHOSTNAME(msg_t *pM)
return "";
else
if(pM->pszHOSTNAME == NULL) {
- if(pM->pRcvFrom == NULL) {
+ resolveDNS(pM);
+ if(pM->rcvFrom.pRcvFrom == NULL) {
return "";
} else {
uchar *psz;
int len;
- prop.GetString(pM->pRcvFrom, &psz, &len);
+ prop.GetString(pM->rcvFrom.pRcvFrom, &psz, &len);
return (char*) psz;
}
} else {
@@ -1687,13 +1744,15 @@ uchar *getRcvFrom(msg_t *pM)
uchar *psz;
int len;
BEGINfunc
+
if(pM == NULL) {
psz = UCHAR_CONSTANT("");
} else {
- if(pM->pRcvFrom == NULL)
+ resolveDNS(pM);
+ if(pM->rcvFrom.pRcvFrom == NULL)
psz = UCHAR_CONSTANT("");
else
- prop.GetString(pM->pRcvFrom, &psz, &len);
+ prop.GetString(pM->rcvFrom.pRcvFrom, &psz, &len);
}
ENDfunc
return psz;
@@ -1740,7 +1799,7 @@ static inline char *getStructuredData(msg_t *pM)
/* check if we have a ProgramName, and, if not, try to aquire/emulate it.
* rgerhards, 2009-06-26
*/
-static inline void prepareProgramName(msg_t *pM, bool bLockMutex)
+static inline void prepareProgramName(msg_t *pM, sbool bLockMutex)
{
if(pM->pCSProgName == NULL) {
if(bLockMutex == LOCK_MUTEX)
@@ -1759,7 +1818,7 @@ static inline void prepareProgramName(msg_t *pM, bool bLockMutex)
/* get the length of the "programname" sz string
* rgerhards, 2005-10-19
*/
-int getProgramNameLen(msg_t *pM, bool bLockMutex)
+int getProgramNameLen(msg_t *pM, sbool bLockMutex)
{
assert(pM != NULL);
prepareProgramName(pM, bLockMutex);
@@ -1770,7 +1829,7 @@ int getProgramNameLen(msg_t *pM, bool bLockMutex)
/* get the "programname" as sz string
* rgerhards, 2005-10-19
*/
-uchar *getProgramName(msg_t *pM, bool bLockMutex)
+uchar *getProgramName(msg_t *pM, sbool bLockMutex)
{
prepareProgramName(pM, bLockMutex);
return (pM->pCSProgName == NULL) ? UCHAR_CONSTANT("") : rsCStrGetSzStrNoNULL(pM->pCSProgName);
@@ -1800,7 +1859,7 @@ static void tryEmulateAPPNAME(msg_t *pM)
* This must be called WITHOUT the message lock being held.
* rgerhards, 2009-06-26
*/
-static inline void prepareAPPNAME(msg_t *pM, bool bLockMutex)
+static inline void prepareAPPNAME(msg_t *pM, sbool bLockMutex)
{
if(pM->pCSAPPNAME == NULL) {
if(bLockMutex == LOCK_MUTEX)
@@ -1817,7 +1876,7 @@ static inline void prepareAPPNAME(msg_t *pM, bool bLockMutex)
/* rgerhards, 2005-11-24
*/
-char *getAPPNAME(msg_t *pM, bool bLockMutex)
+char *getAPPNAME(msg_t *pM, sbool bLockMutex)
{
assert(pM != NULL);
prepareAPPNAME(pM, bLockMutex);
@@ -1826,7 +1885,7 @@ char *getAPPNAME(msg_t *pM, bool bLockMutex)
/* rgerhards, 2005-11-24
*/
-static int getAPPNAMELen(msg_t *pM, bool bLockMutex)
+static int getAPPNAMELen(msg_t *pM, sbool bLockMutex)
{
assert(pM != NULL);
prepareAPPNAME(pM, bLockMutex);
@@ -1849,6 +1908,28 @@ void MsgSetInputName(msg_t *pThis, prop_t *inputName)
}
+/* Set the pfrominet socket store, so that we can obtain the peer at some
+ * later time. Note that we do not check if pRcvFrom is already set, so this
+ * function must only be called during message creation.
+ * NOTE: msgFlags is NOT set. While this is somewhat a violation of layers,
+ * it is done because it gains us some performance. So the caller must make
+ * sure the message flags are properly maintained. For all current callers,
+ * this is always the case and without extra effort required.
+ * rgerhards, 2009-11-17
+ */
+rsRetVal
+msgSetFromSockinfo(msg_t *pThis, struct sockaddr_storage *sa){
+ DEFiRet;
+ assert(pThis->rcvFrom.pRcvFrom == NULL);
+
+ CHKmalloc(pThis->rcvFrom.pfrominet = malloc(sizeof(struct sockaddr_storage)));
+ memcpy(pThis->rcvFrom.pfrominet, sa, sizeof(struct sockaddr_storage));
+
+finalize_it:
+ RETiRet;
+}
+
+
/* rgerhards 2008-09-10: set RcvFrom name in msg object. This calls AddRef()
* on the property, because this must be done in all current cases and there
* is no case expected where this may not be necessary.
@@ -1859,9 +1940,15 @@ void MsgSetRcvFrom(msg_t *pThis, prop_t *new)
assert(pThis != NULL);
prop.AddRef(new);
- if(pThis->pRcvFrom != NULL)
- prop.Destruct(&pThis->pRcvFrom);
- pThis->pRcvFrom = new;
+ if(pThis->msgFlags & NEEDS_DNSRESOL) {
+ if(pThis->rcvFrom.pfrominet != NULL)
+ free(pThis->rcvFrom.pfrominet);
+ pThis->msgFlags &= ~NEEDS_DNSRESOL;
+ } else {
+ if(pThis->rcvFrom.pRcvFrom != NULL)
+ prop.Destruct(&pThis->rcvFrom.pRcvFrom);
+ }
+ pThis->rcvFrom.pRcvFrom = new;
}
@@ -3054,7 +3141,7 @@ static rsRetVal msgConstructFinalizer(msg_t *pThis)
* rgerhards, 2008-01-14
*/
static rsRetVal
-MsgGetSeverity(obj_t *pThis, int *piSeverity)
+MsgGetSeverity(obj_t_ptr pThis, int *piSeverity)
{
ISOBJ_TYPE_assert(pThis, msg);
assert(piSeverity != NULL);
diff --git a/runtime/msg.h b/runtime/msg.h
index 9101cef7..712609f6 100644
--- a/runtime/msg.h
+++ b/runtime/msg.h
@@ -59,14 +59,8 @@ struct msg {
flowControl_t flowCtlType; /**< type of flow control we can apply, for enqueueing, needs not to be persisted because
once data has entered the queue, this property is no longer needed. */
pthread_mutex_t mut;
- bool bDoLock; /* use the mutex? */
+ sbool bDoLock; /* use the mutex? */
short iRefCount; /* reference counter (0 = unused) */
- /* background: the hostname is not present on "regular" messages
- * received via UNIX domain sockets from the same machine. However,
- * it is available when we have a forwarder (e.g. rfc3195d) using local
- * sockets. All in all, the parser would need parse templates, that would
- * resolve all these issues... rgerhards, 2005-10-06
- */
short iSeverity; /* the severity 0..7 */
short iFacility; /* Facility code 0 .. 23*/
short offAfterPRI; /* offset, at which raw message WITHOUT PRI part starts in pszRawMsg */
@@ -94,8 +88,12 @@ struct msg {
cstr_t *pCSPROCID; /* PROCID */
cstr_t *pCSMSGID; /* MSGID */
prop_t *pInputName; /* input name property */
- prop_t *pRcvFrom; /* name of system message was received from */
prop_t *pRcvFromIP; /* IP of system message was received from */
+ union {
+ prop_t *pRcvFrom;/* name of system message was received from */
+ struct sockaddr_storage *pfrominet; /* unresolved name */
+ } rcvFrom;
+
ruleset_t *pRuleset; /* ruleset to be used for processing this message */
time_t ttGenTime; /* time msg object was generated, same as tRcvdAt, but a Unix timestamp.
While this field looks redundant, it is required because a Unix timestamp
@@ -129,6 +127,9 @@ struct msg {
#define MARK 0x008 /* this message is a mark */
#define NEEDS_PARSING 0x010 /* raw message, must be parsed before processing can be done */
#define PARSE_HOSTNAME 0x020 /* parse the hostname during message parsing */
+#define NEEDS_DNSRESOL 0x040 /* fromhost address is unresolved and must be locked up via DNS reverse lookup first */
+#define NEEDS_ACLCHK_U 0x080 /* check UDP ACLs after DNS resolution has been done in main queue consumer */
+#define NO_PRI_IN_RAW 0x100 /* rawmsg does not include a PRI (Solaris!), but PRI is already set correctly in the msg object */
/* function prototypes
@@ -148,6 +149,7 @@ void MsgSetTAG(msg_t *pMsg, uchar* pszBuf, size_t lenBuf);
void MsgSetRuleset(msg_t *pMsg, ruleset_t*);
rsRetVal MsgSetFlowControlType(msg_t *pMsg, flowControl_t eFlowCtl);
rsRetVal MsgSetStructuredData(msg_t *pMsg, char* pszStrucData);
+rsRetVal msgSetFromSockinfo(msg_t *pThis, struct sockaddr_storage *sa);
void MsgSetRcvFrom(msg_t *pMsg, prop_t*);
void MsgSetRcvFromStr(msg_t *pMsg, uchar* pszRcvFrom, int, prop_t **);
rsRetVal MsgSetRcvFromIP(msg_t *pMsg, prop_t*);
@@ -169,14 +171,14 @@ uchar *getRcvFrom(msg_t *pM);
/* TODO: remove these five (so far used in action.c) */
uchar *getMSG(msg_t *pM);
char *getHOSTNAME(msg_t *pM);
-char *getPROCID(msg_t *pM, bool bLockMutex);
-char *getAPPNAME(msg_t *pM, bool bLockMutex);
+char *getPROCID(msg_t *pM, sbool bLockMutex);
+char *getAPPNAME(msg_t *pM, sbool bLockMutex);
int getMSGLen(msg_t *pM);
char *getHOSTNAME(msg_t *pM);
int getHOSTNAMELen(msg_t *pM);
-uchar *getProgramName(msg_t *pM, bool bLockMutex);
-int getProgramNameLen(msg_t *pM, bool bLockMutex);
+uchar *getProgramName(msg_t *pM, sbool bLockMutex);
+int getProgramNameLen(msg_t *pM, sbool bLockMutex);
uchar *getRcvFrom(msg_t *pM);
rsRetVal propNameToID(cstr_t *pCSPropName, propid_t *pPropID);
uchar *propIDToName(propid_t propID);
diff --git a/runtime/net.c b/runtime/net.c
index 85c5cc11..7653ea1d 100644
--- a/runtime/net.c
+++ b/runtime/net.c
@@ -502,8 +502,8 @@ static inline void MaskIP4 (struct in_addr *addr, uint8_t bits) {
addr->s_addr &= htonl(0xffffffff << (32 - bits));
}
-#define SIN(sa) ((struct sockaddr_in *)(sa))
-#define SIN6(sa) ((struct sockaddr_in6 *)(sa))
+#define SIN(sa) ((struct sockaddr_in *)(void*)(sa))
+#define SIN6(sa) ((struct sockaddr_in6 *)(void*)(sa))
/* This is a cancel-safe getnameinfo() version, because we learned
@@ -892,15 +892,18 @@ rsRetVal addAllowedSenderLine(char* pName, uchar** ppRestOfConfLine)
* including IPv4/v6 as well as domain name wildcards.
* This is a helper to isAllowedSender. As it is only called once, it is
* declared inline.
- * Returns 0 if they do not match, something else otherwise.
- * contributed 1007-07-16 by mildew@gmail.com
+ * Returns 0 if they do not match, 1 if they match and 2 if a DNS name would have been required.
+ * contributed 2007-07-16 by mildew@gmail.com
*/
-static inline int MaskCmp(struct NetAddr *pAllow, uint8_t bits, struct sockaddr *pFrom, const char *pszFromHost)
+static inline int
+MaskCmp(struct NetAddr *pAllow, uint8_t bits, struct sockaddr *pFrom, const char *pszFromHost, int bChkDNS)
{
assert(pAllow != NULL);
assert(pFrom != NULL);
if(F_ISSET(pAllow->flags, ADDR_NAME)) {
+ if(bChkDNS == 0)
+ return 2;
dbgprintf("MaskCmp: host=\"%s\"; pattern=\"%s\"\n", pszFromHost, pAllow->addr.HostWildcard);
# if !defined(FNM_CASEFOLD)
@@ -967,18 +970,22 @@ static inline int MaskCmp(struct NetAddr *pAllow, uint8_t bits, struct sockaddr
/* check if a sender is allowed. The root of the the allowed sender.
* list must be proveded by the caller. As such, this function can be
* used to check both UDP and TCP allowed sender lists.
- * returns 1, if the sender is allowed, 0 otherwise.
+ * returns 1, if the sender is allowed, 0 if not and 2 if we could not
+ * obtain a result because we would need a dns name, which we don't have
+ * (2 was added rgerhards, 2009-11-16).
* rgerhards, 2005-09-26
*/
-static int isAllowedSender(uchar *pszType, struct sockaddr *pFrom, const char *pszFromHost)
+static int isAllowedSender2(uchar *pszType, struct sockaddr *pFrom, const char *pszFromHost, int bChkDNS)
{
struct AllowedSenders *pAllow;
struct AllowedSenders *pAllowRoot;
+ int bNeededDNS = 0; /* partial check because we could not resolve DNS? */
+ int ret;
assert(pFrom != NULL);
if(setAllowRoot(&pAllowRoot, pszType) != RS_RET_OK)
- return 0; /* if something went wrong, we denie access - that's the better choice... */
+ return 0; /* if something went wrong, we deny access - that's the better choice... */
if(pAllowRoot == NULL)
return 1; /* checking disabled, everything is valid! */
@@ -990,10 +997,20 @@ static int isAllowedSender(uchar *pszType, struct sockaddr *pFrom, const char *p
* that the sender is disallowed.
*/
for(pAllow = pAllowRoot ; pAllow != NULL ; pAllow = pAllow->pNext) {
- if (MaskCmp (&(pAllow->allowedSender), pAllow->SignificantBits, pFrom, pszFromHost))
+ ret = MaskCmp (&(pAllow->allowedSender), pAllow->SignificantBits, pFrom, pszFromHost, bChkDNS);
+ if(ret == 1)
return 1;
+ else if(ret == 2)
+ bNeededDNS = 2;
}
- return 0;
+ return bNeededDNS;
+}
+
+
+/* legacy API, not to be used any longer */
+static int
+isAllowedSender(uchar *pszType, struct sockaddr *pFrom, const char *pszFromHost) {
+ return isAllowedSender2(pszType, pFrom, pszFromHost, 1);
}
@@ -1165,12 +1182,12 @@ void debugListenInfo(int fd, char *type)
switch(sa.sa_family) {
case PF_INET:
szFamily = "IPv4";
- ipv4 = (struct sockaddr_in*) &sa;
+ ipv4 = (struct sockaddr_in*)(void*) &sa;
port = ntohs(ipv4->sin_port);
break;
case PF_INET6:
szFamily = "IPv6";
- ipv6 = (struct sockaddr_in6*) &sa;
+ ipv6 = (struct sockaddr_in6*)(void*) &sa;
port = ntohs(ipv6->sin6_port);
break;
default:
@@ -1533,12 +1550,36 @@ static int CmpHost(struct sockaddr_storage *s1, struct sockaddr_storage* s2, siz
ret = memcmp(s1, s2, socklen);
}
-dbgprintf("CmpHost returns %d\n", ret);
finalize_it:
return ret;
}
+
+/* check if restrictions (ALCs) exists. The goal of this function is to disable the
+ * somewhat time-consuming ACL checks if no restrictions are defined (the usual case).
+ * This also permits to gain some speedup by using firewall-based ACLs instead of
+ * rsyslog ACLs (the recommended method.
+ * rgerhards, 2009-11-16
+ */
+static rsRetVal
+HasRestrictions(uchar *pszType, int *bHasRestrictions) {
+ struct AllowedSenders *pAllowRoot;
+ DEFiRet;
+
+ CHKiRet(setAllowRoot(&pAllowRoot, pszType));
+
+ *bHasRestrictions = (pAllowRoot == NULL) ? 0 : 1;
+
+finalize_it:
+ if(iRet != RS_RET_OK) {
+ *bHasRestrictions = 1; /* in this case it is better to check individually */
+ DBGPRINTF("Error %d trying to obtain ACL restriction state of '%s'\n", iRet, pszType);
+ }
+ RETiRet;
+}
+
+
/* queryInterface function
* rgerhards, 2008-03-05
*/
@@ -1562,12 +1603,14 @@ CODESTARTobjQueryInterface(net)
pIf->create_udp_socket = create_udp_socket;
pIf->closeUDPListenSockets = closeUDPListenSockets;
pIf->isAllowedSender = isAllowedSender;
+ pIf->isAllowedSender2 = isAllowedSender2;
pIf->should_use_so_bsdcompat = should_use_so_bsdcompat;
pIf->getLocalHostname = getLocalHostname;
pIf->AddPermittedPeer = AddPermittedPeer;
pIf->DestructPermittedPeers = DestructPermittedPeers;
pIf->PermittedPeerWildcardMatch = PermittedPeerWildcardMatch;
pIf->CmpHost = CmpHost;
+ pIf->HasRestrictions = HasRestrictions;
/* data members */
pIf->pACLAddHostnameOnFail = &ACLAddHostnameOnFail;
pIf->pACLDontResolve = &ACLDontResolve;
diff --git a/runtime/net.h b/runtime/net.h
index ec364b1c..101ce79d 100644
--- a/runtime/net.h
+++ b/runtime/net.h
@@ -139,7 +139,7 @@ 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)(uchar *pszType, struct sockaddr *pFrom, const char *pszFromHost);
+ int (*isAllowedSender)(uchar *pszType, struct sockaddr *pFrom, const char *pszFromHost); /* deprecated! */
rsRetVal (*getLocalHostname)(uchar**);
int (*should_use_so_bsdcompat)(void);
/* permitted peer handling should be replaced by something better (see comments above) */
@@ -148,11 +148,14 @@ BEGINinterface(net) /* name must also be changed in ENDinterface macro! */
rsRetVal (*PermittedPeerWildcardMatch)(permittedPeers_t *pPeer, uchar *pszNameToMatch, int *pbIsMatching);
/* v5 interface additions */
int (*CmpHost)(struct sockaddr_storage *, struct sockaddr_storage*, size_t);
+ /* v6 interface additions - 2009-11-16 */
+ rsRetVal (*HasRestrictions)(uchar *, int *bHasRestrictions);
+ int (*isAllowedSender2)(uchar *pszType, struct sockaddr *pFrom, const char *pszFromHost, int bChkDNS);
/* data members - 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) */
ENDinterface(net)
-#define netCURR_IF_VERSION 5 /* increment whenever you change the interface structure! */
+#define netCURR_IF_VERSION 6 /* increment whenever you change the interface structure! */
/* prototypes */
PROTOTYPEObj(net);
diff --git a/runtime/netstrms.c b/runtime/netstrms.c
index 6b28e7ea..e9ff2568 100644
--- a/runtime/netstrms.c
+++ b/runtime/netstrms.c
@@ -36,6 +36,7 @@
#include "nsd.h"
#include "netstrm.h"
#include "nssel.h"
+#include "nspoll.h"
#include "netstrms.h"
MODULE_TYPE_LIB
@@ -304,6 +305,7 @@ ENDObjClassInit(netstrms)
BEGINmodExit
CODESTARTmodExit
nsselClassExit();
+ nspollClassExit();
netstrmsClassExit();
netstrmClassExit(); /* we use this object, so we must exit it after we are finished */
ENDmodExit
@@ -322,6 +324,7 @@ CODESTARTmodInit
/* Initialize all classes that are in our module - this includes ourselfs */
CHKiRet(netstrmClassInit(pModInfo));
CHKiRet(nsselClassInit(pModInfo));
+ CHKiRet(nspollClassInit(pModInfo));
CHKiRet(netstrmsClassInit(pModInfo));
ENDmodInit
/* vi:set ai:
diff --git a/runtime/nsd.h b/runtime/nsd.h
index 8668c934..e5b9320b 100644
--- a/runtime/nsd.h
+++ b/runtime/nsd.h
@@ -87,4 +87,13 @@ BEGINinterface(nsdsel) /* name must also be changed in ENDinterface macro! */
ENDinterface(nsdsel)
#define nsdselCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */
+/* interface for the epoll call */
+BEGINinterface(nsdpoll) /* name must also be changed in ENDinterface macro! */
+ rsRetVal (*Construct)(nsdpoll_t **ppThis);
+ rsRetVal (*Destruct)(nsdpoll_t **ppThis);
+ rsRetVal (*Ctl)(nsdpoll_t *pNsdpoll, nsd_t *pNsd, int id, void *pUsr, int mode, int op);
+ rsRetVal (*Wait)(nsdpoll_t *pNsdpoll, int timeout, int *idRdy, void **ppUsr);
+ENDinterface(nsdpoll)
+#define nsdpollCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */
+
#endif /* #ifndef INCLUDED_NSD_H */
diff --git a/runtime/nsd_ptcp.c b/runtime/nsd_ptcp.c
index fe31ab40..ca00749c 100644
--- a/runtime/nsd_ptcp.c
+++ b/runtime/nsd_ptcp.c
@@ -48,6 +48,7 @@
#include "netstrms.h"
#include "netstrm.h"
#include "nsdsel_ptcp.h"
+#include "nsdpoll_ptcp.h"
#include "nsd_ptcp.h"
MODULE_TYPE_LIB
@@ -562,6 +563,7 @@ finalize_it:
static rsRetVal
Rcv(nsd_t *pNsd, uchar *pRcvBuf, ssize_t *pLenBuf)
{
+ char errStr[1024];
DEFiRet;
nsd_ptcp_t *pThis = (nsd_ptcp_t*) pNsd;
ISOBJ_TYPE_assert(pThis, nsd_ptcp);
@@ -571,7 +573,9 @@ Rcv(nsd_t *pNsd, uchar *pRcvBuf, ssize_t *pLenBuf)
if(*pLenBuf == 0) {
ABORT_FINALIZE(RS_RET_CLOSED);
} else if (*pLenBuf < 0) {
- ABORT_FINALIZE(RS_RET_ERR);
+ rs_strerror_r(errno, errStr, sizeof(errStr));
+ dbgprintf("error during recv on NSD %p: %s\n", pNsd, errStr);
+ ABORT_FINALIZE(RS_RET_RCV_ERR);
}
finalize_it:
@@ -821,6 +825,9 @@ ENDObjClassInit(nsd_ptcp)
BEGINmodExit
CODESTARTmodExit
+# ifdef HAVE_EPOLL_CREATE /* module only available if epoll() is supported! */
+ nsdpoll_ptcpClassExit();
+# endif
nsdsel_ptcpClassExit();
nsd_ptcpClassExit();
ENDmodExit
@@ -839,6 +846,9 @@ CODESTARTmodInit
/* Initialize all classes that are in our module - this includes ourselfs */
CHKiRet(nsd_ptcpClassInit(pModInfo)); /* must be done after tcps_sess, as we use it */
CHKiRet(nsdsel_ptcpClassInit(pModInfo)); /* must be done after tcps_sess, as we use it */
+# ifdef HAVE_EPOLL_CREATE /* module only available if epoll() is supported! */
+ CHKiRet(nsdpoll_ptcpClassInit(pModInfo)); /* must be done after tcps_sess, as we use it */
+# endif
ENDmodInit
/* vi:set ai:
*/
diff --git a/runtime/nsdpoll_ptcp.c b/runtime/nsdpoll_ptcp.c
new file mode 100644
index 00000000..51006707
--- /dev/null
+++ b/runtime/nsdpoll_ptcp.c
@@ -0,0 +1,288 @@
+/* nsdpoll_ptcp.c
+ *
+ * An implementation of the nsd epoll() interface for plain tcp sockets.
+ *
+ * Copyright 2009 Rainer Gerhards and Adiscon GmbH.
+ *
+ * This file is part of the rsyslog runtime library.
+ *
+ * The rsyslog runtime library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The rsyslog runtime library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the rsyslog runtime library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * A copy of the GPL can be found in the file "COPYING" in this distribution.
+ * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution.
+ */
+#include "config.h"
+
+#ifdef HAVE_EPOLL_CREATE /* this module requires epoll! */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#if HAVE_SYS_EPOLL_H
+# include <sys/epoll.h>
+#endif
+
+#include "rsyslog.h"
+#include "module-template.h"
+#include "obj.h"
+#include "errmsg.h"
+#include "srUtils.h"
+#include "nspoll.h"
+#include "nsd_ptcp.h"
+#include "nsdpoll_ptcp.h"
+#include "unlimited_select.h"
+
+/* static data */
+DEFobjStaticHelpers
+DEFobjCurrIf(errmsg)
+DEFobjCurrIf(glbl)
+
+
+/* -START------------------------- helpers for event list ------------------------------------ */
+
+/* add new entry to list. We assume that the fd is not already present and DO NOT check this!
+ * Returns newly created entry in pEvtLst.
+ * Note that we currently need to use level-triggered mode, because the upper layers do not work
+ * in parallel. As such, in edge-triggered mode we may not get notified, because new data comes
+ * in after we have read everything that was present. To use ET mode, we need to change the upper
+ * peers so that they immediately start a new wait before processing the data read. That obviously
+ * requires more elaborate redesign and we postpone this until the current more simplictic mode has
+ * been proven OK in practice.
+ * rgerhards, 2009-11-18
+ */
+static inline rsRetVal
+addEvent(nsdpoll_ptcp_t *pThis, int id, void *pUsr, int mode, nsd_ptcp_t *pSock, nsdpoll_epollevt_lst_t **pEvtLst) {
+ nsdpoll_epollevt_lst_t *pNew;
+ DEFiRet;
+
+ CHKmalloc(pNew = (nsdpoll_epollevt_lst_t*) malloc(sizeof(nsdpoll_epollevt_lst_t)));
+ pNew->id = id;
+ pNew->pUsr = pUsr;
+ pNew->pSock = pSock;
+ pNew->event.events = 0; /* TODO: at some time we should be able to use EPOLLET */
+ if(mode & NSDPOLL_IN)
+ pNew->event.events |= EPOLLIN;
+ if(mode & NSDPOLL_OUT)
+ pNew->event.events |= EPOLLOUT;
+ pNew->event.data.u64 = (uint64) pNew;
+ pNew->pNext = pThis->pRoot;
+ pThis->pRoot = pNew;
+ *pEvtLst = pNew;
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* find and unlink the entry identified by id/pUsr from the list.
+ * rgerhards, 2009-11-23
+ */
+static inline rsRetVal
+unlinkEvent(nsdpoll_ptcp_t *pThis, int id, void *pUsr, nsdpoll_epollevt_lst_t **ppEvtLst) {
+ nsdpoll_epollevt_lst_t *pEvtLst;
+ nsdpoll_epollevt_lst_t *pPrev = NULL;
+ DEFiRet;
+
+ pEvtLst = pThis->pRoot;
+ while(pEvtLst != NULL && !(pEvtLst->id == id && pEvtLst->pUsr == pUsr)) {
+ pPrev = pEvtLst;
+ pEvtLst = pEvtLst->pNext;
+ }
+ if(pEvtLst == NULL)
+ ABORT_FINALIZE(RS_RET_NOT_FOUND);
+
+ *ppEvtLst = pEvtLst;
+
+ /* unlink */
+ if(pPrev == NULL)
+ pThis->pRoot = pEvtLst->pNext;
+ else
+ pPrev->pNext = pEvtLst->pNext;
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* destruct the provided element. It must already be unlinked from the list.
+ * rgerhards, 2009-11-23
+ */
+static inline rsRetVal
+delEvent(nsdpoll_epollevt_lst_t **ppEvtLst) {
+ DEFiRet;
+ free(*ppEvtLst);
+ *ppEvtLst = NULL;
+ RETiRet;
+}
+
+
+/* -END--------------------------- helpers for event list ------------------------------------ */
+
+
+/* Standard-Constructor
+ */
+BEGINobjConstruct(nsdpoll_ptcp) /* be sure to specify the object type also in END macro! */
+# if defined(EPOLL_CLOEXEC) && defined(HAVE_EPOLL_CREATE1)
+ DBGPRINTF("nsdpoll_ptcp uses epoll_create1()\n");
+ pThis->efd = epoll_create1(EPOLL_CLOEXEC);
+# else
+ DBGPRINTF("nsdpoll_ptcp uses epoll_create()\n");
+ pThis->efd = epoll_create(100); /* size is ignored in newer kernels, but 100 is not bad... */
+# endif
+ if(pThis->efd < 0) {
+ DBGPRINTF("epoll_create1() could not create fd\n");
+ ABORT_FINALIZE(RS_RET_IO_ERROR);
+ }
+finalize_it:
+ENDobjConstruct(nsdpoll_ptcp)
+
+
+/* destructor for the nsdpoll_ptcp object */
+BEGINobjDestruct(nsdpoll_ptcp) /* be sure to specify the object type also in END and CODESTART macros! */
+CODESTARTobjDestruct(nsdpoll_ptcp)
+ENDobjDestruct(nsdpoll_ptcp)
+
+
+/* Modify socket set */
+static rsRetVal
+Ctl(nsdpoll_t *pNsdpoll, nsd_t *pNsd, int id, void *pUsr, int mode, int op) {
+ nsdpoll_ptcp_t *pThis = (nsdpoll_ptcp_t*) pNsdpoll;
+ nsd_ptcp_t *pSock = (nsd_ptcp_t*) pNsd;
+ nsdpoll_epollevt_lst_t *pEventLst;
+ int errSave;
+ char errStr[512];
+ DEFiRet;
+
+ if(op == NSDPOLL_ADD) {
+ dbgprintf("adding nsdpoll entry %d/%p, sock %d\n", id, pUsr, pSock->sock);
+ CHKiRet(addEvent(pThis, id, pUsr, mode, pSock, &pEventLst));
+ if(epoll_ctl(pThis->efd, EPOLL_CTL_ADD, pSock->sock, &pEventLst->event) < 0) {
+ errSave = errno;
+ rs_strerror_r(errSave, errStr, sizeof(errStr));
+ errmsg.LogError(errSave, RS_RET_ERR_EPOLL_CTL,
+ "epoll_ctl failed on fd %d, id %d/%p, op %d with %s\n",
+ pSock->sock, id, pUsr, mode, errStr);
+ }
+ } else if(op == NSDPOLL_DEL) {
+ dbgprintf("removing nsdpoll entry %d/%p, sock %d\n", id, pUsr, pSock->sock);
+ CHKiRet(unlinkEvent(pThis, id, pUsr, &pEventLst));
+ if(epoll_ctl(pThis->efd, EPOLL_CTL_DEL, pSock->sock, &pEventLst->event) < 0) {
+ errSave = errno;
+ rs_strerror_r(errSave, errStr, sizeof(errStr));
+ errmsg.LogError(errSave, RS_RET_ERR_EPOLL_CTL,
+ "epoll_ctl failed on fd %d, id %d/%p, op %d with %s\n",
+ pSock->sock, id, pUsr, mode, errStr);
+ ABORT_FINALIZE(RS_RET_ERR_EPOLL_CTL);
+ }
+ CHKiRet(delEvent(&pEventLst));
+ } else {
+ dbgprintf("program error: invalid NSDPOLL_mode %d - ignoring request\n", op);
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* Wait for io to become ready. After the successful call, idRdy contains the
+ * id set by the caller for that i/o event, ppUsr is a pointer to a location
+ * where the user pointer shall be stored.
+ * TODO: this is a trivial implementation that only polls one event at a time. We
+ * may later extend it to poll for multiple events, what would cause less
+ * overhead.
+ * rgerhards, 2009-11-18
+ */
+static rsRetVal
+Wait(nsdpoll_t *pNsdpoll, int timeout, int *idRdy, void **ppUsr) {
+ nsdpoll_ptcp_t *pThis = (nsdpoll_ptcp_t*) pNsdpoll;
+ nsdpoll_epollevt_lst_t *pOurEvt;
+ struct epoll_event event;
+ int nfds;
+ DEFiRet;
+
+ assert(idRdy != NULL);
+ assert(ppUsr != NULL);
+
+ nfds = epoll_wait(pThis->efd, &event, 1, timeout);
+ if(nfds == -1) {
+ if(errno == EINTR) {
+ ABORT_FINALIZE(RS_RET_EINTR);
+ } else {
+ DBGPRINTF("epoll() returned with error code %d\n", errno);
+ ABORT_FINALIZE(RS_RET_ERR_EPOLL);
+ }
+ } else if(nfds == 0) {
+ ABORT_FINALIZE(RS_RET_TIMEOUT);
+ }
+
+ /* we got a valid event, so tell the caller... */
+ pOurEvt = (nsdpoll_epollevt_lst_t*) event.data.u64;
+ *idRdy = pOurEvt->id;
+ *ppUsr = pOurEvt->pUsr;
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* ------------------------------ end support for the epoll() interface ------------------------------ */
+
+
+/* queryInterface function */
+BEGINobjQueryInterface(nsdpoll_ptcp)
+CODESTARTobjQueryInterface(nsdpoll_ptcp)
+ if(pIf->ifVersion != nsdCURR_IF_VERSION) {/* check for current version, increment on each change */
+ ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED);
+ }
+
+ /* ok, we have the right interface, so let's fill it
+ * Please note that we may also do some backwards-compatibility
+ * work here (if we can support an older interface version - that,
+ * of course, also affects the "if" above).
+ */
+ pIf->Construct = (rsRetVal(*)(nsdpoll_t**)) nsdpoll_ptcpConstruct;
+ pIf->Destruct = (rsRetVal(*)(nsdpoll_t**)) nsdpoll_ptcpDestruct;
+ pIf->Ctl = Ctl;
+ pIf->Wait = Wait;
+finalize_it:
+ENDobjQueryInterface(nsdpoll_ptcp)
+
+
+/* exit our class
+ */
+BEGINObjClassExit(nsdpoll_ptcp, OBJ_IS_CORE_MODULE) /* CHANGE class also in END MACRO! */
+CODESTARTObjClassExit(nsdpoll_ptcp)
+ /* release objects we no longer need */
+ objRelease(glbl, CORE_COMPONENT);
+ objRelease(errmsg, CORE_COMPONENT);
+ENDObjClassExit(nsdpoll_ptcp)
+
+
+/* Initialize the nsdpoll_ptcp class. Must be called as the very first method
+ * before anything else is called inside this class.
+ * rgerhards, 2008-02-19
+ */
+BEGINObjClassInit(nsdpoll_ptcp, 1, OBJ_IS_CORE_MODULE) /* class, version */
+ /* request objects we use */
+ CHKiRet(objUse(errmsg, CORE_COMPONENT));
+ CHKiRet(objUse(glbl, CORE_COMPONENT));
+
+ /* set our own handlers */
+ENDObjClassInit(nsdpoll_ptcp)
+#endif /* #ifdef HAVE_EPOLL_CREATE this module requires epoll! */
+
+/* vi:set ai:
+ */
diff --git a/runtime/nsdpoll_ptcp.h b/runtime/nsdpoll_ptcp.h
new file mode 100644
index 00000000..cea2823d
--- /dev/null
+++ b/runtime/nsdpoll_ptcp.h
@@ -0,0 +1,60 @@
+/* An implementation of the nsd poll interface for plain tcp sockets.
+ *
+ * Copyright 2009 Rainer Gerhards and Adiscon GmbH.
+ *
+ * This file is part of the rsyslog runtime library.
+ *
+ * The rsyslog runtime library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The rsyslog runtime library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the rsyslog runtime library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * A copy of the GPL can be found in the file "COPYING" in this distribution.
+ * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution.
+ */
+
+#ifndef INCLUDED_NSDPOLL_PTCP_H
+#define INCLUDED_NSDPOLL_PTCP_H
+
+#include "nsd.h"
+#if HAVE_SYS_EPOLL_H
+# include <sys/epoll.h>
+#endif
+typedef nsdpoll_if_t nsdpoll_ptcp_if_t; /* we just *implement* this interface */
+/* a helper object to keep track of the epoll event records
+ * Note that we need to keep track of that list because we need to
+ * free the events when they are no longer needed.
+ */
+typedef struct nsdpoll_epollevt_lst_s nsdpoll_epollevt_lst_t;
+struct nsdpoll_epollevt_lst_s {
+#if HAVE_SYS_EPOLL_H
+ epoll_event_t event;
+#endif
+ int id;
+ void *pUsr;
+ nsd_ptcp_t *pSock; /* our associated netstream driver data */
+ nsdpoll_epollevt_lst_t *pNext;
+};
+
+/* the nsdpoll_ptcp object */
+struct nsdpoll_ptcp_s {
+ BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */
+ int efd; /* file descriptor used by epoll */
+ nsdpoll_epollevt_lst_t *pRoot; /* Root of the epoll event list */
+};
+
+/* interface is defined in nsd.h, we just implement it! */
+#define nsdpoll_ptcpCURR_IF_VERSION nsdCURR_IF_VERSION
+
+/* prototypes */
+PROTOTYPEObj(nsdpoll_ptcp);
+
+#endif /* #ifndef INCLUDED_NSDPOLL_PTCP_H */
diff --git a/runtime/nsdsel_ptcp.c b/runtime/nsdsel_ptcp.c
index 41b85e0c..e2cfca7c 100644
--- a/runtime/nsdsel_ptcp.c
+++ b/runtime/nsdsel_ptcp.c
@@ -36,6 +36,7 @@
#include "errmsg.h"
#include "nsd_ptcp.h"
#include "nsdsel_ptcp.h"
+#include "unlimited_select.h"
/* static data */
DEFobjStaticHelpers
@@ -47,14 +48,23 @@ DEFobjCurrIf(glbl)
*/
BEGINobjConstruct(nsdsel_ptcp) /* be sure to specify the object type also in END macro! */
pThis->maxfds = 0;
+#ifdef USE_UNLIMITED_SELECT
+ pThis->pReadfds = calloc(1, glbl.GetFdSetSize());
+ pThis->pWritefds = calloc(1, glbl.GetFdSetSize());
+#else
FD_ZERO(&pThis->readfds);
FD_ZERO(&pThis->writefds);
+#endif
ENDobjConstruct(nsdsel_ptcp)
/* destructor for the nsdsel_ptcp object */
BEGINobjDestruct(nsdsel_ptcp) /* be sure to specify the object type also in END and CODESTART macros! */
CODESTARTobjDestruct(nsdsel_ptcp)
+#ifdef USE_UNLIMITED_SELECT
+ freeFdSet(pThis->pReadfds);
+ freeFdSet(pThis->pWritefds);
+#endif
ENDobjDestruct(nsdsel_ptcp)
@@ -65,20 +75,27 @@ Add(nsdsel_t *pNsdsel, nsd_t *pNsd, nsdsel_waitOp_t waitOp)
DEFiRet;
nsdsel_ptcp_t *pThis = (nsdsel_ptcp_t*) pNsdsel;
nsd_ptcp_t *pSock = (nsd_ptcp_t*) pNsd;
+#ifdef USE_UNLIMITED_SELECT
+ fd_set *pReadfds = pThis->pReadfds;
+ fd_set *pWritefds = pThis->pWritefds;
+#else
+ fd_set *pReadfds = &pThis->readfds;
+ fd_set *pWritefds = &pThis->writefds;
+#endif
ISOBJ_TYPE_assert(pSock, nsd_ptcp);
ISOBJ_TYPE_assert(pThis, nsdsel_ptcp);
switch(waitOp) {
case NSDSEL_RD:
- FD_SET(pSock->sock, &pThis->readfds);
+ FD_SET(pSock->sock, pReadfds);
break;
case NSDSEL_WR:
- FD_SET(pSock->sock, &pThis->writefds);
+ FD_SET(pSock->sock, pWritefds);
break;
case NSDSEL_RDWR:
- FD_SET(pSock->sock, &pThis->readfds);
- FD_SET(pSock->sock, &pThis->writefds);
+ FD_SET(pSock->sock, pReadfds);
+ FD_SET(pSock->sock, pWritefds);
break;
}
@@ -98,6 +115,13 @@ Select(nsdsel_t *pNsdsel, int *piNumReady)
DEFiRet;
int i;
nsdsel_ptcp_t *pThis = (nsdsel_ptcp_t*) pNsdsel;
+#ifdef USE_UNLIMITED_SELECT
+ fd_set *pReadfds = pThis->pReadfds;
+ fd_set *pWritefds = pThis->pWritefds;
+#else
+ fd_set *pReadfds = &pThis->readfds;
+ fd_set *pWritefds = &pThis->writefds;
+#endif
ISOBJ_TYPE_assert(pThis, nsdsel_ptcp);
assert(piNumReady != NULL);
@@ -106,13 +130,13 @@ Select(nsdsel_t *pNsdsel, int *piNumReady)
// TODO: name in dbgprintf!
dbgprintf("--------<NSDSEL_PTCP> calling select, active fds (max %d): ", pThis->maxfds);
for(i = 0; i <= pThis->maxfds; ++i)
- if(FD_ISSET(i, &pThis->readfds) || FD_ISSET(i, &pThis->writefds))
+ if(FD_ISSET(i, pReadfds) || FD_ISSET(i, pWritefds))
dbgprintf("%d ", i);
dbgprintf("\n");
}
/* now do the select */
- *piNumReady = select(pThis->maxfds+1, &pThis->readfds, &pThis->writefds, NULL, NULL);
+ *piNumReady = select(pThis->maxfds+1, pReadfds, pWritefds, NULL, NULL);
RETiRet;
}
@@ -125,6 +149,13 @@ IsReady(nsdsel_t *pNsdsel, nsd_t *pNsd, nsdsel_waitOp_t waitOp, int *pbIsReady)
DEFiRet;
nsdsel_ptcp_t *pThis = (nsdsel_ptcp_t*) pNsdsel;
nsd_ptcp_t *pSock = (nsd_ptcp_t*) pNsd;
+#ifdef USE_UNLIMITED_SELECT
+ fd_set *pReadfds = pThis->pReadfds;
+ fd_set *pWritefds = pThis->pWritefds;
+#else
+ fd_set *pReadfds = &pThis->readfds;
+ fd_set *pWritefds = &pThis->writefds;
+#endif
ISOBJ_TYPE_assert(pThis, nsdsel_ptcp);
ISOBJ_TYPE_assert(pSock, nsd_ptcp);
@@ -132,14 +163,14 @@ IsReady(nsdsel_t *pNsdsel, nsd_t *pNsd, nsdsel_waitOp_t waitOp, int *pbIsReady)
switch(waitOp) {
case NSDSEL_RD:
- *pbIsReady = FD_ISSET(pSock->sock, &pThis->readfds);
+ *pbIsReady = FD_ISSET(pSock->sock, pReadfds);
break;
case NSDSEL_WR:
- *pbIsReady = FD_ISSET(pSock->sock, &pThis->writefds);
+ *pbIsReady = FD_ISSET(pSock->sock, pWritefds);
break;
case NSDSEL_RDWR:
- *pbIsReady = FD_ISSET(pSock->sock, &pThis->readfds)
- | FD_ISSET(pSock->sock, &pThis->writefds);
+ *pbIsReady = FD_ISSET(pSock->sock, pReadfds)
+ | FD_ISSET(pSock->sock, pWritefds);
break;
}
diff --git a/runtime/nsdsel_ptcp.h b/runtime/nsdsel_ptcp.h
index 6c0c7fa7..f9ec8210 100644
--- a/runtime/nsdsel_ptcp.h
+++ b/runtime/nsdsel_ptcp.h
@@ -31,8 +31,13 @@ typedef nsdsel_if_t nsdsel_ptcp_if_t; /* we just *implement* this interface */
struct nsdsel_ptcp_s {
BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */
int maxfds;
+#ifdef USE_UNLIMITED_SELECT
+ fd_set *pReadfds;
+ fd_set *pWritefds;
+#else
fd_set readfds;
fd_set writefds;
+#endif
};
/* interface is defined in nsd.h, we just implement it! */
diff --git a/runtime/nspoll.c b/runtime/nspoll.c
new file mode 100644
index 00000000..f287cd4e
--- /dev/null
+++ b/runtime/nspoll.c
@@ -0,0 +1,198 @@
+/* nspoll.c
+ *
+ * This is an io waiter interface utilizing the much-more-efficient poll/epoll API.
+ * Note that it may not always be available for a given driver. If so, that is reported
+ * back to the upper peer which then should consult a nssel-based io waiter.
+ *
+ * Work on this module begun 2009-11-18 by Rainer Gerhards.
+ *
+ * Copyright 2009 Rainer Gerhards and Adiscon GmbH.
+ *
+ * This file is part of the rsyslog runtime library.
+ *
+ * The rsyslog runtime library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The rsyslog runtime library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the rsyslog runtime library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * A copy of the GPL can be found in the file "COPYING" in this distribution.
+ * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution.
+ */
+#include "config.h"
+
+#include "rsyslog.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include "rsyslog.h"
+#include "obj.h"
+#include "module-template.h"
+#include "netstrm.h"
+#include "nspoll.h"
+
+/* static data */
+DEFobjStaticHelpers
+DEFobjCurrIf(glbl)
+
+
+/* load our low-level driver. This must be done before any
+ * driver-specific functions (allmost all...) can be carried
+ * out. Note that the driver's .ifIsLoaded is correctly
+ * initialized by calloc() and we depend on that. Please note that
+ * we do some name-mangeling. We know that each nsd driver also needs
+ * a nspoll driver. So we simply append "sel" to the nsd driver name: This,
+ * of course, means that the driver name must match these rules, but that
+ * shouldn't be a real problem.
+ * WARNING: this code is mostly identical to similar code in
+ * netstrms.c - TODO: abstract it and move it to some common place.
+ * rgerhards, 2008-04-28
+ */
+static rsRetVal
+loadDrvr(nspoll_t *pThis)
+{
+ DEFiRet;
+ uchar *pBaseDrvrName;
+ uchar szDrvrName[48]; /* 48 shall be large enough */
+
+ pBaseDrvrName = pThis->pBaseDrvrName;
+ if(pBaseDrvrName == NULL) /* if no drvr name is set, use system default */
+ pBaseDrvrName = glbl.GetDfltNetstrmDrvr();
+ if(snprintf((char*)szDrvrName, sizeof(szDrvrName), "lmnsdpoll_%s", pBaseDrvrName) == sizeof(szDrvrName))
+ ABORT_FINALIZE(RS_RET_DRVRNAME_TOO_LONG);
+ CHKmalloc(pThis->pDrvrName = (uchar*) strdup((char*)szDrvrName));
+
+ pThis->Drvr.ifVersion = nsdCURR_IF_VERSION;
+ /* The pDrvrName+2 below is a hack to obtain the object name. It
+ * safes us to have yet another variable with the name without "lm" in
+ * front of it. If we change the module load interface, we may re-think
+ * about this hack, but for the time being it is efficient and clean
+ * enough. -- rgerhards, 2008-04-18
+ */
+RUNLOG_VAR("%s", szDrvrName+2);
+ CHKiRet(obj.UseObj(__FILE__, szDrvrName+2, DONT_LOAD_LIB, (void*) &pThis->Drvr));
+
+finalize_it:
+ if(iRet != RS_RET_OK) {
+ if(pThis->pDrvrName != NULL)
+ free(pThis->pDrvrName);
+ pThis->pDrvrName = NULL;
+ }
+ RETiRet;
+}
+
+
+/* Standard-Constructor */
+BEGINobjConstruct(nspoll) /* be sure to specify the object type also in END macro! */
+ENDobjConstruct(nspoll)
+
+
+/* destructor for the nspoll object */
+BEGINobjDestruct(nspoll) /* be sure to specify the object type also in END and CODESTART macros! */
+CODESTARTobjDestruct(nspoll)
+ if(pThis->pDrvrData != NULL)
+ pThis->Drvr.Destruct(&pThis->pDrvrData);
+
+ /* and now we must release our driver, if we got one. We use the presence of
+ * a driver name string as load indicator (because we also need that string
+ * to release the driver
+ */
+ if(pThis->pDrvrName != NULL) {
+ obj.ReleaseObj(__FILE__, pThis->pDrvrName+2, DONT_LOAD_LIB, (void*) &pThis->Drvr);
+ free(pThis->pDrvrName);
+ }
+ENDobjDestruct(nspoll)
+
+
+/* ConstructionFinalizer */
+static rsRetVal
+ConstructFinalize(nspoll_t *pThis)
+{
+ DEFiRet;
+ ISOBJ_TYPE_assert(pThis, nspoll);
+RUNLOG_STR("trying to load epoll driver\n");
+ CHKiRet(loadDrvr(pThis));
+ CHKiRet(pThis->Drvr.Construct(&pThis->pDrvrData));
+finalize_it:
+dbgprintf("XXX: done trying to load epoll driver, state %d\n", iRet);
+ RETiRet;
+}
+
+
+/* Carries out the actual wait (all done in lower layers)
+ */
+static rsRetVal
+Wait(nspoll_t *pThis, int timeout, int *idRdy, void **ppUsr) {
+ DEFiRet;
+ ISOBJ_TYPE_assert(pThis, nspoll);
+ assert(idRdy != NULL);
+ iRet = pThis->Drvr.Wait(pThis->pDrvrData, timeout, idRdy, ppUsr);
+ RETiRet;
+}
+
+
+/* semantics like the epoll_ctl() function, does the same thing.
+ * rgerhards, 2009-11-18
+ */
+static rsRetVal
+Ctl(nspoll_t *pThis, netstrm_t *pStrm, int id, void *pUsr, int mode, int op) {
+ DEFiRet;
+ ISOBJ_TYPE_assert(pThis, nspoll);
+ iRet = pThis->Drvr.Ctl(pThis->pDrvrData, pStrm->pDrvrData, id, pUsr, mode, op);
+ RETiRet;
+}
+
+
+/* queryInterface function */
+BEGINobjQueryInterface(nspoll)
+CODESTARTobjQueryInterface(nspoll)
+ if(pIf->ifVersion != nspollCURR_IF_VERSION) {/* check for current version, increment on each change */
+ ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED);
+ }
+
+ /* ok, we have the right interface, so let's fill it
+ * Please note that we may also do some backwards-compatibility
+ * work here (if we can support an older interface version - that,
+ * of course, also affects the "if" above).
+ */
+ pIf->Construct = nspollConstruct;
+ pIf->ConstructFinalize = ConstructFinalize;
+ pIf->Destruct = nspollDestruct;
+ pIf->Wait = Wait;
+ pIf->Ctl = Ctl;
+finalize_it:
+ENDobjQueryInterface(nspoll)
+
+
+/* exit our class
+ */
+BEGINObjClassExit(nspoll, OBJ_IS_LOADABLE_MODULE) /* CHANGE class also in END MACRO! */
+CODESTARTObjClassExit(nspoll)
+ /* release objects we no longer need */
+ objRelease(glbl, CORE_COMPONENT);
+ENDObjClassExit(nspoll)
+
+
+/* Initialize the nspoll class. Must be called as the very first method
+ * before anything else is called inside this class.
+ * rgerhards, 2008-02-19
+ */
+BEGINObjClassInit(nspoll, 1, OBJ_IS_CORE_MODULE) /* class, version */
+ /* request objects we use */
+ DBGPRINTF("doing nspollClassInit\n");
+ CHKiRet(objUse(glbl, CORE_COMPONENT));
+
+ /* set our own handlers */
+ENDObjClassInit(nspoll)
+/* vi:set ai:
+ */
diff --git a/runtime/nspoll.h b/runtime/nspoll.h
new file mode 100644
index 00000000..a77759c0
--- /dev/null
+++ b/runtime/nspoll.h
@@ -0,0 +1,65 @@
+/* Definitions for the nspoll io activity waiter
+ *
+ * Copyright 2009 Rainer Gerhards and Adiscon GmbH.
+ *
+ * This file is part of the rsyslog runtime library.
+ *
+ * The rsyslog runtime library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The rsyslog runtime library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the rsyslog runtime library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * A copy of the GPL can be found in the file "COPYING" in this distribution.
+ * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution.
+ */
+
+#ifndef INCLUDED_NSPOLL_H
+#define INCLUDED_NSPOLL_H
+
+#include "netstrms.h"
+
+/* some operations to be portable when we do not have epoll() available */
+#define NSDPOLL_ADD 1
+#define NSDPOLL_DEL 2
+
+/* and some mode specifiers for waiting on input/output */
+#define NSDPOLL_IN 1 /* EPOLLIN */
+#define NSDPOLL_OUT 2 /* EPOLLOUT */
+/* next is 4, 8, 16, ... - must be bit values, as they are ored! */
+
+/* the nspoll object */
+struct nspoll_s {
+ BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */
+ nsd_t *pDrvrData; /**< the driver's data elements */
+ uchar *pBaseDrvrName; /**< nsd base driver name to use, or NULL if system default */
+ uchar *pDrvrName; /**< full base driver name (set when driver is loaded) */
+ nsdpoll_if_t Drvr; /**< our stream driver */
+};
+
+
+/* interface */
+BEGINinterface(nspoll) /* name must also be changed in ENDinterface macro! */
+ rsRetVal (*Construct)(nspoll_t **ppThis);
+ rsRetVal (*ConstructFinalize)(nspoll_t *pThis);
+ rsRetVal (*Destruct)(nspoll_t **ppThis);
+ rsRetVal (*Wait)(nspoll_t *pNsdpoll, int timeout, int *idRdy, void **ppUsr);
+ rsRetVal (*Ctl)(nspoll_t *pNsdpoll, netstrm_t *pStrm, int id, void *pUsr, int mode, int op);
+ rsRetVal (*IsEPollSupported)(void); /* static method */
+ENDinterface(nspoll)
+#define nspollCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */
+
+/* prototypes */
+PROTOTYPEObj(nspoll);
+
+/* the name of our library binary */
+#define LM_NSPOLL_FILENAME LM_NETSTRMS_FILENAME
+
+#endif /* #ifndef INCLUDED_NSPOLL_H */
diff --git a/runtime/nssel.c b/runtime/nssel.c
index d11d5fe1..7c5be3a9 100644
--- a/runtime/nssel.c
+++ b/runtime/nssel.c
@@ -219,6 +219,7 @@ ENDObjClassExit(nssel)
*/
BEGINObjClassInit(nssel, 1, OBJ_IS_CORE_MODULE) /* class, version */
/* request objects we use */
+ DBGPRINTF("doing nsselClassInit\n");
CHKiRet(objUse(glbl, CORE_COMPONENT));
/* set our own handlers */
diff --git a/runtime/parser.c b/runtime/parser.c
index cacbe065..bd0bf8e9 100644
--- a/runtime/parser.c
+++ b/runtime/parser.c
@@ -60,6 +60,8 @@ DEFobjCurrIf(ruleset)
/* config data */
static uchar cCCEscapeChar = '#';/* character to be used to start an escape sequence for control chars */
static int bEscapeCCOnRcv = 1; /* escape control characters on reception: 0 - no, 1 - yes */
+static int bEscape8BitChars = 0; /* escape characters > 127 on reception: 0 - no, 1 - yes */
+static int bEscapeTab = 1; /* escape tab control character when doing CC escapes: 0 - no, 1 - yes */
static int bDropTrailingLF = 1; /* drop trailing LF's on reception? */
/* This is the list of all parsers known to us.
@@ -308,7 +310,7 @@ SanitizeMsg(msg_t *pMsg)
size_t iDst;
size_t iMaxLine;
size_t maxDest;
- bool bUpdatedLen = FALSE;
+ sbool bUpdatedLen = FALSE;
uchar szSanBuf[32*1024]; /* buffer used for sanitizing a string */
assert(pMsg != NULL);
@@ -343,6 +345,11 @@ SanitizeMsg(msg_t *pMsg)
* needs sanitation than to do the sanitation in any case. So we first do
* this and terminate when it is not needed - which is expectedly the case
* for the vast majority of messages. -- rgerhards, 2009-06-15
+ * Note that we do NOT check here if tab characters are to be escaped or
+ * not. I expect this functionality to be seldomly used and thus I do not
+ * like to pay the performance penalty. So the penalty is only with those
+ * that actually use it, because we may call the sanitizer without actual
+ * need below (but it then still will work perfectly well!). -- rgerhards, 2009-11-27
*/
int bNeedSanitize = 0;
for(iSrc = 0 ; iSrc < lenMsg ; iSrc++) {
@@ -351,6 +358,9 @@ SanitizeMsg(msg_t *pMsg)
bNeedSanitize = 1;
break;
}
+ } else if(pszMsg[iSrc] > 127 && bEscape8BitChars) {
+ bNeedSanitize = 1;
+ break;
}
}
@@ -371,7 +381,7 @@ SanitizeMsg(msg_t *pMsg)
CHKmalloc(pDst = MALLOC(sizeof(uchar) * (iMaxLine + 1)));
iSrc = iDst = 0;
while(iSrc < lenMsg && iDst < maxDest - 3) { /* leave some space if last char must be escaped */
- if(iscntrl((int) pszMsg[iSrc])) {
+ if(iscntrl((int) pszMsg[iSrc]) && (pszMsg[iSrc] != '\t' || bEscapeTab)) {
/* note: \0 must always be escaped, the rest of the code currently
* can not handle it! -- rgerhards, 2009-08-26
*/
@@ -385,6 +395,14 @@ SanitizeMsg(msg_t *pMsg)
pDst[iDst++] = '0' + ((pszMsg[iSrc] & 0070) >> 3);
pDst[iDst++] = '0' + ((pszMsg[iSrc] & 0007));
}
+ } else if(pszMsg[iSrc] > 127 && bEscape8BitChars) {
+ /* In this case, we also do the conversion. Note that this most
+ * probably breaks European languages. -- rgerhards, 2010-01-27
+ */
+ pDst[iDst++] = cCCEscapeChar;
+ pDst[iDst++] = '0' + ((pszMsg[iSrc] & 0300) >> 6);
+ pDst[iDst++] = '0' + ((pszMsg[iSrc] & 0070) >> 3);
+ pDst[iDst++] = '0' + ((pszMsg[iSrc] & 0007));
} else {
pDst[iDst++] = pszMsg[iSrc];
}
@@ -419,19 +437,24 @@ ParsePRI(msg_t *pMsg)
msg = pMsg->pszRawMsg;
pri = DEFUPRI;
iPriText = 0;
- if(*msg == '<') {
- /* while we process the PRI, we also fill the PRI textual representation
- * inside the msg object. This may not be ideal from an OOP point of view,
- * but it offers us performance...
- */
- pri = 0;
- while(--lenMsg > 0 && isdigit((int) *++msg)) {
- pri = 10 * pri + (*msg - '0');
+ if(pMsg->msgFlags & NO_PRI_IN_RAW) {
+ /* In this case, simply do so as if the pri would be right at top */
+ MsgSetAfterPRIOffs(pMsg, 0);
+ } else {
+ if(*msg == '<') {
+ /* while we process the PRI, we also fill the PRI textual representation
+ * inside the msg object. This may not be ideal from an OOP point of view,
+ * but it offers us performance...
+ */
+ pri = 0;
+ while(--lenMsg > 0 && isdigit((int) *++msg)) {
+ pri = 10 * pri + (*msg - '0');
+ }
+ if(*msg == '>')
+ ++msg;
+ if(pri & ~(LOG_FACMASK|LOG_PRIMASK))
+ pri = DEFUPRI;
}
- if(*msg == '>')
- ++msg;
- if(pri & ~(LOG_FACMASK|LOG_PRIMASK))
- pri = DEFUPRI;
}
pMsg->iFacility = LOG_FAC(pri);
pMsg->iSeverity = LOG_PRI(pri);
@@ -451,8 +474,8 @@ ParseMsg(msg_t *pMsg)
rsRetVal localRet = RS_RET_ERR;
parserList_t *pParserList;
parser_t *pParser;
- bool bIsSanitized;
- bool bPRIisParsed;
+ sbool bIsSanitized;
+ sbool bPRIisParsed;
static int iErrMsgRateLimiter = 0;
DEFiRet;
@@ -467,7 +490,8 @@ ParseMsg(msg_t *pMsg)
* (and that functionality is too important for debugging to drop it...).
*/
DBGPRINTF("msg parser: flags %x, from '%s', msg '%.50s'\n", pMsg->msgFlags,
- getRcvFrom(pMsg), pMsg->pszRawMsg);
+ (pMsg->msgFlags & NEEDS_DNSRESOL) ? UCHAR_CONSTANT("~NOTRESOLVED~") : getRcvFrom(pMsg),
+ pMsg->pszRawMsg);
/* we now need to go through our list of parsers and see which one is capable of
* parsing the message. Note that the first parser that requires message sanitization
@@ -623,6 +647,8 @@ resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unus
{
cCCEscapeChar = '#';
bEscapeCCOnRcv = 1; /* default is to escape control characters */
+ bEscape8BitChars = 0; /* default is to escape control characters */
+ bEscapeTab = 1; /* default is to escape control characters */
bDropTrailingLF = 1; /* default is to drop trailing LF's on reception */
return RS_RET_OK;
@@ -674,6 +700,8 @@ BEGINObjClassInit(parser, 1, OBJ_IS_CORE_MODULE) /* class, version */
CHKiRet(regCfSysLineHdlr((uchar *)"controlcharacterescapeprefix", 0, eCmdHdlrGetChar, NULL, &cCCEscapeChar, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"droptrailinglfonreception", 0, eCmdHdlrBinary, NULL, &bDropTrailingLF, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"escapecontrolcharactersonreceive", 0, eCmdHdlrBinary, NULL, &bEscapeCCOnRcv, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"escape8bitcharactersonreceive", 0, eCmdHdlrBinary, NULL, &bEscape8BitChars, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"escapecontrolcharactertab", 0, eCmdHdlrBinary, NULL, &bEscapeTab, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, NULL));
InitParserList(&pParsLstRoot);
diff --git a/runtime/parser.h b/runtime/parser.h
index c4f63021..bdd572cb 100644
--- a/runtime/parser.h
+++ b/runtime/parser.h
@@ -38,8 +38,8 @@ struct parser_s {
BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */
uchar *pName; /* name of this parser */
modInfo_t *pModule; /* pointer to parser's module */
- bool bDoSanitazion; /* do standard message sanitazion before calling parser? */
- bool bDoPRIParsing; /* do standard PRI parsing before calling parser? */
+ sbool bDoSanitazion; /* do standard message sanitazion before calling parser? */
+ sbool bDoPRIParsing; /* do standard PRI parsing before calling parser? */
};
/* interfaces */
diff --git a/runtime/queue.h b/runtime/queue.h
index 93573dae..38c0d491 100644
--- a/runtime/queue.h
+++ b/runtime/queue.h
@@ -60,9 +60,9 @@ struct queue_s {
queueType_t qType;
int nLogDeq; /* number of elements currently logically dequeued */
int bShutdownImmediate; /* should all workers cease processing messages? */
- bool bEnqOnly; /* does queue run in enqueue-only mode (1) or not (0)? */
- bool bSaveOnShutdown;/* persists everthing on shutdown (if DA!)? 1-yes, 0-no */
- bool bQueueStarted; /* has queueStart() been called on this queue? 1-yes, 0-no */
+ sbool bEnqOnly; /* does queue run in enqueue-only mode (1) or not (0)? */
+ sbool bSaveOnShutdown;/* persists everthing on shutdown (if DA!)? 1-yes, 0-no */
+ sbool bQueueStarted; /* has queueStart() been called on this queue? 1-yes, 0-no */
int iQueueSize; /* Current number of elements in the queue */
int iMaxQueueSize; /* how large can the queue grow? */
int iNumWorkerThreads;/* number of worker threads to use */
@@ -73,14 +73,14 @@ struct queue_s {
void *pUsr; /* a global, user-supplied pointer. Is passed back to consumer. */
int iUpdsSincePersist;/* nbr of queue updates since the last persist call */
int iPersistUpdCnt; /* persits queue info after this nbr of updates - 0 -> persist only on shutdown */
- bool bSyncQueueFiles;/* if working with files, sync them after each write? */
+ sbool bSyncQueueFiles;/* if working with files, sync them after each write? */
int iHighWtrMrk; /* high water mark for disk-assisted memory queues */
int iLowWtrMrk; /* low water mark for disk-assisted memory queues */
int iDiscardMrk; /* if the queue is above this mark, low-severity messages are discarded */
int iFullDlyMrk; /* if the queue is above this mark, FULL_DELAYable message are put on hold */
int iLightDlyMrk; /* if the queue is above this mark, LIGHT_DELAYable message are put on hold */
int iDiscardSeverity;/* messages of this severity above are discarded on too-full queue */
- bool bNeedDelQIF; /* does the QIF file need to be deleted when queue becomes empty? */
+ sbool bNeedDelQIF; /* does the QIF file need to be deleted when queue becomes empty? */
int toQShutdown; /* timeout for regular queue shutdown in ms */
int toActShutdown; /* timeout for long-running action shutdown in ms */
int toWrkShutdown; /* timeout for idle workers in ms, -1 means indefinite (0 is immediate) */
diff --git a/runtime/rsyslog.c b/runtime/rsyslog.c
index a76ae25a..921ad0bd 100644
--- a/runtime/rsyslog.c
+++ b/runtime/rsyslog.c
@@ -81,6 +81,7 @@
#include "rule.h"
#include "ruleset.h"
#include "parser.h"
+#include "atomic.h"
/* forward definitions */
static rsRetVal dfltErrLogger(int, uchar *errMsg);
@@ -140,6 +141,12 @@ rsrtInit(char **ppErrObj, obj_if_t *pObjIF)
CHKiRet(objClassInit(NULL)); /* *THIS* *MUST* always be the first class initilizer being called! */
CHKiRet(objGetObjInterface(pObjIF)); /* this provides the root pointer for all other queries */
+#ifndef HAVE_ATOMIC_BUILTINS
+#ifdef HAVE_SEMAPHORE_H
+ CHKiRet(atomicSemInit());
+#endif /* HAVE_SEMAPHORE_H */
+#endif /* !defined(HAVE_ATOMIC_BUILTINS) */
+
/* initialize core classes. We must be very careful with the order of events. Some
* classes use others and if we do not initialize them in the right order, we may end
* up with an invalid call. The most important thing that can happen is that an error
@@ -216,6 +223,13 @@ rsrtExit(void)
glblClassExit();
rulesetClassExit();
ruleClassExit();
+
+#ifndef HAVE_ATOMIC_BUILTINS
+#ifdef HAVE_SEMAPHORE_H
+ atomicSemExit();
+#endif /* HAVE_SEMAPHORE_H */
+#endif /* !defined(HAVE_ATOMIC_BUILTINS) */
+
objClassExit(); /* *THIS* *MUST/SHOULD?* always be the first class initilizer being called (except debug)! */
}
diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h
index 1a9186ed..0b4fbfed 100644
--- a/runtime/rsyslog.h
+++ b/runtime/rsyslog.h
@@ -79,6 +79,10 @@
#define CORE_FEATURE_BATCHING 1
/*#define CORE_FEATURE_whatever 2 ... and so on ... */
+/* under Solaris (actually only SPARC), we need to redefine some types
+ * to be void, so that we get void* pointers. Otherwise, we will see
+ * alignment errors.
+ */
/* some universal fixed size integer defines ... */
typedef long long int64;
typedef long long unsigned uint64;
@@ -87,6 +91,7 @@ typedef char intTiny; /* 0..127! */
typedef unsigned char uintTiny; /* 0..255! */
/* define some base data types */
+
typedef unsigned char uchar;/* get rid of the unhandy "unsigned char" */
typedef struct aUsrp_s aUsrp_t;
typedef struct thrdInfo thrdInfo_t;
@@ -98,6 +103,7 @@ typedef struct NetAddr netAddr_t;
typedef struct netstrms_s netstrms_t;
typedef struct netstrm_s netstrm_t;
typedef struct nssel_s nssel_t;
+typedef struct nspoll_s nspoll_t;
typedef enum nsdsel_waitOp_e nsdsel_waitOp_t;
typedef struct nsd_ptcp_s nsd_ptcp_t;
typedef struct nsd_gtls_s nsd_gtls_t;
@@ -105,9 +111,8 @@ typedef struct nsd_gsspi_s nsd_gsspi_t;
typedef struct nsd_nss_s nsd_nss_t;
typedef struct nsdsel_ptcp_s nsdsel_ptcp_t;
typedef struct nsdsel_gtls_s nsdsel_gtls_t;
+typedef struct nsdpoll_ptcp_s nsdpoll_ptcp_t;
typedef struct wti_s wti_t;
-typedef obj_t nsd_t;
-typedef obj_t nsdsel_t;
typedef struct msg msg_t;
typedef struct queue_s qqueue_t;
typedef struct prop_s prop_t;
@@ -134,12 +139,31 @@ typedef uint64 qDeqID; /* queue Dequeue order ID. 32 bits is considered dangerou
typedef struct tcpLstnPortList_s tcpLstnPortList_t; // TODO: rename?
typedef struct strmLstnPortList_s strmLstnPortList_t; // TODO: rename?
+/* under Solaris (actually only SPARC), we need to redefine some types
+ * to be void, so that we get void* pointers. Otherwise, we will see
+ * alignment errors.
+ */
+#ifdef OS_SOLARIS
+ typedef void * obj_t_ptr;
+ typedef void nsd_t;
+ typedef void nsdsel_t;
+ typedef void nsdpoll_t;
+#else
+ typedef obj_t *obj_t_ptr;
+ typedef obj_t nsd_t;
+ typedef obj_t nsdsel_t;
+ typedef obj_t nsdpoll_t;
+#endif
+
+
#ifdef __hpux
typedef unsigned int u_int32_t; /* TODO: is this correct? */
typedef int socklen_t;
#endif
-typedef char bool; /* I intentionally use char, to keep it slim so that many fit into the CPU cache! */
+typedef struct epoll_event epoll_event_t;
+
+typedef char sbool; /* (small bool) I intentionally use char, to keep it slim so that many fit into the CPU cache! */
/* settings for flow control
* TODO: is there a better place for them? -- rgerhards, 2008-03-14
@@ -389,6 +413,9 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth
RS_RET_VAR_NOT_FOUND = -2142, /**< variable not found */
RS_RET_EMPTY_MSG = -2143, /**< provided (raw) MSG is empty */
RS_RET_PEER_CLOSED_CONN = -2144, /**< remote peer closed connection (information, no error) */
+ RS_RET_ERR_OPEN_KLOG = -2145, /**< error opening the kernel log socket (primarily solaris) */
+ RS_RET_ERR_AQ_CONLOG = -2146, /**< error aquiring console log (on solaris) */
+ RS_RET_ERR_DOOR = -2147, /**< some problems with handling the Solaris door functionality */
RS_RET_NO_SRCNAME_TPL = -2150, /**< sourcename template was not specified where one was needed (omudpspoof spoof addr) */
RS_RET_HOST_NOT_SPECIFIED = -2151, /**< (target) host was not specified where it was needed */
RS_RET_ERR_LIBNET_INIT = -2152, /**< error initializing libnet */
@@ -400,6 +427,11 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth
RS_RET_NO_RULESET= -2158,/**< no ruleset name as specified where one was needed */
RS_RET_PARSER_NOT_FOUND = -2159,/**< parser with the specified name was not found */
RS_RET_COULD_NOT_PARSE = -2160,/**< (this) parser could not parse the message (no error, means try next one) */
+ RS_RET_EINTR = -2161, /**< EINTR occured during a system call (not necessarily an error) */
+ RS_RET_ERR_EPOLL = -2162, /**< epoll() returned with an unexpected error code */
+ RS_RET_ERR_EPOLL_CTL = -2163, /**< epol_ctll() returned with an unexpected error code */
+ RS_RET_TIMEOUT = -2164, /**< timeout occured during operation */
+ RS_RET_RCV_ERR = -2165, /**< error occured during socket rcv operation */
/* RainerScript error messages (range 1000.. 1999) */
RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */
diff --git a/runtime/rule.h b/runtime/rule.h
index 99ac44e7..7b607637 100644
--- a/runtime/rule.h
+++ b/runtime/rule.h
@@ -47,7 +47,7 @@ struct rule_s {
fiop_t operation;
regex_t *regex_cache; /* cache for compiled REs, if such are used */
cstr_t *pCSCompValue; /* value to "compare" against */
- bool isNegated;
+ sbool isNegated;
propid_t propID; /* ID of the requested property */
} prop;
expr_t *f_expr; /* expression object */
diff --git a/runtime/srutils.c b/runtime/srutils.c
index 92227399..d357cd77 100644
--- a/runtime/srutils.c
+++ b/runtime/srutils.c
@@ -46,6 +46,9 @@
#include "srUtils.h"
#include "obj.h"
+#if _POSIX_TIMERS <= 0
+#include <sys/time.h>
+#endif
/* here we host some syslog specific names. There currently is no better place
* to do it, but over here is also not ideal... -- rgerhards, 2008-02-14
@@ -392,10 +395,22 @@ int getNumberDigits(long lNum)
rsRetVal
timeoutComp(struct timespec *pt, long iTimeout)
{
+# if _POSIX_TIMERS <= 0
+ struct timeval tv;
+# endif
+
BEGINfunc
assert(pt != NULL);
/* compute timeout */
+
+# if _POSIX_TIMERS > 0
+ /* this is the "regular" code */
clock_gettime(CLOCK_REALTIME, pt);
+# else
+ gettimeofday(&tv, NULL);
+ pt->tv_sec = tv.tv_sec;
+ pt->tv_nsec = tv.tv_usec * 1000;
+# endif
pt->tv_sec += iTimeout / 1000;
pt->tv_nsec += (iTimeout % 1000) * 1000000; /* think INTEGER arithmetic! */
if(pt->tv_nsec > 999999999) { /* overrun? */
@@ -417,11 +432,21 @@ timeoutVal(struct timespec *pt)
{
struct timespec t;
long iTimeout;
- BEGINfunc
+# if _POSIX_TIMERS <= 0
+ struct timeval tv;
+# endif
+ BEGINfunc
assert(pt != NULL);
/* compute timeout */
+# if _POSIX_TIMERS > 0
+ /* this is the "regular" code */
clock_gettime(CLOCK_REALTIME, &t);
+# else
+ gettimeofday(&tv, NULL);
+ t.tv_sec = tv.tv_sec;
+ t.tv_nsec = tv.tv_usec * 1000;
+# endif
iTimeout = (pt->tv_nsec - t.tv_nsec) / 1000000;
iTimeout += (pt->tv_sec - t.tv_sec) * 1000;
diff --git a/runtime/stream.c b/runtime/stream.c
index 0415c25c..e0b97f9f 100644
--- a/runtime/stream.c
+++ b/runtime/stream.c
@@ -215,7 +215,8 @@ doPhysOpen(strm_t *pThis)
}
pThis->fd = open((char*)pThis->pszCurrFName, iFlags, pThis->tOpenMode);
- DBGPRINTF("file '%s' opened as #%d with mode %d\n", pThis->pszCurrFName, pThis->fd, pThis->tOpenMode);
+ DBGPRINTF("file '%s' opened as #%d with mode %d\n", pThis->pszCurrFName,
+ pThis->fd, (int) pThis->tOpenMode);
if(pThis->fd == -1) {
char errStr[1024];
int err = errno;
@@ -923,7 +924,7 @@ asyncWriterThread(void *pPtr)
{
int iDeq;
struct timespec t;
- bool bTimedOut = 0;
+ sbool bTimedOut = 0;
strm_t *pThis = (strm_t*) pPtr;
ISOBJ_TYPE_assert(pThis, strm);
@@ -1090,7 +1091,7 @@ doZipWrite(strm_t *pThis, uchar *pBuf, size_t lenBuf)
{
z_stream zstrm;
int zRet; /* zlib return state */
- bool bzInitDone = FALSE;
+ sbool bzInitDone = FALSE;
DEFiRet;
assert(pThis != NULL);
assert(pBuf != NULL);
diff --git a/runtime/stream.h b/runtime/stream.h
index e67bcda6..37e9d570 100644
--- a/runtime/stream.h
+++ b/runtime/stream.h
@@ -102,12 +102,12 @@ typedef struct strm_s {
int64 iMaxFileSize;/* maximum size a file may grow to */
int iMaxFiles; /* maximum number of files if a circular mode is in use */
int iFileNumDigits;/* min number of digits to use in file number (only in circular mode) */
- bool bDeleteOnClose; /* set to 1 to auto-delete on close -- be careful with that setting! */
+ sbool bDeleteOnClose; /* set to 1 to auto-delete on close -- be careful with that setting! */
int64 iCurrOffs;/* current offset */
int64 *pUsrWCntr; /* NULL or a user-provided counter that receives the nbr of bytes written since the last CntrSet() */
/* dynamic properties, valid only during file open, not to be persistet */
- bool bDisabled; /* should file no longer be written to? (currently set only if omfile file size limit fails) */
- bool bSync; /* sync this file after every write? */
+ sbool bDisabled; /* should file no longer be written to? (currently set only if omfile file size limit fails) */
+ sbool bSync; /* sync this file after every write? */
size_t sIOBufSize;/* size of IO buffer */
uchar *pszDir; /* Directory */
int lenDir;
@@ -118,13 +118,13 @@ typedef struct strm_s {
size_t iBufPtrMax; /* current max Ptr in Buffer (if partial read!) */
size_t iBufPtr; /* pointer into current buffer */
int iUngetC; /* char set via UngetChar() call or -1 if none set */
- bool bInRecord; /* if 1, indicates that we are currently writing a not-yet complete record */
+ sbool bInRecord; /* if 1, indicates that we are currently writing a not-yet complete record */
int iZipLevel; /* zip level (0..9). If 0, zip is completely disabled */
Bytef *pZipBuf;
/* support for async flush procesing */
- bool bAsyncWrite; /* do asynchronous writes (always if a flush interval is given) */
- bool bStopWriter; /* shall writer thread terminate? */
- bool bDoTimedWait; /* instruct writer thread to do a times wait to support flush timeouts */
+ sbool bAsyncWrite; /* do asynchronous writes (always if a flush interval is given) */
+ sbool bStopWriter; /* shall writer thread terminate? */
+ sbool bDoTimedWait; /* instruct writer thread to do a times wait to support flush timeouts */
int iFlushInterval; /* flush in which interval - 0, no flushing */
apc_id_t apcID; /* id of current Apc request (used for cancelling) */
pthread_mutex_t mut;/* mutex for flush in async mode */
@@ -143,7 +143,7 @@ typedef struct strm_s {
/* support for omfile size-limiting commands, special counters, NOT persisted! */
off_t iSizeLimit; /* file size limit, 0 = no limit */
uchar *pszSizeLimitCmd; /* command to carry out when size limit is reached */
- bool bIsTTY; /* is this a tty file? */
+ sbool bIsTTY; /* is this a tty file? */
} strm_t;
diff --git a/runtime/unlimited_select.h b/runtime/unlimited_select.h
new file mode 100644
index 00000000..32dadc03
--- /dev/null
+++ b/runtime/unlimited_select.h
@@ -0,0 +1,45 @@
+/* unlimited_select.h
+ * Tweak the macros for accessing fd_set so that the select() syscall
+ * won't be limited to a particular number of file descriptors.
+ *
+ * Copyright 2009 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.
+ */
+
+#ifndef UNLIMITED_SELECT_H_INCLUDED
+
+#include <string.h>
+#include <stdlib.h>
+#include <sys/select.h>
+#include "glbl.h"
+
+#ifdef USE_UNLIMITED_SELECT
+# undef FD_ZERO
+# define FD_ZERO(set) memset((set), 0, glbl.GetFdSetSize());
+#endif
+
+#ifdef USE_UNLIMITED_SELECT
+void freeFdSet(fd_set *p) {
+ free(p);
+}
+#else
+# define freeFdSet(x)
+#endif
+
+#endif /* #ifndef UNLIMITED_SELECT_H_INCLUDED */
diff --git a/runtime/wti.c b/runtime/wti.c
index 288670b6..14964fb0 100644
--- a/runtime/wti.c
+++ b/runtime/wti.c
@@ -79,7 +79,7 @@ wtiGetDbgHdr(wti_t *pThis)
/* return the current worker processing state. For the sake of
* simplicity, we do not use the iRet interface. -- rgerhards, 2009-07-17
*/
-bool
+sbool
wtiGetState(wti_t *pThis)
{
return ATOMIC_FETCH_32BIT(pThis->bIsRunning);
@@ -102,7 +102,7 @@ wtiSetAlwaysRunning(wti_t *pThis)
* is inside wti). -- rgerhards, 2009-07-17
*/
rsRetVal
-wtiSetState(wti_t *pThis, bool bNewVal)
+wtiSetState(wti_t *pThis, sbool bNewVal)
{
ISOBJ_TYPE_assert(pThis, wti);
if(bNewVal)
diff --git a/runtime/wti.h b/runtime/wti.h
index f466a053..e587c69e 100644
--- a/runtime/wti.h
+++ b/runtime/wti.h
@@ -35,7 +35,7 @@ struct wti_s {
BEGINobjInstance;
pthread_t thrdID; /* thread ID */
int bIsRunning; /* is this thread currently running? (must be int for atomic op!) */
- bool bAlwaysRunning; /* should this thread always run? */
+ sbool bAlwaysRunning; /* should this thread always run? */
wtp_t *pWtp; /* my worker thread pool (important if only the work thread instance is passed! */
batch_t batch; /* pointer to an object array meaningful for current user pointer (e.g. queue pUsr data elemt) */
uchar *pszDbgHdr; /* header string for debug messages */
@@ -50,8 +50,8 @@ rsRetVal wtiWorker(wti_t *pThis);
rsRetVal wtiSetDbgHdr(wti_t *pThis, uchar *pszMsg, size_t lenMsg);
rsRetVal wtiCancelThrd(wti_t *pThis);
rsRetVal wtiSetAlwaysRunning(wti_t *pThis);
-rsRetVal wtiSetState(wti_t *pThis, bool bNew);
-bool wtiGetState(wti_t *pThis);
+rsRetVal wtiSetState(wti_t *pThis, sbool bNew);
+sbool wtiGetState(wti_t *pThis);
PROTOTYPEObjClassInit(wti);
PROTOTYPEpropSetMeth(wti, pszDbgHdr, uchar*);
PROTOTYPEpropSetMeth(wti, pWtp, wtp_t*);
diff --git a/runtime/wtp.c b/runtime/wtp.c
index 060e6627..649ffa5a 100644
--- a/runtime/wtp.c
+++ b/runtime/wtp.c
@@ -329,11 +329,13 @@ wtpWrkrExecCancelCleanup(void *arg)
static void *
wtpWorker(void *arg) /* the arg is actually a wti object, even though we are in wtp! */
{
- uchar *pszDbgHdr;
- uchar thrdName[32] = "rs:";
wti_t *pWti = (wti_t*) arg;
wtp_t *pThis;
sigset_t sigSet;
+# if HAVE_PRCTL && defined PR_SET_NAME
+ uchar *pszDbgHdr;
+ uchar thrdName[32] = "rs:";
+# endif
BEGINfunc
ISOBJ_TYPE_assert(pWti, wti);
@@ -442,7 +444,6 @@ wtpAdviseMaxWorkers(wtp_t *pThis, int nMaxWrkr)
CHKiRet(wtpStartWrkr(pThis));
}
} else {
-dbgprintf("YYY: wtpAdviseMaxWorkers, sufficient workers, just doing adivse signal cond busy\n");
pthread_cond_signal(pThis->pcondBusy);
}
diff --git a/solaris/README b/solaris/README
new file mode 100644
index 00000000..3f88431d
--- /dev/null
+++ b/solaris/README
@@ -0,0 +1,38 @@
+Notes for Solaris
+
+Rsyslog will be fully supported on Solaris in the future. To build it, the GNU build
+tools (and most of the GNU environment) is needed. This software can be
+found at the excellent http://www.blastwave.org site.
+
+PREQUISITES
+It is strongly recommended to use GCC4 with support for
+atomic instructions (if available for the platform). While rsyslog can
+be built without atomic instructin support (and will work well then),
+it then falls back to POSIX semaphores, which require much more CPU
+time than atomic instructions. Note that even on intel platforms the
+(current, as of 2010-03-25) blastwave gcc4 version targets too-old
+processors by default. To change that, use "-imarch=I686" in your
+CFLAGS.
+
+CONFIGURE OPTIONS
+A number of GNU tools are renamed g* so that they not conflict with
+the native Solaris tools. As we need the GNU replacements, this
+must be specified on the ./configure line.
+Also, we must tell the linker where to find the glibc library when
+building the plugins. This is done via the LDFLAGS variable as
+shown below (based on the good information availabe at
+http://prefetch.net/articles/linkers.badldlibrary.html
+
+The working sample configure sequence I use is:
+
+export LDFLAGS="-R/opt/csw/gcc4/lib"
+./configure AR=gar ...other options...
+
+As a "quick and dirty" fix, one may set the following library
+path before executing rsyslog (may be useful to avoid recompile):
+
+export LD_LIBRARY_PATH=/opt/csw/gcc4/lib
+
+NOT YET SUPPORTED
+* local log socket
+* kernel log
diff --git a/solaris/cddllicense.txt b/solaris/cddllicense.txt
new file mode 100644
index 00000000..a10bba27
--- /dev/null
+++ b/solaris/cddllicense.txt
@@ -0,0 +1,242 @@
+ COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL)
+ Version 1.0
+
+
+1. Definitions.
+
+ 1.1. “Contributor” means each individual or entity that creates or contributes to the creation of Modifications.
+
+ 1.2. “Contributor Version” means the combination of the Original Software, prior Modifications used by a Contributor
+ (if any), and the Modifications made by that particular Contributor.
+
+ 1.3. “Covered Software” means (a) the Original Software, or (b) Modifications, or (c) the combination
+ of files containing Original Software with files containing Modifications, in each case including portions thereof.
+
+ 1.4. “Executable” means the Covered Software in any form other than Source Code.
+
+ 1.5. “Initial Developer” means the individual or entity that first makes Original Software available under this License.
+
+ 1.6. “Larger Work” means a work which combines Covered Software or portions thereof with code not governed by the terms
+ of this License.
+
+ 1.7. “License” means this document.
+
+ 1.8. “Licensable” means having the right to grant, to the maximum extent possible, whether at the time of the
+ initial grant or subsequently acquired, any and all of the rights conveyed herein.
+
+ 1.9. “Modifications” means the Source Code and Executable form of any of the following:
+ A. Any file that results from an addition to, deletion from or modification of the contents of a file
+ containing Original Software or previous Modifications;
+ B. Any new file that contains any part of the Original Software or previous Modification; or
+ C. Any new file that is contributed or otherwise made available under the terms of this License.
+
+ 1.10. “Original Software” means the Source Code and Executable form of computer software code that is originally
+ released under this License.
+
+ 1.11. “Patent Claims” means any patent claim(s), now owned or hereafter acquired, including without limitation,
+ method, process, and apparatus claims, in any patent Licensable by grantor.
+
+ 1.12. “Source Code” means (a) the common form of computer software code in which modifications are made and
+ (b) associated documentation included in or with such code.
+
+ 1.13. “You” (or “Your”) means an individual or a legal entity exercising rights under, and complying with all of
+ the terms of, this License. For legal entities, “You” includes any entity which controls, is controlled by, or is
+ under common control with You. For purposes of this definition, “control” means (a) the power, direct or indirect,
+ to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more
+ than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity.
+
+2. License Grants.
+
+ 2.1. The Initial Developer Grant.
+ Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims,
+ the Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license:
+
+ (a) under intellectual property rights (other than patent or trademark) Licensable by Initial Developer,
+ to use, reproduce, modify, display, perform, sublicense and distribute the Original Software (or portions
+ thereof), with or without Modifications, and/or as part of a Larger Work; and
+
+ (b) under Patent Claims infringed by the making, using or selling of Original Software, to make, have made,
+ use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Software (or portions thereof).
+
+ (c) The licenses granted in Sections 2.1(a) and (b) are effective on the date Initial Developer first
+ distributes or otherwise makes the Original Software available to a third party under the terms of this License.
+
+ (d) Notwithstanding Section 2.1(b) above, no patent license is granted: (1) for code that You delete from
+ the Original Software, or (2) for infringements caused by: (i) the modification of the Original Software,
+ or (ii) the combination of the Original Software with other software or devices.
+
+ 2.2. Contributor Grant.
+ Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims,
+ each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license:
+
+ (a) under intellectual property rights (other than patent or trademark) Licensable by Contributor to use,
+ reproduce, modify, display, perform, sublicense and distribute the Modifications created by such Contributor
+ (or portions thereof), either on an unmodified basis, with other Modifications, as Covered Software and/or
+ as part of a Larger Work; and
+
+ (b) under Patent Claims infringed by the making, using, or selling of Modifications made by that Contributor
+ either alone and/or in combination with its Contributor Version (or portions of such combination), to make,
+ use, sell, offer for sale, have made, and/or otherwise dispose of: (1) Modifications made by that Contributor
+ (or portions thereof); and (2) the combination of Modifications made by that Contributor with its Contributor
+ Version (or portions of such combination).
+
+ (c) The licenses granted in Sections 2.2(a) and 2.2(b) are effective on the date Contributor first distributes
+ or otherwise makes the Modifications available to a third party.
+
+ (d) Notwithstanding Section 2.2(b) above, no patent license is granted: (1) for any code that Contributor has
+ deleted from the Contributor Version; (2) for infringements caused by: (i) third party modifications of
+ Contributor Version, or (ii) the combination of Modifications made by that Contributor with other software
+ (except as part of the Contributor Version) or other devices; or (3) under Patent Claims infringed by Covered
+ Software in the absence of Modifications made by that Contributor.
+
+3. Distribution Obligations.
+
+ 3.1. Availability of Source Code.
+ Any Covered Software that You distribute or otherwise make available in Executable form must also be made available
+ in Source Code form and that Source Code form must be distributed only under the terms of this License. You must
+ include a copy of this License with every copy of the Source Code form of the Covered Software You distribute or
+ otherwise make available. You must inform recipients of any such Covered Software in Executable form as to how they
+ can obtain such Covered Software in Source Code form in a reasonable manner on or through a medium customarily used
+ for software exchange.
+
+ 3.2. Modifications.
+ The Modifications that You create or to which You contribute are governed by the terms of this License. You
+ represent that You believe Your Modifications are Your original creation(s) and/or You have sufficient rights to
+ grant the rights conveyed by this License.
+
+ 3.3. Required Notices.
+ You must include a notice in each of Your Modifications that identifies You as the Contributor of the Modification.
+ You may not remove or alter any copyright, patent or trademark notices contained within the Covered Software, or
+ any notices of licensing or any descriptive text giving attribution to any Contributor or the Initial Developer.
+
+ 3.4. Application of Additional Terms.
+ You may not offer or impose any terms on any Covered Software in Source Code form that alters or restricts the
+ applicable version of this License or the recipients’ rights hereunder. You may choose to offer, and to charge a
+ fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software.
+ However, you may do so only on Your own behalf, and not on behalf of the Initial Developer or any Contributor.
+ You must make it absolutely clear that any such warranty, support, indemnity or liability obligation is offered
+ by You alone, and You hereby agree to indemnify the Initial Developer and every Contributor for any liability
+ incurred by the Initial Developer or such Contributor as a result of warranty, support, indemnity or liability
+ terms You offer.
+
+ 3.5. Distribution of Executable Versions.
+ You may distribute the Executable form of the Covered Software under the terms of this License or under the terms
+ of a license of Your choice, which may contain terms different from this License, provided that You are in compliance
+ with the terms of this License and that the license for the Executable form does not attempt to limit or alter
+ the recipient’s rights in the Source Code form from the rights set forth in this License. If You distribute the
+ Covered Software in Executable form under a different license, You must make it absolutely clear that any terms
+ which differ from this License are offered by You alone, not by the Initial Developer or Contributor. You hereby
+ agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer
+ or such Contributor as a result of any such terms You offer.
+
+ 3.6. Larger Works.
+ You may create a Larger Work by combining Covered Software with other code not governed by the terms of this License
+ and distribute the Larger Work as a single product. In such a case, You must make sure the requirements of this
+ License are fulfilled for the Covered Software.
+
+4. Versions of the License.
+
+ 4.1. New Versions.
+ Sun Microsystems, Inc. is the initial license steward and may publish revised and/or new versions of this License
+ from time to time. Each version will be given a distinguishing version number. Except as provided in Section 4.3,
+ no one other than the license steward has the right to modify this License.
+
+ 4.2. Effect of New Versions.
+ You may always continue to use, distribute or otherwise make the Covered Software available under the terms of
+ the version of the License under which You originally received the Covered Software. If the Initial Developer
+ includes a notice in the Original Software prohibiting it from being distributed or otherwise made available under
+ any subsequent version of the License, You must distribute and make the Covered Software available under the terms
+ of the version of the License under which You originally received the Covered Software. Otherwise, You may also
+ choose to use, distribute or otherwise make the Covered Software available under the terms of any subsequent version
+ of the License published by the license steward.
+
+ 4.3. Modified Versions.
+ When You are an Initial Developer and You want to create a new license for Your Original Software, You may create
+ and use a modified version of this License if You: (a) rename the license and remove any references to the name of
+ the license steward (except to note that the license differs from this License); and (b) otherwise make it clear that
+ the license contains terms which differ from this License.
+
+5. DISCLAIMER OF WARRANTY.
+
+COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN “AS IS” BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR
+IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A
+PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU.
+SHOULD ANY COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
+COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE.
+NO USE OF ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+6. TERMINATION.
+
+ 6.1. This License and the rights granted hereunder will terminate automatically if You fail to comply with terms
+ herein and fail to cure such breach within 30 days of becoming aware of the breach. Provisions which, by their
+ nature, must remain in effect beyond the termination of this License shall survive.
+
+ 6.2. If You assert a patent infringement claim (excluding declaratory judgment actions) against Initial Developer
+ or a Contributor (the Initial Developer or Contributor against whom You assert such claim is referred to as
+ “Participant”) alleging that the Participant Software (meaning the Contributor Version where the Participant
+ is a Contributor or the Original Software where the Participant is the Initial Developer) directly or
+ indirectly infringes any patent, then any and all rights granted directly or indirectly to You by such Participant,
+ the Initial Developer (if the Initial Developer is not the Participant) and all Contributors under Sections 2.1
+ and/or 2.2 of this License shall, upon 60 days notice from Participant terminate prospectively and automatically
+ at the expiration of such 60 day notice period, unless if within such 60 day period You withdraw Your claim with
+ respect to the Participant Software against such Participant either unilaterally or pursuant to a written agreement
+ with Participant.
+
+ 6.3. If You assert a patent infringement claim against Participant alleging that the Participant Software directly
+ or indirectly infringes any patent where such claim is resolved (such as by license or settlement) prior to the
+ initiation of patent infringement litigation, then the reasonable value of the licenses granted by such Participant
+ under Sections 2.1 or 2.2 shall be taken into account in determining the amount or value of any payment or license.
+
+ 6.4. In the event of termination under Sections 6.1 or 6.2 above, all end user licenses that have been validly granted
+ by You or any distributor hereunder prior to termination (excluding licenses granted to You by any distributor)
+ shall survive termination.
+
+7. LIMITATION OF LIABILITY.
+
+UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE
+INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO
+ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR
+LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY
+SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL
+INJURY RESULTING FROM SUCH PARTY’S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
+EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
+
+8. U.S. GOVERNMENT END USERS.
+
+The Covered Software is a “commercial item,” as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of
+“commercial computer software” (as that term is defined at 48 C.F.R. § 252.227-7014(a)(1)) and “commercial computer software documentation”
+as such terms are used in 48 C.F.R. 12.212 Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
+all U.S. Government End Users acquire Covered Software with only those rights set forth herein. This U.S. Government Rights clause is in lieu of,
+and supersedes, any other FAR, DFAR, or other clause or provision that addresses Government rights in computer software under this License.
+
+9. MISCELLANEOUS.
+
+This License represents the complete agreement concerning subject matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. This License shall be governed
+by the law of the jurisdiction specified in a notice contained within the Original Software (except to the extent applicable law, if any,
+provides otherwise), excluding such jurisdiction’s conflict-of-law provisions. Any litigation relating to this License shall be subject
+to the jurisdiction of the courts located in the jurisdiction and venue specified in a notice contained within the Original Software, with the
+losing party responsible for costs, including, without limitation, court costs and reasonable attorneys’ fees and expenses. The application of
+the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any law or regulation which provides that
+the language of a contract shall be construed against the drafter shall not apply to this License. You agree that You alone are responsible for
+compliance with the United States export administration regulations (and the export control laws and regulation of any other countries) when You use,
+distribute or otherwise make available any Covered Software.
+
+10. RESPONSIBILITY FOR CLAIMS.
+
+As between Initial Developer and the Contributors, each party is responsible for claims and damages arising, directly or indirectly, out of
+its utilization of rights under this License and You agree to work with Initial Developer and Contributors to distribute such responsibility on
+an equitable basis. Nothing herein is intended or shall be deemed to constitute any admission of liability.
+
+--------
+
+NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION
+LICENSE (CDDL)
+
+The OpenSolaris code released under the CDDL shall be governed by the laws
+of the State of California (excluding conflict-of-law provisions). Any
+litigation relating to this License shall be subject to the jurisdiction of
+the Federal Courts of the Northern District of California and the state
+courts of the State of California, with venue lying in Santa Clara County,
+California.
+
diff --git a/tcps_sess.c b/tcps_sess.c
index 0b91b6c4..1ae065fa 100644
--- a/tcps_sess.c
+++ b/tcps_sess.c
@@ -405,7 +405,7 @@ processDataRcvd(tcps_sess_t *pThis, char c, struct syslogTime *stTime, time_t tt
*/
}
- if(( (c == '\n')
+ if(( ((c == '\n') && !pThis->pSrv->bDisableLFDelim)
|| ((pThis->pSrv->addtlFrameDelim != TCPSRV_NO_ADDTL_DELIMITER) && (c == pThis->pSrv->addtlFrameDelim))
) && pThis->eFraming == TCP_FRAMING_OCTET_STUFFING) { /* record delimiter? */
defaultDoSubmitMessage(pThis, stTime, ttGenTime, pMultiSub);
diff --git a/tcpsrv.c b/tcpsrv.c
index ef453f3a..fbb9446d 100644
--- a/tcpsrv.c
+++ b/tcpsrv.c
@@ -15,12 +15,9 @@
* callbacks before the code is run. The tcpsrv then calls back
* into the specific input modules at the appropriate time.
*
- * NOTE: read comments in module-template.h to understand how this file
- * works!
- *
* File begun on 2007-12-21 by RGerhards (extracted from syslogd.c)
*
- * Copyright 2007, 2008, 2009 Rainer Gerhards and Adiscon GmbH.
+ * Copyright 2007-2010 Rainer Gerhards and Adiscon GmbH.
*
* This file is part of rsyslog.
*
@@ -68,6 +65,7 @@
#include "netstrms.h"
#include "netstrm.h"
#include "nssel.h"
+#include "nspoll.h"
#include "errmsg.h"
#include "ruleset.h"
#include "unicode-helper.h"
@@ -89,6 +87,7 @@ DEFobjCurrIf(net)
DEFobjCurrIf(netstrms)
DEFobjCurrIf(netstrm)
DEFobjCurrIf(nssel)
+DEFobjCurrIf(nspoll)
DEFobjCurrIf(prop)
@@ -238,11 +237,13 @@ static void deinit_tcp_listener(tcpsrv_t *pThis)
if(pThis->pSessions != NULL) {
/* close all TCP connections! */
- i = TCPSessGetNxtSess(pThis, -1);
- while(i != -1) {
- tcps_sess.Destruct(&pThis->pSessions[i]);
- /* now get next... */
- i = TCPSessGetNxtSess(pThis, i);
+ if(!pThis->bUsingEPoll) {
+ i = TCPSessGetNxtSess(pThis, -1);
+ while(i != -1) {
+ tcps_sess.Destruct(&pThis->pSessions[i]);
+ /* now get next... */
+ i = TCPSessGetNxtSess(pThis, i);
+ }
}
/* we are done with the session table - so get rid of it... */
@@ -438,7 +439,8 @@ SessAccept(tcpsrv_t *pThis, tcpLstnPortList_t *pLstnInfo, tcps_sess_t **ppSess,
}
*ppSess = pSess;
- pThis->pSessions[iSess] = pSess;
+ if(!pThis->bUsingEPoll)
+ pThis->pSessions[iSess] = pSess;
pSess = NULL; /* this is now also handed over */
finalize_it:
@@ -465,11 +467,29 @@ RunCancelCleanup(void *arg)
}
+/* helper to close a session. Takes status of poll vs. select into consideration.
+ * rgerhards, 2009-11-25
+ */
+static inline rsRetVal
+closeSess(tcpsrv_t *pThis, tcps_sess_t **ppSess, nspoll_t *pPoll) {
+ DEFiRet;
+ if(pPoll != NULL) {
+ CHKiRet(nspoll.Ctl(pPoll, (*ppSess)->pStrm, 0, *ppSess, NSDPOLL_IN, NSDPOLL_DEL));
+ }
+ pThis->pOnRegularClose(*ppSess);
+ tcps_sess.Destruct(ppSess);
+finalize_it:
+ RETiRet;
+}
+
+
/* process a receive request on one of the streams
+ * If pPoll is non-NULL, we have a netstream in epoll mode, which means we need
+ * to remove any descriptor we close from the epoll set.
* rgerhards, 2009-07-020
*/
static rsRetVal
-doReceive(tcpsrv_t *pThis, tcps_sess_t **ppSess)
+doReceive(tcpsrv_t *pThis, tcps_sess_t **ppSess, nspoll_t *pPoll)
{
char buf[128*1024]; /* reception buffer - may hold a partial or multiple messages */
ssize_t iRcvd;
@@ -478,7 +498,6 @@ doReceive(tcpsrv_t *pThis, tcps_sess_t **ppSess)
ISOBJ_TYPE_assert(pThis, tcpsrv);
DBGPRINTF("netstream %p with new data\n", (*ppSess)->pStrm);
-
/* Receive message */
iRet = pThis->pRcvData(*ppSess, buf, sizeof(buf), &iRcvd);
switch(iRet) {
@@ -491,8 +510,7 @@ doReceive(tcpsrv_t *pThis, tcps_sess_t **ppSess)
errmsg.LogError(0, RS_RET_PEER_CLOSED_CONN, "Netstream session %p closed by remote peer %s.\n",
(*ppSess)->pStrm, pszPeer);
}
- pThis->pOnRegularClose(*ppSess);
- tcps_sess.Destruct(ppSess);
+ CHKiRet(closeSess(pThis, ppSess, pPoll));
break;
case RS_RET_RETRY:
/* we simply ignore retry - this is not an error, but we also have not received anything */
@@ -505,26 +523,29 @@ doReceive(tcpsrv_t *pThis, tcps_sess_t **ppSess)
*/
errmsg.LogError(0, localRet, "Tearing down TCP Session - see "
"previous messages for reason(s)\n");
- pThis->pOnErrClose(*ppSess);
- tcps_sess.Destruct(ppSess);
+ CHKiRet(closeSess(pThis, ppSess, pPoll));
}
break;
default:
errno = 0;
errmsg.LogError(0, iRet, "netstream session %p will be closed due to error\n",
(*ppSess)->pStrm);
- pThis->pOnErrClose(*ppSess);
- tcps_sess.Destruct(ppSess);
+ CHKiRet(closeSess(pThis, ppSess, pPoll));
break;
}
+
+finalize_it:
RETiRet;
}
-/* This function is called to gather input. */
+/* This function is called to gather input.
+ * This variant here is only used if we need to work with a netstream driver
+ * that does not support epoll().
+ */
#pragma GCC diagnostic ignored "-Wempty-body"
-static rsRetVal
-Run(tcpsrv_t *pThis)
+static inline rsRetVal
+RunSelect(tcpsrv_t *pThis)
{
DEFiRet;
int nfds;
@@ -532,7 +553,7 @@ Run(tcpsrv_t *pThis)
int iTCPSess;
int bIsReady;
tcps_sess_t *pNewSess;
- nssel_t *pSel;
+ nssel_t *pSel = NULL;
ISOBJ_TYPE_assert(pThis, tcpsrv);
@@ -583,7 +604,7 @@ Run(tcpsrv_t *pThis)
ABORT_FINALIZE(RS_RET_FORCE_TERM);
CHKiRet(nssel.IsReady(pSel, pThis->pSessions[iTCPSess]->pStrm, NSDSEL_RD, &bIsReady, &nfds));
if(bIsReady) {
- doReceive(pThis, &pThis->pSessions[iTCPSess]);
+ doReceive(pThis, &pThis->pSessions[iTCPSess], NULL);
--nfds; /* indicate we have processed one */
}
iTCPSess = TCPSessGetNxtSess(pThis, iTCPSess);
@@ -606,11 +627,93 @@ finalize_it: /* this is a very special case - this time only we do not exit the
#pragma GCC diagnostic warning "-Wempty-body"
+/* This function is called to gather input. It tries doing that via the epoll()
+ * interface. If the driver does not support that, it falls back to calling its
+ * select() equivalent.
+ * rgerhards, 2009-11-18
+ */
+static rsRetVal
+Run(tcpsrv_t *pThis)
+{
+ DEFiRet;
+ int i;
+ tcps_sess_t *pNewSess;
+ nspoll_t *pPoll = NULL;
+ void *pUsr;
+ rsRetVal localRet;
+
+ ISOBJ_TYPE_assert(pThis, tcpsrv);
+
+ /* this is an endless loop - it is terminated by the framework canelling
+ * this thread. Thus, we also need to instantiate a cancel cleanup handler
+ * to prevent us from leaking anything. -- rgerhards, 20080-04-24
+ */
+ if((localRet = nspoll.Construct(&pPoll)) == RS_RET_OK) {
+ // TODO: set driver
+ localRet = nspoll.ConstructFinalize(pPoll);
+ }
+ if(localRet != RS_RET_OK) {
+ /* fall back to select */
+ dbgprintf("tcpsrv could not use epoll() interface, iRet=%d, using select()\n", localRet);
+ iRet = RunSelect(pThis);
+ FINALIZE;
+ }
+
+ dbgprintf("tcpsrv uses epoll() interface, nsdpol driver found\n");
+
+ /* flag that we are in epoll mode */
+ pThis->bUsingEPoll = TRUE;
+
+ /* Add the TCP listen sockets to the list of sockets to monitor */
+ for(i = 0 ; i < pThis->iLstnCurr ; ++i) {
+ dbgprintf("Trying to add listener %d, pUsr=%p\n", i, pThis->ppLstn);
+ CHKiRet(nspoll.Ctl(pPoll, pThis->ppLstn[i], i, pThis->ppLstn, NSDPOLL_IN, NSDPOLL_ADD));
+ dbgprintf("Added listener %d\n", i);
+ }
+
+ while(1) {
+ localRet = nspoll.Wait(pPoll, -1, &i, &pUsr);
+ if(glbl.GetGlobalInputTermState() == 1)
+ break; /* terminate input! */
+
+ /* check if we need to ignore the i/o ready state. We do this if we got an invalid
+ * return state. Validly, this can happen for RS_RET_EINTR, for other cases it may
+ * not be the right thing, but what is the right thing is really hard at this point...
+ */
+ if(localRet != RS_RET_OK)
+ continue;
+
+ dbgprintf("poll returned with i %d, pUsr %p\n", i, pUsr);
+
+ if(pUsr == pThis->ppLstn) {
+ DBGPRINTF("New connect on NSD %p.\n", pThis->ppLstn[i]);
+ SessAccept(pThis, pThis->ppLstnPort[i], &pNewSess, pThis->ppLstn[i]);
+ CHKiRet(nspoll.Ctl(pPoll, pNewSess->pStrm, 0, pNewSess, NSDPOLL_IN, NSDPOLL_ADD));
+ DBGPRINTF("New session created with NSD %p.\n", pNewSess);
+ } else {
+ pNewSess = (tcps_sess_t*) pUsr;
+ doReceive(pThis, &pNewSess, pPoll);
+ }
+ }
+
+ /* remove the tcp listen sockets from the epoll set */
+ for(i = 0 ; i < pThis->iLstnCurr ; ++i) {
+ CHKiRet(nspoll.Ctl(pPoll, pThis->ppLstn[i], i, pThis->ppLstn, NSDPOLL_IN, NSDPOLL_DEL));
+ }
+
+finalize_it:
+ if(pPoll != NULL)
+ nspoll.Destruct(&pPoll);
+ RETiRet;
+}
+
+
/* Standard-Constructor */
BEGINobjConstruct(tcpsrv) /* be sure to specify the object type also in END macro! */
pThis->iSessMax = TCPSESS_MAX_DEFAULT;
pThis->iLstnMax = TCPLSTN_MAX_DEFAULT;
pThis->addtlFrameDelim = TCPSRV_NO_ADDTL_DELIMITER;
+ pThis->bDisableLFDelim = 0;
pThis->OnMsgReceive = NULL;
ENDobjConstruct(tcpsrv)
@@ -767,6 +870,18 @@ SetOnMsgReceive(tcpsrv_t *pThis, rsRetVal (*OnMsgReceive)(tcps_sess_t*, uchar*,
}
+/* set enable/disable standard LF frame delimiter (use with care!)
+ * -- rgerhards, 2010-01-03
+ */
+static rsRetVal
+SetbDisableLFDelim(tcpsrv_t *pThis, int bVal)
+{
+ DEFiRet;
+ ISOBJ_TYPE_assert(pThis, tcpsrv);
+ pThis->bDisableLFDelim = bVal;
+ RETiRet;
+}
+
/* Set additional framing to use (if any) -- rgerhards, 2008-12-10 */
static rsRetVal
@@ -908,7 +1023,6 @@ CODESTARTobjQueryInterface(tcpsrv)
pIf->ConstructFinalize = tcpsrvConstructFinalize;
pIf->Destruct = tcpsrvDestruct;
- //pIf->SessAccept = SessAccept;
pIf->configureTCPListen = configureTCPListen;
pIf->create_tcp_socket = create_tcp_socket;
pIf->Run = Run;
@@ -916,6 +1030,7 @@ CODESTARTobjQueryInterface(tcpsrv)
pIf->SetUsrP = SetUsrP;
pIf->SetInputName = SetInputName;
pIf->SetAddtlFrameDelim = SetAddtlFrameDelim;
+ pIf->SetbDisableLFDelim = SetbDisableLFDelim;
pIf->SetSessMax = SetSessMax;
pIf->SetLstnMax = SetLstnMax;
pIf->SetDrvrMode = SetDrvrMode;
@@ -969,6 +1084,7 @@ BEGINObjClassInit(tcpsrv, 1, OBJ_IS_LOADABLE_MODULE) /* class, version - CHANGE
CHKiRet(objUse(netstrms, LM_NETSTRMS_FILENAME));
CHKiRet(objUse(netstrm, DONT_LOAD_LIB));
CHKiRet(objUse(nssel, DONT_LOAD_LIB));
+ CHKiRet(objUse(nspoll, DONT_LOAD_LIB));
CHKiRet(objUse(tcps_sess, DONT_LOAD_LIB));
CHKiRet(objUse(conf, CORE_COMPONENT));
CHKiRet(objUse(glbl, CORE_COMPONENT));
diff --git a/tcpsrv.h b/tcpsrv.h
index b8d82163..57bdf4b1 100644
--- a/tcpsrv.h
+++ b/tcpsrv.h
@@ -54,7 +54,8 @@ struct tcpsrv_s {
uchar *pszInputName; /**< value to be used as input name */
ruleset_t *pRuleset; /**< ruleset to bind to */
permittedPeers_t *pPermPeers;/**< driver's permitted peers */
- bool bEmitMsgOnClose; /**< emit an informational message when the remote peer closes connection */
+ sbool bEmitMsgOnClose; /**< emit an informational message when the remote peer closes connection */
+ sbool bUsingEPoll; /**< are we in epoll mode (means we do not need to keep track of sessions!) */
int iLstnCurr; /**< max nbr of listeners currently supported */
netstrm_t **ppLstn; /**< our netstream listners */
tcpLstnPortList_t **ppLstnPort; /**< pointer to relevant listen port description */
@@ -63,6 +64,7 @@ struct tcpsrv_s {
tcpLstnPortList_t *pLstnPorts; /**< head pointer for listen ports */
int addtlFrameDelim; /**< additional frame delimiter for plain TCP syslog framing (e.g. to handle NetScreen) */
+ int bDisableLFDelim; /**< if 1, standard LF frame delimiter is disabled (*very dangerous*) */
tcps_sess_t **pSessions;/**< array of all of our sessions */
void *pUsr; /**< a user-settable pointer (provides extensibility for "derived classes")*/
/* callbacks */
@@ -114,11 +116,13 @@ BEGINinterface(tcpsrv) /* name must also be changed in ENDinterface macro! */
/* added v6 */
rsRetVal (*SetOnMsgReceive)(tcpsrv_t *pThis, rsRetVal (*OnMsgReceive)(tcps_sess_t*, uchar*, int)); /* 2009-05-24 */
rsRetVal (*SetRuleset)(tcpsrv_t *pThis, ruleset_t*); /* 2009-06-12 */
- /* added v7 */
+ /* added v7 (accidently named v8!) */
rsRetVal (*SetLstnMax)(tcpsrv_t *pThis, int iMaxLstn); /* 2009-08-17 */
rsRetVal (*SetNotificationOnRemoteClose)(tcpsrv_t *pThis, int bNewVal); /* 2009-10-01 */
+ /* added v9 -- rgerhards, 2010-03-01 */
+ rsRetVal (*SetbDisableLFDelim)(tcpsrv_t*, int);
ENDinterface(tcpsrv)
-#define tcpsrvCURR_IF_VERSION 8 /* increment whenever you change the interface structure! */
+#define tcpsrvCURR_IF_VERSION 9 /* increment whenever you change the interface structure! */
/* change for v4:
* - SetAddtlFrameDelim() added -- rgerhards, 2008-12-10
* - SetInputName() added -- rgerhards, 2008-12-10
diff --git a/template.c b/template.c
index 050905b0..3c04aefa 100644
--- a/template.c
+++ b/template.c
@@ -61,7 +61,6 @@ static inline rsRetVal ExtendBuf(uchar **pBuf, size_t *pLenBuf, size_t iMinSize)
CHKmalloc(pNewBuf = (uchar*) realloc(*pBuf, iNewSize));
*pBuf = pNewBuf;
*pLenBuf = iNewSize;
-dbgprintf("extend buf to at least %ld, done %ld\n", iMinSize, iNewSize);
finalize_it:
RETiRet;
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 6e577b18..32765ae4 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,6 +1,6 @@
if ENABLE_TESTBENCH
TESTRUNS = rt_init rscript
-check_PROGRAMS = $(TESTRUNS) ourtail nettester tcpflood chkseq
+check_PROGRAMS = $(TESTRUNS) ourtail nettester tcpflood chkseq msleep randomgen diagtalker
TESTS = $(TESTRUNS) cfg.sh \
arrayqueue.sh \
linkedlistqueue.sh \
@@ -36,6 +36,8 @@ TESTS = $(TESTRUNS) cfg.sh \
pipeaction.sh \
pipe_noreader.sh \
execonlyonce.sh \
+ dircreate_dflt.sh \
+ dircreate_off.sh \
queue-persist.sh
if ENABLE_OMUDPSPOOF
@@ -53,6 +55,8 @@ TESTS += omod-if-array.sh \
threadingmqaq.sh \
discard.sh \
badqi.sh \
+ tabescape_dflt.sh \
+ tabescape_off.sh \
fieldtest.sh
endif
@@ -61,12 +65,14 @@ TESTS += omruleset.sh \
omruleset-queue.sh
endif
-check_JAVA = DiagTalker.java
+if ENABLE_EXTENDED_TESTS
+TESTS += random.sh
+endif
endif # if ENABLE_TESTBENCH
TESTS_ENVIRONMENT = RSYSLOG_MODDIR='$(abs_top_builddir)'/runtime/.libs/
-DISTCLEANFILES=rsyslog.pid '$(abs_top_builddir)'/DiagTalker.class
+DISTCLEANFILES=rsyslog.pid
test_files = testbench.h runtime-dummy.c
EXTRA_DIST= 1.rstest 2.rstest 3.rstest err1.rstest \
@@ -109,12 +115,17 @@ EXTRA_DIST= 1.rstest 2.rstest 3.rstest err1.rstest \
testsuites/master.tspgsql \
testsuites/subsecond.conf \
testsuites/master.subsecond \
+ testsuites/parse_8bit_escape.conf \
+ testsuites/8bit.parse_8bit_escape \
testsuites/parse1.conf \
testsuites/field1.conf \
testsuites/1.parse1 \
testsuites/2.parse1 \
testsuites/3.parse1 \
testsuites/4.parse1 \
+ testsuites/mark.parse1 \
+ testsuites/8bit.parse1 \
+ testsuites/empty.parse1 \
testsuites/snare.parse1 \
testsuites/oversizeTag-1.parse1 \
testsuites/weird.parse1 \
@@ -135,6 +146,7 @@ EXTRA_DIST= 1.rstest 2.rstest 3.rstest err1.rstest \
testsuites/parse3.conf \
testsuites/reallife.parse3 \
testsuites/parse-nodate.conf \
+ testsuites/samples.parse-nodate \
testsuites/parse_invld_regex.conf \
testsuites/samples.parse_invld_regex \
testsuites/parse-3164-buggyday.conf \
@@ -232,6 +244,8 @@ EXTRA_DIST= 1.rstest 2.rstest 3.rstest err1.rstest \
testsuites/gzipwr_large_dynfile.conf \
complex1.sh \
testsuites/complex1.conf \
+ random.sh \
+ testsuites/random.conf \
dynfile_invld_async.sh \
dynfile_invld_sync.sh \
dynfile_cachemiss.sh \
@@ -255,15 +269,31 @@ EXTRA_DIST= 1.rstest 2.rstest 3.rstest err1.rstest \
execonlyonce.sh \
testsuites/execonlyonce.conf \
testsuites/execonlyonce.data \
- DiagTalker.java \
+ tabescape_dflt.sh \
+ testsuites/tabescape_dflt.conf \
+ testsuites/1.tabescape_dflt \
+ tabescape_off.sh \
+ testsuites/tabescape_off.conf \
+ testsuites/1.tabescape_off \
+ dircreate_dflt.sh \
+ testsuites/dircreate_dflt.conf \
+ dircreate_off.sh \
+ testsuites/dircreate_off.conf \
cfg.sh
ourtail_SOURCES = ourtail.c
+msleep_SOURCES = msleep.c
chkseq_SOURCES = chkseq.c
tcpflood_SOURCES = tcpflood.c
tcpflood_LDADD = $(SOL_LIBS)
+diagtalker_SOURCES = diagtalker.c
+diagtalker_LDADD = $(SOL_LIBS)
+
+randomgen_SOURCES = randomgen.c
+randomgen_LDADD = $(SOL_LIBS)
+
nettester_SOURCES = nettester.c getline.c
nettester_LDADD = $(SOL_LIBS)
diff --git a/tests/complex1.sh b/tests/complex1.sh
index b5dc2c9d..b3e31b30 100755
--- a/tests/complex1.sh
+++ b/tests/complex1.sh
@@ -7,15 +7,16 @@ echo ===========================================================================
echo TEST: \[complex1.sh\]: complex test with gzip and multiple action queues
source $srcdir/diag.sh init
# uncomment for debugging support:
-export RSYSLOG_DEBUG="debug nostdout"
-export RSYSLOG_DEBUGLOG="log"
+#export RSYSLOG_DEBUG="debug nostdout"
+#export RSYSLOG_DEBUGLOG="log"
source $srcdir/diag.sh startup complex1.conf
-# send 30,000 messages of 400 bytes plus header max, via three dest ports
+# send 40,000 messages of 400 bytes plus header max, via three dest ports
source $srcdir/diag.sh tcpflood -m40000 -rd400 -P129 -f5 -n3 -c15 -i1
sleep 2 # due to large messages, we need this time for the tcp receiver to settle...
source $srcdir/diag.sh shutdown-when-empty # shut down rsyslogd when done processing messages
source $srcdir/diag.sh wait-shutdown # and wait for it to terminate
ls rsyslog.out.*.log
-zcat rsyslog.out.*.log > rsyslog.out.log
+source $srcdir/diag.sh setzcat # find out which zcat to use
+$ZCAT rsyslog.out.*.log > rsyslog.out.log
source $srcdir/diag.sh seq-check 1 40000 -E
source $srcdir/diag.sh exit
diff --git a/tests/diag.sh b/tests/diag.sh
index 61766221..5b74a6dc 100755
--- a/tests/diag.sh
+++ b/tests/diag.sh
@@ -10,28 +10,26 @@
#valgrind="valgrind --tool=helgrind --log-fd=1"
#valgrind="valgrind --tool=exp-ptrcheck --log-fd=1"
#set -o xtrace
-#export RSYSLOG_DEBUG="debug nostdout noprintmutexaction"
+#export RSYSLOG_DEBUG="debug nostdout"
#export RSYSLOG_DEBUGLOG="log"
case $1 in
'init') $srcdir/killrsyslog.sh # kill rsyslogd if it runs for some reason
cp $srcdir/testsuites/diag-common.conf diag-common.conf
cp $srcdir/testsuites/diag-common2.conf diag-common2.conf
rm -f rsyslog.action.*.include
- rm -f rsyslogd.started work-*.conf
+ rm -f rsyslogd.started work-*.conf rsyslog.random.data
rm -f rsyslogd2.started work-*.conf
rm -f work rsyslog.out.log rsyslog.out.log.save # common work files
- rm -f rsyslog.out.*.log
- rm -rf test-spool
- rm -f rsyslog.pipe
+ rm -rf test-spool test-logdir
+ rm -f rsyslog.out.*.log work-presort rsyslog.pipe
rm -f core.* vgcore.*
mkdir test-spool
;;
'exit') rm -f rsyslogd.started work-*.conf diag-common.conf
rm -f rsyslogd2.started diag-common2.conf rsyslog.action.*.include
rm -f work rsyslog.out.log rsyslog.out.log.save # common work files
- rm -f rsyslog.out.*.log
- rm -rf test-spool
- rm -f rsyslog.pipe
+ rm -rf test-spool test-logdir
+ rm -f rsyslog.out.*.log rsyslog.random.data work-presort rsyslog.pipe
echo -------------------------------------------------------------------------------
;;
'startup') # start rsyslogd with default params. $2 is the config file name to use
@@ -40,17 +38,18 @@ case $1 in
$srcdir/diag.sh wait-startup $3
;;
'wait-startup') # wait for rsyslogd startup ($2 is the instance)
+ while test ! -f rsyslog$2.pid; do
+ ./msleep 100 # wait 100 milliseconds
+ done
while test ! -f rsyslogd$2.started; do
- #true
- sleep 0.1 # if this is not supported by all platforms, use above!
+ ./msleep 100 # wait 100 milliseconds
done
echo "rsyslogd$2 started with pid " `cat rsyslog$2.pid`
;;
'wait-shutdown') # actually, we wait for rsyslog.pid to be deleted. $2 is the
# instance
while test -f rsyslog$2.pid; do
- #true
- sleep 0.1 # if this is not supported by all platforms, use above!
+ ./msleep 100 # wait 100 milliseconds
done
if [ -e core.* ]
then
@@ -62,9 +61,9 @@ case $1 in
'wait-queueempty') # wait for main message queue to be empty. $2 is the instance.
if [ "$2" == "2" ]
then
- echo WaitMainQueueEmpty | java -classpath $abs_top_builddir DiagTalker
+ echo WaitMainQueueEmpty | ./diagtalker
else
- echo WaitMainQueueEmpty | java -classpath $abs_top_builddir DiagTalker 13501
+ echo WaitMainQueueEmpty | ./diagtalker
fi
;;
'shutdown-when-empty') # shut rsyslogd down when main queue is empty. $2 is the instance.
@@ -86,7 +85,7 @@ case $1 in
;;
'injectmsg') # inject messages via our inject interface (imdiag)
echo injecting $3 messages
- echo injectmsg $2 $3 $4 $5 | java -classpath $abs_top_builddir DiagTalker
+ echo injectmsg $2 $3 $4 $5 | ./diagtalker
# TODO: some return state checking? (does it really make sense here?)
;;
'check-mainq-spool') # check if mainqueue spool files exist, if not abort (we just check .qi).
@@ -141,5 +140,12 @@ case $1 in
exit 1
fi
;;
+ 'setzcat') # find out name of zcat tool
+ if [ `uname` == SunOS ]; then
+ ZCAT=gzcat
+ else
+ ZCAT=zcat
+ fi
+ ;;
*) echo "invalid argument" $1
esac
diff --git a/tests/diagtalker.c b/tests/diagtalker.c
new file mode 100644
index 00000000..6a721e47
--- /dev/null
+++ b/tests/diagtalker.c
@@ -0,0 +1,157 @@
+/* A yet very simple tool to talk to imdiag (this replaces the
+ * previous Java implementation in order to get fewer dependencies).
+ *
+ * Copyright 2010 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 <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+
+static char *targetIP = "127.0.0.1";
+static int targetPort = 13500;
+
+
+/* open a single tcp connection
+ */
+int openConn(int *fd)
+{
+ int sock;
+ struct sockaddr_in addr;
+ int port;
+ int retries = 0;
+
+ if((sock=socket(AF_INET, SOCK_STREAM, 0))==-1) {
+ perror("socket()");
+ exit(1);
+ }
+
+ port = targetPort;
+ memset((char *) &addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ if(inet_aton(targetIP, &addr.sin_addr)==0) {
+ fprintf(stderr, "inet_aton() failed\n");
+ exit(1);
+ }
+ while(1) { /* loop broken inside */
+ if(connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == 0) {
+ break;
+ } else {
+ if(retries++ == 50) {
+ perror("connect()");
+ fprintf(stderr, "connect() failed\n");
+ exit(1);
+ } else {
+ fprintf(stderr, "connect failed, retrying...\n");
+ usleep(100000); /* ms = 1000 us! */
+ }
+ }
+ }
+
+ *fd = sock;
+ return 0;
+}
+
+
+/* send a string
+ */
+static void
+sendCmd(int fd, char *buf, int len)
+{
+ int lenSend;
+
+ lenSend = send(fd, buf, len, 0);
+ if(lenSend != len) {
+ perror("sending string");
+ exit(1);
+ }
+}
+
+
+/* wait for a response from remote system
+ */
+static void
+waitRsp(int fd, char *buf, int len)
+{
+ int ret;
+
+ ret = recv(fd, buf, len - 1, 0);
+ if(ret < 0) {
+ perror("receiving response");
+ exit(1);
+ }
+ /* we assume the message was complete, it may be better to wait
+ * for a LF...
+ */
+ buf[ret] = '\0';
+}
+
+
+/* do the actual processing
+ */
+static void
+doProcessing()
+{
+ int fd;
+ int len;
+ char line[2048];
+
+ openConn(&fd);
+ while(!feof(stdin)) {
+ if(fgets(line, sizeof(line) - 1, stdin) == NULL)
+ break;
+ len = strlen(line);
+ sendCmd(fd, line, len);
+ waitRsp(fd, line, sizeof(line));
+ printf("imdiag: %s", line);
+ }
+}
+
+
+/* Run the test.
+ * rgerhards, 2009-04-03
+ */
+int main(int argc, char *argv[])
+{
+ int ret = 0;
+ int opt;
+
+ while((opt = getopt(argc, argv, "f:t:p:c:C:m:i:I:P:d:n:M:rB")) != -1) {
+ switch (opt) {
+ case 't': targetIP = optarg;
+ break;
+ case 'p': targetPort = atoi(optarg);
+ break;
+ default: printf("invalid option '%c' or value missing - terminating...\n", opt);
+ exit (1);
+ break;
+ }
+ }
+
+ doProcessing();
+
+ exit(ret);
+}
diff --git a/tests/dircreate_dflt.sh b/tests/dircreate_dflt.sh
new file mode 100755
index 00000000..71a671f3
--- /dev/null
+++ b/tests/dircreate_dflt.sh
@@ -0,0 +1,20 @@
+# Test for automatic creation of dynafile directories
+# note that we use the "test-spool" directory, because it is handled by diag.sh
+# in any case, so we do not need to add any extra new test dir.
+# added 2009-11-30 by Rgerhards
+# This file is part of the rsyslog project, released under GPLv3
+# uncomment for debugging support:
+echo ===================================================================================
+echo \[dircreate_dflt_dflt.sh\]: testing automatic directory creation for dynafiles - default
+source $srcdir/diag.sh init
+source $srcdir/diag.sh startup dircreate_dflt.conf
+source $srcdir/diag.sh injectmsg 0 1 # a single message is sufficient
+source $srcdir/diag.sh shutdown-when-empty # shut down rsyslogd when done processing messages
+source $srcdir/diag.sh wait-shutdown
+if [ ! -e test-logdir/rsyslog.out.log ]
+then
+ echo "test-logdir or logfile not created!"
+ exit 1
+fi
+exit
+source $srcdir/diag.sh exit
diff --git a/tests/dircreate_off.sh b/tests/dircreate_off.sh
new file mode 100755
index 00000000..92fdee01
--- /dev/null
+++ b/tests/dircreate_off.sh
@@ -0,0 +1,20 @@
+# Test for automatic creation of dynafile directories
+# note that we use the "test-spool" directory, because it is handled by diag.sh
+# in any case, so we do not need to add any extra new test dir.
+# added 2009-11-30 by Rgerhards
+# This file is part of the rsyslog project, released under GPLv3
+# uncomment for debugging support:
+echo ===================================================================================
+echo \[dircreate_off_off.sh\]: testing automatic directory creation for dynafiles - default
+source $srcdir/diag.sh init
+source $srcdir/diag.sh startup dircreate_off.conf
+source $srcdir/diag.sh injectmsg 0 1 # a single message is sufficient
+source $srcdir/diag.sh shutdown-when-empty # shut down rsyslogd when done processing messages
+source $srcdir/diag.sh wait-shutdown
+if [ -e test-logdir/rsyslog.out.log ]
+then
+ echo "test-logdir or logfile WAS created where not permitted to!"
+ exit 1
+fi
+exit
+source $srcdir/diag.sh exit
diff --git a/tests/dynfile_invalid2.sh b/tests/dynfile_invalid2.sh
index b6fb3945..cb3ef51e 100755
--- a/tests/dynfile_invalid2.sh
+++ b/tests/dynfile_invalid2.sh
@@ -9,8 +9,8 @@ echo ===========================================================================
echo TEST: \[dynfile_invalid2.sh\]: test open fail for dynafiles
source $srcdir/diag.sh init
# uncomment for debugging support:
-export RSYSLOG_DEBUG="debug nostdout noprintmutexaction"
-export RSYSLOG_DEBUGLOG="log"
+#export RSYSLOG_DEBUG="debug nostdout noprintmutexaction"
+#export RSYSLOG_DEBUGLOG="log"
source $srcdir/diag.sh startup dynfile_invalid2.conf
# we send handcrafted message. We have a dynafile cache of 4, and now send one message
# each to fill up the cache.
diff --git a/tests/gzipwr_large_dynfile.sh b/tests/gzipwr_large_dynfile.sh
index ebd4c558..73d44796 100755
--- a/tests/gzipwr_large_dynfile.sh
+++ b/tests/gzipwr_large_dynfile.sh
@@ -18,8 +18,8 @@ echo ===========================================================================
echo TEST: \[gzipwr_large_dynfile.sh\]: test for gzip file writing for large message sets
source $srcdir/diag.sh init
# uncomment for debugging support:
-export RSYSLOG_DEBUG="debug nostdout"
-export RSYSLOG_DEBUGLOG="log"
+#export RSYSLOG_DEBUG="debug nostdout"
+#export RSYSLOG_DEBUGLOG="log"
source $srcdir/diag.sh startup gzipwr_large_dynfile.conf
# send 4000 messages of 10.000bytes plus header max, randomized
source $srcdir/diag.sh tcpflood -m4000 -r -d10000 -P129 -f5
diff --git a/tests/DiagTalker.java b/tests/historical/DiagTalker.java
index 5a6f7dd5..147cec34 100644
--- a/tests/DiagTalker.java
+++ b/tests/historical/DiagTalker.java
@@ -1,3 +1,4 @@
+This tool has been replaced by ./tests/diagtalker.c in release 4.7.1
/* A yet very simple tool to talk to imdiag.
*
* Copyright 2009 Rainer Gerhards and Adiscon GmbH.
diff --git a/tests/historical/README b/tests/historical/README
new file mode 100644
index 00000000..5f10ecef
--- /dev/null
+++ b/tests/historical/README
@@ -0,0 +1,2 @@
+This directory contains tools that are currently not being used, but are
+kept because they may be used again in the future.
diff --git a/tests/msleep.c b/tests/msleep.c
new file mode 100644
index 00000000..36fa01b5
--- /dev/null
+++ b/tests/msleep.c
@@ -0,0 +1,51 @@
+/* sleeps for the specified number of MILLIseconds.
+ * Primarily meant as a portable tool available everywhere for the
+ * testbench (sleep 0.1 does not work on all platforms).
+ *
+ * Part of the testbench for rsyslog.
+ *
+ * Copyright 2010 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 <stdlib.h>
+#include <time.h>
+
+int main(int argc, char *argv[])
+{
+ struct timeval tvSelectTimeout;
+ long sleepTime;
+
+ if(argc != 2) {
+ fprintf(stderr, "usage: msleep <milliseconds>\n");
+ exit(1);
+ }
+
+ sleepTime = atoi(argv[1]);
+ tvSelectTimeout.tv_sec = sleepTime / 1000;
+ tvSelectTimeout.tv_usec = (sleepTime % 1000) * 1000; /* micro seconds */
+ if(select(0, NULL, NULL, NULL, &tvSelectTimeout) == -1) {
+ perror("select");
+ exit(1);
+ }
+
+ return 0;
+}
+
diff --git a/tests/nettester.c b/tests/nettester.c
index 6932381e..7c8c413a 100644
--- a/tests/nettester.c
+++ b/tests/nettester.c
@@ -64,7 +64,7 @@ static int iPort = 12514; /* port which shall be used for sending data */
static char* pszCustomConf = NULL; /* custom config file, use -c conf to specify */
static int verbose = 0; /* verbose output? -v option */
static int IPv4Only = 0; /* use only IPv4 in rsyslogd call? */
-static int useDebugEnv = 0; /* activate debugging environment (for rsyslog debug log)? */
+static char **ourEnvp;
/* these two are quick hacks... */
int iFailed = 0;
@@ -125,6 +125,10 @@ void readLine(int fd, char *ln)
* We use traditional framing '\n' at EOR for this tester. It may be
* worth considering additional framing modes.
* rgerhards, 2009-04-08
+ * Note: we re-create the socket within the retry loop, because this
+ * seems to be needed under Solaris. If we do not do that, we run
+ * into troubles (maybe something wrongly initialized then?)
+ * -- rgerhards, 2010-04-12
*/
int
tcpSend(char *buf, int lenBuf)
@@ -132,30 +136,34 @@ tcpSend(char *buf, int lenBuf)
static int sock = INVALID_SOCKET;
struct sockaddr_in addr;
int retries;
+ int ret;
+ int iRet = 0; /* 0 OK, anything else error */
if(sock == INVALID_SOCKET) {
/* first time, need to connect to target */
- if((sock=socket(AF_INET, SOCK_STREAM, 0))==-1) {
- perror("socket()");
- return(1);
- }
-
- memset((char *) &addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_port = htons(iPort);
- if(inet_aton("127.0.0.1", &addr.sin_addr)==0) {
- fprintf(stderr, "inet_aton() failed\n");
- return(1);
- }
retries = 0;
while(1) { /* loop broken inside */
- if(connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == 0) {
+ /* first time, need to connect to target */
+ if((sock=socket(AF_INET, SOCK_STREAM, 0))==-1) {
+ perror("socket()");
+ iRet = 1;
+ goto finalize_it;
+ }
+ memset((char *) &addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(iPort);
+ if(inet_aton("127.0.0.1", &addr.sin_addr)==0) {
+ fprintf(stderr, "inet_aton() failed\n");
+ iRet = 1;
+ goto finalize_it;
+ }
+ if((ret = connect(sock, (struct sockaddr*)&addr, sizeof(addr))) == 0) {
break;
} else {
if(retries++ == 50) {
- ++iFailed;
fprintf(stderr, "connect() failed\n");
- return(1);
+ iRet = 1;
+ goto finalize_it;
} else {
usleep(100000); /* ms = 1000 us! */
}
@@ -164,20 +172,32 @@ tcpSend(char *buf, int lenBuf)
}
/* send test data */
- if(send(sock, buf, lenBuf, 0) != lenBuf) {
+ if((ret = send(sock, buf, lenBuf, 0)) != lenBuf) {
perror("send test data");
- fprintf(stderr, "send() failed\n");
- return(1);
+ fprintf(stderr, "send() failed, sock=%d, ret=%d\n", sock, ret);
+ iRet = 1;
+ goto finalize_it;
}
/* send record terminator */
if(send(sock, "\n", 1, 0) != 1) {
perror("send record terminator");
fprintf(stderr, "send() failed\n");
- return(1);
+ iRet = 1;
+ goto finalize_it;
}
- return 0;
+finalize_it:
+ if(iRet != 0) {
+ /* need to do some (common) cleanup */
+ if(sock != INVALID_SOCKET) {
+ close(sock);
+ sock = INVALID_SOCKET;
+ }
+ ++iFailed;
+ }
+
+ return iRet;
}
@@ -226,9 +246,6 @@ int openPipe(char *configFile, pid_t *pid, int *pfd)
char *newargv[] = {"../tools/rsyslogd", "dummy", "-c4", "-u2", "-n", "-irsyslog.pid",
"-M../runtime/.libs:../.libs", NULL, NULL};
char confFile[1024];
- char *newenviron[] = { NULL };
- char *newenvironDeb[] = { "RSYSLOG_DEBUG=debug nostdout",
- "RSYSLOG_DEBUGLOG=log", NULL };
sprintf(confFile, "-f%s/testsuites/%s.conf", srcdir,
(pszCustomConf == NULL) ? configFile : pszCustomConf);
@@ -254,8 +271,9 @@ int openPipe(char *configFile, pid_t *pid, int *pfd)
close(pipefd[1]);
close(pipefd[0]);
fclose(stdin);
- execve("../tools/rsyslogd", newargv, (useDebugEnv) ? newenvironDeb : newenviron);
+ execve("../tools/rsyslogd", newargv, ourEnvp);
} else {
+ usleep(10000);
close(pipefd[1]);
*pid = cpid;
*pfd = pipefd[0];
@@ -375,6 +393,7 @@ processTestFile(int fd, char *pszFileName)
expected[strlen(expected)-1] = '\0'; /* remove \n */
/* pull response from server and then check if it meets our expectation */
+//printf("try pull pipe...\n");
readLine(fd, buf);
if(strlen(buf) == 0) {
printf("something went wrong - read a zero-length string from rsyslogd\n");
@@ -441,7 +460,8 @@ doTests(int fd, char *files)
printf("Error: no test cases found, no tests executed.\n");
iFailed = 1;
} else {
- printf("Number of tests run: %d, number of failures: %d\n", iTests, iFailed);
+ printf("Number of tests run: %3d, number of failures: %d, test: %s/%s\n",
+ iTests, iFailed, testSuite, inputMode2Str(inputMode));
}
return(iFailed);
@@ -478,7 +498,7 @@ void doAtExit(void)
* of this file.
* rgerhards, 2009-04-03
*/
-int main(int argc, char *argv[])
+int main(int argc, char *argv[], char *envp[])
{
int fd;
int opt;
@@ -487,7 +507,8 @@ int main(int argc, char *argv[])
char buf[4096];
char testcases[4096];
- while((opt = getopt(argc, argv, "4dc:i:p:t:v")) != EOF) {
+ ourEnvp = envp;
+ while((opt = getopt(argc, argv, "4c:i:p:t:v")) != EOF) {
switch((char)opt) {
case '4':
IPv4Only = 1;
@@ -495,9 +516,6 @@ int main(int argc, char *argv[])
case 'c':
pszCustomConf = optarg;
break;
- case 'd':
- useDebugEnv = 1;
- break;
case 'i':
if(!strcmp(optarg, "udp"))
inputMode = inputUDP;
@@ -554,6 +572,11 @@ int main(int argc, char *argv[])
/* arm died-child handler */
signal(SIGCHLD, childDied);
+ /* make sure we do not abort if there is an issue with pipes.
+ * our code does the necessary error handling.
+ */
+ sigset(SIGPIPE, SIG_IGN);
+
/* start to be tested rsyslogd */
openPipe(testSuite, &rsyslogdPid, &fd);
readLine(fd, buf);
diff --git a/tests/parsertest.sh b/tests/parsertest.sh
index 28f4b088..9f9c2f74 100755
--- a/tests/parsertest.sh
+++ b/tests/parsertest.sh
@@ -4,6 +4,8 @@ source $srcdir/diag.sh nettester parse1 udp
source $srcdir/diag.sh nettester parse1 tcp
source $srcdir/diag.sh nettester parse2 udp
source $srcdir/diag.sh nettester parse2 tcp
+source $srcdir/diag.sh nettester parse_8bit_escape udp
+source $srcdir/diag.sh nettester parse_8bit_escape tcp
source $srcdir/diag.sh nettester parse3 udp
source $srcdir/diag.sh nettester parse3 tcp
source $srcdir/diag.sh nettester parse_invld_regex udp
@@ -22,6 +24,8 @@ source $srcdir/diag.sh nettester parse1 udp -4
source $srcdir/diag.sh nettester parse1 tcp -4
source $srcdir/diag.sh nettester parse2 udp -4
source $srcdir/diag.sh nettester parse2 tcp -4
+source $srcdir/diag.sh nettester parse_8bit_escape udp -4
+source $srcdir/diag.sh nettester parse_8bit_escape tcp -4
source $srcdir/diag.sh nettester parse3 udp -4
source $srcdir/diag.sh nettester parse3 tcp -4
source $srcdir/diag.sh nettester parse_invld_regex udp -4
diff --git a/tests/random.sh b/tests/random.sh
new file mode 100755
index 00000000..d1f392d3
--- /dev/null
+++ b/tests/random.sh
@@ -0,0 +1,20 @@
+# Test if rsyslog survives sending truely random data to it...
+#
+# added 2010-04-01 by Rgerhards
+# This file is part of the rsyslog project, released under GPLv3
+echo ===============================================================================
+echo TEST: \[random.sh\]: testing random data
+source $srcdir/diag.sh init
+# uncomment for debugging support:
+#export RSYSLOG_DEBUG="debug nostdout noprintmutexaction"
+#export RSYSLOG_DEBUGLOG="log"
+source $srcdir/diag.sh startup random.conf
+# generate random data
+./randomgen -f rsyslog.random.data -s 100000
+ls -l rsyslog.random.data
+source $srcdir/diag.sh tcpflood -B -I rsyslog.random.data -c5 -C10
+source $srcdir/diag.sh shutdown-when-empty # shut down rsyslogd when done processing messages
+source $srcdir/diag.sh wait-shutdown # and wait for it to terminate
+# we do not check anything yet, the point is if rsyslog survived ;)
+# TODO: check for exit message, but we'll notice an abort anyhow, so not that important
+source $srcdir/diag.sh exit
diff --git a/tests/randomgen.c b/tests/randomgen.c
new file mode 100644
index 00000000..9ba56954
--- /dev/null
+++ b/tests/randomgen.c
@@ -0,0 +1,130 @@
+/* generates random data for later use in test cases. Of course,
+ * we could generate random data during the testcase itself, but
+ * the core idea is that we record the random data so that we have
+ * a chance to reproduce a problem should it occur. IMHO this
+ * provides the best compromise, by a) having randomness but
+ * b) knowing what was used during the test.
+ *
+ * Params
+ * -f output file name (stdout if not given)
+ * -s size of test data, plain number is size in k, 1MB default
+ * -u uses /dev/urandom instead of libc random number generator
+ * (when available). Note that this is usually much slower.
+ *
+ * Part of the testbench for rsyslog.
+ *
+ * Copyright 2010 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 <stdlib.h>
+#include <time.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <assert.h>
+#include <unistd.h>
+#include <string.h>
+#include <netinet/in.h>
+
+#define EXIT_FAILURE 1
+
+static char *fileName = NULL; /* name of output file */
+static int tryUseURandom = 0; /* try to use /dev/urandom? */
+static long long fileSize = 1024*1024; /* file size in K, 1MB default */
+
+
+/* generate the random file. This code really can be improved (e.g. read /dev/urandom
+ * when available)
+ */
+static inline void
+genFile()
+{
+ long i;
+ FILE *fp;
+ FILE *rfp = NULL;
+
+ if(fileName == NULL) {
+ fp = stdout;
+ } else {
+ if((fp = fopen(fileName, "w")) == NULL) {
+ perror(fileName);
+ }
+ }
+
+ /* try to use /dev/urandom, if available */
+ if(tryUseURandom)
+ rfp = fopen("/dev/urandom", "r");
+
+ if(rfp == NULL) {
+ /* fallback, use libc random number generator */
+ for(i = 0 ; i < fileSize ; ++i) {
+ if(fputc((char) rand(), fp) == EOF) {
+ perror(fileName);
+ exit(1);
+ }
+ }
+ } else {
+ /* use /dev/urandom */
+ printf("using /dev/urandom");
+ for(i = 0 ; i < fileSize ; ++i) {
+ if(fputc(fgetc(rfp), fp) == EOF) {
+ perror(fileName);
+ exit(1);
+ }
+ }
+ }
+
+ if(fileName != NULL)
+ fclose(fp);
+}
+
+
+/* Run the test.
+ * rgerhards, 2009-04-03
+ */
+int main(int argc, char *argv[])
+{
+ int ret = 0;
+ int opt;
+
+ srand(time(NULL)); /* seed is good enough for our needs */
+
+ while((opt = getopt(argc, argv, "f:s:u")) != -1) {
+ switch (opt) {
+ case 'f': fileName = optarg;
+ break;
+ case 's': fileSize = atol(optarg) * 1024;
+ break;
+ case 'u': tryUseURandom = 1;
+ break;
+ default: printf("invalid option '%c' or value missing - terminating...\n", opt);
+ exit (1);
+ break;
+ }
+ }
+
+ printf("generating random data file '%s' of %ldkb - may take a short while...\n",
+ fileName, (long) (fileSize / 1024));
+ genFile();
+
+ exit(ret);
+}
diff --git a/tests/rt-init.c b/tests/rt-init.c
index 66a9ad32..dbe94b4a 100644
--- a/tests/rt-init.c
+++ b/tests/rt-init.c
@@ -39,6 +39,6 @@ ENDExit
BEGINTest
CODESTARTTest
-finalize_it:
+/*finalize_it:*/
/* room for custom error reporter, leave blank if not needed */
ENDTest
diff --git a/tests/tabescape_dflt.sh b/tests/tabescape_dflt.sh
new file mode 100755
index 00000000..d0e13ec9
--- /dev/null
+++ b/tests/tabescape_dflt.sh
@@ -0,0 +1,14 @@
+echo ===============================================================================
+echo \[tabescape_dflt.sh\]: test for default tab escaping
+$srcdir/killrsyslog.sh # kill rsyslogd if it runs for some reason
+
+./nettester -ttabescape_dflt -iudp
+if [ "$?" -ne "0" ]; then
+ exit 1
+fi
+
+echo test via tcp
+./nettester -ttabescape_dflt -itcp
+if [ "$?" -ne "0" ]; then
+ exit 1
+fi
diff --git a/tests/tabescape_off.sh b/tests/tabescape_off.sh
new file mode 100755
index 00000000..71ede7c0
--- /dev/null
+++ b/tests/tabescape_off.sh
@@ -0,0 +1,14 @@
+echo ===============================================================================
+echo \[tabescape_off.sh\]: test for tab escaping off
+$srcdir/killrsyslog.sh # kill rsyslogd if it runs for some reason
+
+./nettester -ttabescape_off -iudp
+if [ "$?" -ne "0" ]; then
+ exit 1
+fi
+
+echo test via tcp
+./nettester -ttabescape_off -itcp
+if [ "$?" -ne "0" ]; then
+ exit 1
+fi
diff --git a/tests/tcpflood.c b/tests/tcpflood.c
index 32bf959d..e92d1308 100644
--- a/tests/tcpflood.c
+++ b/tests/tcpflood.c
@@ -20,6 +20,14 @@
* one field to the right. Zero (default) disables this functionality.
* -M the message to be sent. Disables all message format options, as
* only that exact same message is sent.
+ * -I read specified input file, do NOT generate own test data. The test
+ * completes when eof is reached.
+ * -B The specified file (-I) is binary. No data processing is done by
+ * tcpflood. If multiple connections are specified, data is read in
+ * chunks and spread across the connections without taking any record
+ * delemiters into account.
+ * -C when input from a file is read, this file is transmitted -C times
+ * (C like cycle, running out of meaningful option switches ;))
*
* Part of the testbench for rsyslog.
*
@@ -54,6 +62,7 @@
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
+#include <sys/resource.h>
#define EXIT_FAILURE 1
#define INVALID_SOCKET -1
@@ -75,6 +84,10 @@ static int *sockArray; /* array of sockets to use */
static int msgNum = 0; /* initial message number to start with */
static int bShowProgress = 1; /* show progress messages */
static char *MsgToSend = NULL; /* if non-null, this is the actual message to send */
+static int bBinaryFile = 0; /* is -I file binary */
+static char *dataFile = NULL; /* name of data file, if NULL, generate own data */
+static int numFileIterations = 1;/* how often is file data to be sent? */
+FILE *dataFP = NULL; /* file pointer for data file, if used */
/* open a single tcp connection
@@ -166,8 +179,8 @@ int openConnections(void)
void closeConnections(void)
{
int i;
- char msgBuf[128];
size_t lenMsg;
+ char msgBuf[128];
if(bShowProgress)
write(1, " close connections", sizeof(" close connections")-1);
@@ -186,6 +199,62 @@ void closeConnections(void)
}
+/* generate the message to be sent according to program command line parameters.
+ * this has been moved to its own function as we now have various different ways
+ * of constructing test messages. -- rgerhards, 2010-03-31
+ */
+static inline void
+genMsg(char *buf, size_t maxBuf, int *pLenBuf)
+{
+ int edLen; /* actual extra data length to use */
+ char extraData[MAX_EXTRADATA_LEN + 1];
+ char dynFileIDBuf[128] = "";
+ static int numMsgsGen = 0;
+ int done;
+
+ if(dataFP != NULL) {
+ /* get message from file */
+ do {
+ done = 1;
+ *pLenBuf = fread(buf, 1, 1024, dataFP);
+ if(feof(dataFP)) {
+ if(--numFileIterations > 0) {
+ rewind(dataFP);
+ done = 0; /* need new iteration */
+ } else {
+ *pLenBuf = 0;
+ goto finalize_it;
+ }
+ }
+ } while(!done); /* Attention: do..while()! */
+ } else if(MsgToSend == NULL) {
+ if(dynFileIDs > 0) {
+ snprintf(dynFileIDBuf, maxBuf, "%d:", rand() % dynFileIDs);
+ }
+ if(extraDataLen == 0) {
+ *pLenBuf = snprintf(buf, maxBuf, "<%s>Mar 1 01:00:00 172.20.245.8 tag msgnum:%s%8.8d:\n",
+ msgPRI, dynFileIDBuf, msgNum);
+ } else {
+ if(bRandomizeExtraData)
+ edLen = ((long) rand() + extraDataLen) % extraDataLen + 1;
+ else
+ edLen = extraDataLen;
+ memset(extraData, 'X', edLen);
+ extraData[edLen] = '\0';
+ *pLenBuf = snprintf(buf, maxBuf, "<%s>Mar 1 01:00:00 172.20.245.8 tag msgnum:%s%8.8d:%d:%s\n",
+ msgPRI, dynFileIDBuf, msgNum, edLen, extraData);
+ }
+ } else {
+ /* use fixed message format from command line */
+ *pLenBuf = snprintf(buf, maxBuf, "%s\n", MsgToSend);
+ }
+
+ if(numMsgsGen++ >= numMsgsToSend)
+ *pLenBuf = 0; /* indicate end of run */
+
+finalize_it: ;
+}
+
/* send messages to the tcp connections we keep open. We use
* a very basic format that helps identify the message
* (via msgnum:<number>: e.g. msgnum:00000001:). This format is suitable
@@ -196,52 +265,42 @@ void closeConnections(void)
*/
int sendMessages(void)
{
- int i;
+ int i = 0;
int socknum;
int lenBuf;
int lenSend;
- int edLen; /* actual extra data length to use */
- char dynFileIDBuf[128] = "";
+ char *statusText;
char buf[MAX_EXTRADATA_LEN + 1024];
- char extraData[MAX_EXTRADATA_LEN + 1];
- printf("Sending %d messages.\n", numMsgsToSend);
+ if(dataFile == NULL) {
+ printf("Sending %d messages.\n", numMsgsToSend);
+ statusText = "messages";
+ } else {
+ printf("Sending file '%s' %d times.\n", dataFile, numFileIterations);
+ statusText = "kb";
+ }
if(bShowProgress)
- printf("\r%8.8d messages sent", 0);
- for(i = 0 ; i < numMsgsToSend ; ++i) {
+ printf("\r%8.8d %s sent", 0, statusText);
+ while(1) { /* broken inside loop! */
if(i < numConnections)
socknum = i;
else if(i >= numMsgsToSend - numConnections)
socknum = i - (numMsgsToSend - numConnections);
- else
- socknum = rand() % numConnections;
- if(MsgToSend == NULL) {
- if(dynFileIDs > 0) {
- sprintf(dynFileIDBuf, "%d:", rand() % dynFileIDs);
- }
- if(extraDataLen == 0) {
- lenBuf = sprintf(buf, "<%s>Mar 1 01:00:00 172.20.245.8 tag msgnum:%s%8.8d:\n",
- msgPRI, dynFileIDBuf, msgNum);
- } else {
- if(bRandomizeExtraData)
- edLen = ((long) rand() + extraDataLen) % extraDataLen + 1;
- else
- edLen = extraDataLen;
- memset(extraData, 'X', edLen);
- extraData[edLen] = '\0';
- lenBuf = sprintf(buf, "<%s>Mar 1 01:00:00 172.20.245.8 tag msgnum:%s%8.8d:%d:%s\n",
- msgPRI, dynFileIDBuf, msgNum, edLen, extraData);
- }
- } else {
- /* use fixed message format from command line */
- lenBuf = sprintf(buf, "%s\n", MsgToSend);
+ else {
+ int rnd = rand();
+ //socknum = rand() % numConnections;
+ socknum = rnd % numConnections;
}
+ genMsg(buf, sizeof(buf), &lenBuf); /* generate the message to send according to params */
+ if(lenBuf == 0)
+ break; /* end of processing! */
lenSend = send(sockArray[socknum], buf, lenBuf, 0);
if(lenSend != lenBuf) {
printf("\r%5.5d\n", i);
fflush(stdout);
perror("send test data");
- printf("send() failed at socket %d, index %d, msgNum %d\n", socknum, i, msgNum);
+ printf("send() failed at socket %d, index %d, msgNum %d\n",
+ sockArray[socknum], i, msgNum);
fflush(stderr);
return(1);
}
@@ -250,8 +309,9 @@ int sendMessages(void)
printf("\r%8.8d", i);
}
++msgNum;
+ ++i;
}
- printf("\r%8.8d messages sent\n", i);
+ printf("\r%8.8d %s sent\n", i, statusText);
return 0;
}
@@ -335,7 +395,7 @@ int main(int argc, char *argv[])
if(!isatty(1))
bShowProgress = 0;
- while((opt = getopt(argc, argv, "f:t:p:c:m:i:P:d:n:M:r")) != -1) {
+ while((opt = getopt(argc, argv, "f:t:p:c:C:m:i:I:P:d:n:M:rB")) != -1) {
switch (opt) {
case 't': targetIP = optarg;
break;
@@ -345,6 +405,8 @@ int main(int argc, char *argv[])
break;
case 'c': numConnections = atoi(optarg);
break;
+ case 'C': numFileIterations = atoi(optarg);
+ break;
case 'm': numMsgsToSend = atoi(optarg);
break;
case 'i': msgNum = atoi(optarg);
@@ -364,12 +426,41 @@ int main(int argc, char *argv[])
break;
case 'M': MsgToSend = optarg;
break;
+ case 'I': dataFile = optarg;
+ /* in this mode, we do not know the num messages to send, so
+ * we set a (high) number to keep the code happy.
+ */
+ numMsgsToSend = 1000000;
+ break;
+ case 'B': bBinaryFile = 1;
+ break;
default: printf("invalid option '%c' or value missing - terminating...\n", opt);
exit (1);
break;
}
}
+ if(numConnections > 20) {
+ /* if we use many (whatever this means, 20 is randomly picked)
+ * connections, we need to make sure we have a high enough
+ * limit. -- rgerhards, 2010-03-25
+ */
+ struct rlimit maxFiles;
+ maxFiles.rlim_cur = numConnections + 20;
+ maxFiles.rlim_max = numConnections + 20;
+ if(setrlimit(RLIMIT_NOFILE, &maxFiles) < 0) {
+ perror("setrlimit to increase file handles failed");
+ exit(1);
+ }
+ }
+
+ if(dataFile != NULL) {
+ if((dataFP = fopen(dataFile, "r")) == NULL) {
+ perror(dataFile);
+ exit(1);
+ }
+ }
+
if(openConnections() != 0) {
printf("error opening connections\n");
exit(1);
diff --git a/tests/testsuites/1.tabescape_dflt b/tests/testsuites/1.tabescape_dflt
new file mode 100644
index 00000000..91444bd3
--- /dev/null
+++ b/tests/testsuites/1.tabescape_dflt
@@ -0,0 +1,3 @@
+<167>Mar 6 16:57:54 172.20.245.8 test: before HT after HT (do NOT remove TAB!)
+ before HT#011after HT (do NOT remove TAB!)
+#Only the first two lines are important, you may place anything behind them!
diff --git a/tests/testsuites/1.tabescape_off b/tests/testsuites/1.tabescape_off
new file mode 100644
index 00000000..6a331c35
--- /dev/null
+++ b/tests/testsuites/1.tabescape_off
@@ -0,0 +1,3 @@
+<167>Mar 6 16:57:54 172.20.245.8 test: before HT after HT (do NOT remove TAB!)
+ before HT after HT (do NOT remove TAB!)
+#Only the first two lines are important, you may place anything behind them!
diff --git a/tests/testsuites/8bit.parse1 b/tests/testsuites/8bit.parse1
new file mode 100644
index 00000000..90db6352
--- /dev/null
+++ b/tests/testsuites/8bit.parse1
@@ -0,0 +1,2 @@
+<6>AUG 10 22:18:24 host tag This msg contains 8-bit European chars: äöü
+6,kern,info,Aug 10 22:18:24,host,tag,tag, This msg contains 8-bit European chars: äöü
diff --git a/tests/testsuites/8bit.parse_8bit_escape b/tests/testsuites/8bit.parse_8bit_escape
new file mode 100644
index 00000000..b2f6335c
--- /dev/null
+++ b/tests/testsuites/8bit.parse_8bit_escape
@@ -0,0 +1,2 @@
+<6>AUG 10 22:18:24 host tag This msg contains 8-bit European chars: äöü
+6,kern,info,Aug 10 22:18:24,host,tag,tag, This msg contains 8-bit European chars: #303#244#303#266#303#274
diff --git a/tests/testsuites/dircreate_dflt.conf b/tests/testsuites/dircreate_dflt.conf
new file mode 100644
index 00000000..9b9aadb8
--- /dev/null
+++ b/tests/testsuites/dircreate_dflt.conf
@@ -0,0 +1,11 @@
+# see .sh file for description
+# rgerhards, 2009-11-30
+$IncludeConfig diag-common.conf
+
+# set spool locations and switch queue to disk-only mode
+$WorkDirectory test-spool
+$MainMsgQueueFilename mainq
+$MainMsgQueueType disk
+
+$template dynfile,"test-logdir/rsyslog.out.log" # trick to use relative path names!
+*.* ?dynfile
diff --git a/tests/testsuites/dircreate_off.conf b/tests/testsuites/dircreate_off.conf
new file mode 100644
index 00000000..28ccbd8c
--- /dev/null
+++ b/tests/testsuites/dircreate_off.conf
@@ -0,0 +1,12 @@
+# see .sh file for description
+# rgerhards, 2009-11-30
+$IncludeConfig diag-common.conf
+
+# set spool locations and switch queue to disk-only mode
+$WorkDirectory test-spool
+$MainMsgQueueFilename mainq
+$MainMsgQueueType disk
+
+$CreateDirs off
+$template dynfile,"test-logdir/rsyslog.out.log" # trick to use relative path names!
+*.* ?dynfile
diff --git a/tests/testsuites/empty.parse1 b/tests/testsuites/empty.parse1
new file mode 100644
index 00000000..86a86986
--- /dev/null
+++ b/tests/testsuites/empty.parse1
@@ -0,0 +1,3 @@
+<14>Jan 6 2009 15:22:26 localhost
+14,user,info,Jan 6 15:22:26,localhost,,,
+#Note: there is one space after localhost, but then \n!
diff --git a/tests/testsuites/mark.parse1 b/tests/testsuites/mark.parse1
new file mode 100644
index 00000000..fff9ae6d
--- /dev/null
+++ b/tests/testsuites/mark.parse1
@@ -0,0 +1,7 @@
+#This is a malformed message, but one from real life. At least,
+#it should be parsed as can be seen here.
+<6>Feb 18 16:01:59 serverX -- MARK --
+6,kern,info,Feb 18 16:01:59,serverX,--,--, MARK --
+# and the next one as an extreme case (note the absence of PRI)
+Feb 18 16:01:59 serverX -- MARK --
+13,user,notice,Feb 18 16:01:59,serverX,--,--, MARK --
diff --git a/tests/testsuites/parse_8bit_escape.conf b/tests/testsuites/parse_8bit_escape.conf
new file mode 100644
index 00000000..0598f33f
--- /dev/null
+++ b/tests/testsuites/parse_8bit_escape.conf
@@ -0,0 +1,9 @@
+$ModLoad ../plugins/omstdout/.libs/omstdout
+$IncludeConfig nettest.input.conf # This picks the to be tested input from the test driver!
+
+$ErrorMessagesToStderr off
+$Escape8BitCharactersOnReceive on
+
+# use a special format that we can easily parse in expect
+$template expect,"%PRI%,%syslogfacility-text%,%syslogseverity-text%,%timestamp%,%hostname%,%programname%,%syslogtag%,%msg%\n"
+*.* :omstdout:;expect
diff --git a/tests/testsuites/random.conf b/tests/testsuites/random.conf
new file mode 100644
index 00000000..a7079df1
--- /dev/null
+++ b/tests/testsuites/random.conf
@@ -0,0 +1,13 @@
+# we write to /dev/null, as we have no chance to verify the output
+# in any case. What we really check is that rsyslogd does not
+# segfault or otherwise abort.
+# rgerhards, 2010-04-01
+$IncludeConfig diag-common.conf
+
+$ModLoad ../plugins/imtcp/.libs/imtcp
+$MainMsgQueueTimeoutShutdown 10000
+$InputTCPServerRun 13514
+
+$template outfmt,"%rawmsg%\n"
+$template dynfile,"rsyslog.out.log" # trick to use relative path names!
+*.* /dev/null
diff --git a/tests/testsuites/tabescape_dflt.conf b/tests/testsuites/tabescape_dflt.conf
new file mode 100644
index 00000000..b9d92a37
--- /dev/null
+++ b/tests/testsuites/tabescape_dflt.conf
@@ -0,0 +1,8 @@
+$ModLoad ../plugins/omstdout/.libs/omstdout
+$IncludeConfig nettest.input.conf # This picks the to be tested input from the test driver!
+
+$ErrorMessagesToStderr off
+
+# use a special format that we can easily parse in expect
+$template fmt,"%msg%\n"
+*.* :omstdout:;fmt
diff --git a/tests/testsuites/tabescape_off.conf b/tests/testsuites/tabescape_off.conf
new file mode 100644
index 00000000..c1eca305
--- /dev/null
+++ b/tests/testsuites/tabescape_off.conf
@@ -0,0 +1,10 @@
+$ModLoad ../plugins/omstdout/.libs/omstdout
+$IncludeConfig nettest.input.conf # This picks the to be tested input from the test driver!
+
+$ErrorMessagesToStderr off
+
+$EscapeControlCharacterTab off
+
+# use a special format that we can easily parse in expect
+$template fmt,"%msg%\n"
+*.* :omstdout:;fmt
diff --git a/tests/threadingmqaq.sh b/tests/threadingmqaq.sh
index 29047bea..ae5d3568 100755
--- a/tests/threadingmqaq.sh
+++ b/tests/threadingmqaq.sh
@@ -12,6 +12,9 @@ source $srcdir/diag.sh startup threadingmqaq.conf
#source $srcdir/diag.sh tcpflood -c2 -m100000
#source $srcdir/diag.sh shutdown-when-empty # shut down rsyslogd when done processing messages
source $srcdir/diag.sh injectmsg 0 100000
+# we need to sleep a bit on some environments, as imdiag can not correctly
+# diagnose when the action queues are empty...
+sleep 3
source $srcdir/diag.sh shutdown-when-empty # shut down rsyslogd when done processing messages
source $srcdir/diag.sh wait-shutdown
source $srcdir/diag.sh seq-check 0 99999
diff --git a/threads.c b/threads.c
index ccc80816..4064fc7a 100644
--- a/threads.c
+++ b/threads.c
@@ -207,7 +207,7 @@ static void* thrdStarter(void *arg)
* executing threads. It is added at the end of the list.
* rgerhards, 2007-12-14
*/
-rsRetVal thrdCreate(rsRetVal (*thrdMain)(thrdInfo_t*), rsRetVal(*afterRun)(thrdInfo_t *), bool bNeedsCancel)
+rsRetVal thrdCreate(rsRetVal (*thrdMain)(thrdInfo_t*), rsRetVal(*afterRun)(thrdInfo_t *), sbool bNeedsCancel)
{
DEFiRet;
thrdInfo_t *pThis;
diff --git a/threads.h b/threads.h
index 1cac02b5..75ba2fcf 100644
--- a/threads.h
+++ b/threads.h
@@ -32,7 +32,7 @@ struct thrdInfo {
rsRetVal (*pUsrThrdMain)(struct thrdInfo*); /* user thread main to be called in new thread */
rsRetVal (*pAfterRun)(struct thrdInfo*); /* cleanup function */
pthread_t thrdID;
- bool bNeedsCancel; /* must input be terminated by pthread_cancel()? */
+ sbool bNeedsCancel; /* must input be terminated by pthread_cancel()? */
};
/* prototypes */
@@ -40,7 +40,7 @@ rsRetVal thrdExit(void);
rsRetVal thrdInit(void);
rsRetVal thrdTerminate(thrdInfo_t *pThis);
rsRetVal thrdTerminateAll(void);
-rsRetVal thrdCreate(rsRetVal (*thrdMain)(thrdInfo_t*), rsRetVal(*afterRun)(thrdInfo_t *), bool);
+rsRetVal thrdCreate(rsRetVal (*thrdMain)(thrdInfo_t*), rsRetVal(*afterRun)(thrdInfo_t *), sbool);
/* macros (replace inline functions) */
diff --git a/tools/omfile.c b/tools/omfile.c
index 1ade3132..5e49afa9 100644
--- a/tools/omfile.c
+++ b/tools/omfile.c
@@ -48,10 +48,13 @@
#include <libgen.h>
#include <unistd.h>
#include <sys/file.h>
-
#ifdef OS_SOLARIS
# include <fcntl.h>
#endif
+#ifdef HAVE_ATOMIC_BUILTINS
+# include <pthread.h>
+#endif
+
#include "conf.h"
#include "syslogd-types.h"
@@ -89,12 +92,33 @@ static uint64 clockFileAccess = 0;
static unsigned clockFileAccess = 0;
#endif
/* and the "tick" function */
+#ifdef HAVE_ATOMIC_BUILTINS
static inline uint64
getClockFileAccess(void)
{
return ATOMIC_INC_AND_FETCH(clockFileAccess);
}
-
+#else
+/* if we do not have atomics, we need to guard this via a mutex.
+ * the reason is that otherwise cache lookups may fail. That function
+ * requires the highest current value, and we can not provide that
+ * without using atomic instructions and mutexes.
+ * rgerhards, 2010-03-05
+ */
+static pthread_mutex_t mutClock;
+static uint64
+getClockFileAccess(void)
+{
+ uint64 retVal;
+
+ BEGINfunc
+ d_pthread_mutex_lock(&mutClock);
+ retVal = ++clockFileAccess;
+ d_pthread_mutex_unlock(&mutClock);
+ ENDfunc
+ return retVal;
+}
+#endif /* #ifdef HAVE_ATOMIC_BUILTINS */
/* The following structure is a dynafile name cache entry.
*/
@@ -109,6 +133,7 @@ typedef struct s_dynaFileCacheEntry dynaFileCacheEntry;
#define IOBUF_DFLT_SIZE 1024 /* default size for io buffers */
#define FLUSH_INTRVL_DFLT 1 /* default buffer flush interval (in seconds) */
#define USE_ASYNCWRITER_DFLT 0 /* default buffer use async writer */
+#define FLUSHONTX_DFLT 1 /* default for flush on TX end */
#define DFLT_bForceChown 0
/* globals for default values */
@@ -124,7 +149,7 @@ static uid_t dirGID; /* GID to be used for newly created directories */
static int bCreateDirs = 1;/* auto-create directories for dynaFiles: 0 - no, 1 - yes */
static int bEnableSync = 0;/* enable syncing of files (no dash in front of pathname in conf): 0 - no, 1 - yes */
static int iZipLevel = 0; /* zip compression mode (0..9 as usual) */
-static bool bFlushOnTXEnd = 0;/* flush write buffers when transaction has ended? */
+static sbool bFlushOnTXEnd = FLUSHONTX_DFLT;/* flush write buffers when transaction has ended? */
static int64 iIOBufSize = IOBUF_DFLT_SIZE; /* size of an io buffer */
static int iFlushInterval = FLUSH_INTRVL_DFLT; /* how often flush the output buffer on inactivity? */
static int bUseAsyncWriter = USE_ASYNCWRITER_DFLT; /* should we enable asynchronous writing? */
@@ -141,7 +166,7 @@ typedef struct _instanceData {
int fDirCreateMode; /* creation mode for mkdir() */
int bCreateDirs; /* auto-create directories? */
int bSyncFile; /* should the file by sync()'ed? 1- yes, 0- no */
- bool bForceChown; /* force chown() on existing files? */
+ sbool bForceChown; /* force chown() on existing files? */
uid_t fileUID; /* IDs for creation */
uid_t dirUID;
gid_t fileGID;
@@ -160,8 +185,8 @@ typedef struct _instanceData {
int iZipLevel; /* zip mode to use for this selector */
int iIOBufSize; /* size of associated io buffer */
int iFlushInterval; /* how fast flush buffer on inactivity? */
- bool bFlushOnTXEnd; /* flush write buffers when transaction has ended? */
- bool bUseAsyncWriter; /* use async stream writer? */
+ sbool bFlushOnTXEnd; /* flush write buffers when transaction has ended? */
+ sbool bUseAsyncWriter; /* use async stream writer? */
} instanceData;
@@ -187,8 +212,9 @@ CODESTARTdbgPrintInstInfo
dbgprintf("\tflush interval=%d\n", pData->iFlushInterval);
dbgprintf("\tfile cache size=%d\n", pData->iDynaFileCacheSize);
dbgprintf("\tcreate directories: %s\n", pData->bCreateDirs ? "yes" : "no");
- dbgprintf("\tfile owner %d, group %d\n", pData->fileUID, pData->fileGID);
- dbgprintf("\tdirectory owner %d, group %d\n", pData->dirUID, pData->dirGID);
+ dbgprintf("\tfile owner %d, group %d\n", (int) pData->fileUID, (int) pData->fileGID);
+ dbgprintf("\tforce chown() for all files: %s\n", pData->bForceChown ? "yes" : "no");
+ dbgprintf("\tdirectory owner %d, group %d\n", (int) pData->dirUID, (int) pData->dirGID);
dbgprintf("\tdir create mode 0%3.3o, file create mode 0%3.3o\n",
pData->fDirCreateMode, pData->fCreateMode);
dbgprintf("\tfail if owner/group can not be set: %s\n", pData->bFailOnChown ? "yes" : "no");
@@ -822,7 +848,7 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a
bCreateDirs = 1;
bEnableSync = 0;
iZipLevel = 0;
- bFlushOnTXEnd = 0;
+ bFlushOnTXEnd = FLUSHONTX_DFLT;
iIOBufSize = IOBUF_DFLT_SIZE;
iFlushInterval = FLUSH_INTRVL_DFLT;
bUseAsyncWriter = USE_ASYNCWRITER_DFLT;
@@ -853,6 +879,9 @@ CODESTARTmodExit
objRelease(errmsg, CORE_COMPONENT);
objRelease(strm, CORE_COMPONENT);
free(pszFileDfltTplName);
+# ifndef HAVE_ATOMIC_BUILTINS
+ pthread_mutex_destroy(&mutClock);
+# endif
ENDmodExit
@@ -870,6 +899,11 @@ CODESTARTmodInit
CODEmodInit_QueryRegCFSLineHdlr
CHKiRet(objUse(errmsg, CORE_COMPONENT));
CHKiRet(objUse(strm, CORE_COMPONENT));
+
+# ifndef HAVE_ATOMIC_BUILTINS
+ pthread_mutex_init(&mutClock, NULL);
+# endif
+
INITChkCoreFeature(bCoreSupportsBatching, CORE_FEATURE_BATCHING);
DBGPRINTF("omfile: %susing transactional output interface.\n", bCoreSupportsBatching ? "" : "not ");
CHKiRet(omsdRegCFSLineHdlr((uchar *)"dynafilecachesize", 0, eCmdHdlrInt, (void*) setDynaFileCacheSize, NULL, STD_LOADABLE_MODULE_ID));
diff --git a/tools/ompipe.c b/tools/ompipe.c
index 5fb9b27e..cf22bc84 100644
--- a/tools/ompipe.c
+++ b/tools/ompipe.c
@@ -36,9 +36,12 @@
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
+#include <unistd.h>
#include <string.h>
+#include <unistd.h>
#include <assert.h>
#include <errno.h>
+#include <fcntl.h>
#include <sys/file.h>
#include "syslogd.h"
diff --git a/tools/syncdemo.c b/tools/syncdemo.c
new file mode 100644
index 00000000..b4b75cdc
--- /dev/null
+++ b/tools/syncdemo.c
@@ -0,0 +1,318 @@
+/* syncdemo - a program to demonstrate the performance and validity of different
+ * synchronization methods as well as some timing properties.
+ *
+ * The task to be done is very simple: a single gloabl integer is to to incremented
+ * by multiple threads. All this is done in a very-high concurrency environment. Note that
+ * the test is unfair to mechanisms likes spinlocks, because we have almost only wait
+ * time but no real processing time between the waits. However, the test provides
+ * some good insight into atomic instructions vs. other synchronisation methods.
+ * It also proves that garbling variables by not doing proper synchronisation is
+ * highly likely. For best results, this program should be executed on a
+ * multiprocessor machine (on a uniprocessor, it will probably not display the
+ * problems caused by missing synchronisation).
+ *
+ * compile with $ gcc -O0 -o syncdemo -lpthread syncdemo.c
+ *
+ * This program REQUIRES linux. With slight modification, it may run on Solaris.
+ * Note that gcc on Sparc does NOT offer atomic instruction support!
+ *
+ * Copyright (C) 2010 by Rainer Gerhards <rgerhards@hq.adiscon.com>
+ * Released under the GNU GPLv3.
+ *
+ * Inspired by (retrieved 2010-04-13)
+ * http://www.alexonlinux.com/multithreaded-simple-data-type-access-and-atomic-variables
+ */
+#define _GNU_SOURCE
+#include <sched.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <linux/unistd.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <getopt.h>
+
+/* config settings */
+static int bCPUAffinity = 0;
+static int procs = 0; /* number of processors */
+static int numthrds = 0; /* if zero, => equal num of processors */
+static unsigned goal = 50000000; /* 50 million */
+static int bCSV = 0; /* generate CVS output? */
+static int numIterations = 1; /* number of iterations */
+static int dummyLoad = 0; /* number of dummy load iterations to generate */
+static enum { none, atomic, cas, mutex, spinlock } syncType;
+
+static int global_int = 0; /* our global counter */
+static unsigned thrd_WorkToDo; /* number of computations each thread must do */
+static volatile int bStartRun = 0; /* indicate to flag when threads should start */
+
+static struct timeval tvStart, tvEnd; /* used for timing one testing iteration */
+
+/* statistic counters */
+static long long totalRuntime;
+
+/* sync objects (if needed) */
+static pthread_mutex_t mut;
+static pthread_spinlock_t spin;
+
+static char*
+getSyncMethName()
+{
+ switch(syncType) {
+ case none : return "none";
+ case atomic : return "atomic instruction";
+ case mutex : return "mutex";
+ case spinlock: return "spin lock";
+ case cas : return "cas";
+ }
+}
+
+
+static pid_t
+gettid()
+{
+ return syscall( __NR_gettid );
+}
+
+
+void *workerThread( void *arg )
+{
+ int i, j;
+ int oldval, newval; /* for CAS sync mode */
+ int thrd_num = (int)(long)arg;
+ cpu_set_t set;
+
+ CPU_ZERO(&set);
+ CPU_SET(thrd_num % procs, &set);
+
+ /* if enabled, try to put thread on a fixed CPU (the one that corresponds to the
+ * thread ID). This may
+ */
+ if(bCPUAffinity) {
+ if (sched_setaffinity( gettid(), sizeof( cpu_set_t ), &set )) {
+ perror( "sched_setaffinity" );
+ return NULL;
+ }
+ }
+
+ /* wait for "go" */
+ while(bStartRun == 0)
+ /*WAIT!*/;
+
+ for (i = 0; i < thrd_WorkToDo; i++) {
+ switch(syncType) {
+ case none:
+ global_int++;
+ break;
+ case atomic:
+ __sync_fetch_and_add(&global_int,1);
+ break;
+ case cas:
+ do {
+ oldval = global_int;
+ newval = oldval + 1;
+ } while(!__sync_bool_compare_and_swap(&global_int, oldval, newval));
+ break;
+ case mutex:
+ pthread_mutex_lock(&mut);
+ global_int++;
+ pthread_mutex_unlock(&mut);
+ break;
+ case spinlock:
+ pthread_spin_lock(&spin);
+ global_int++;
+ pthread_spin_unlock(&spin);
+ break;
+ }
+
+ /* we now generate "dummy load" if instructed to do so. The idea is that
+ * we do some other work, as in real life, so that we have a better
+ * ratio of sync vs. actual work to do.
+ */
+ for(j = 0 ; j < dummyLoad ; ++j) {
+ /* be careful: compiler may optimize loop out! */;
+ }
+ }
+
+ return NULL;
+}
+
+
+static void beginTiming(void)
+{
+ if(!bCSV) {
+ printf("Test Parameters:\n");
+ printf("\tNumber of Cores.........: %d\n", procs);
+ printf("\tNumber of Threads.......: %d\n", numthrds);
+ printf("\tSet Affinity............: %s\n", bCPUAffinity ? "yes" : "no");
+ printf("\tCount to................: %u\n", goal);
+ printf("\tWork for each Thread....: %u\n", thrd_WorkToDo);
+ printf("\tDummy Load Counter......: %d\n", dummyLoad);
+ printf("\tSync Method used........: %s\n", getSyncMethName());
+ }
+ gettimeofday(&tvStart, NULL);
+}
+
+
+static void endTiming(void)
+{
+ unsigned delta;
+ long sec, usec;
+
+ gettimeofday(&tvEnd, NULL);
+ if(tvStart.tv_usec > tvEnd.tv_usec) {
+ tvEnd.tv_sec--;
+ tvEnd.tv_usec += 1000000;
+ }
+
+ sec = tvEnd.tv_sec - tvStart.tv_sec;
+ usec = tvEnd.tv_usec - tvStart.tv_usec;
+
+ delta = thrd_WorkToDo * numthrds - global_int;
+ if(bCSV) {
+ printf("%s,%d,%d,%d,%u,%u,%ld.%ld\n",
+ getSyncMethName(), procs, numthrds, bCPUAffinity, goal, delta, sec, usec);
+ } else {
+ printf("measured (sytem time) runtime is %ld.%ld seconds\n", sec, usec);
+ if(delta == 0) {
+ printf("Computation was done correctly.\n");
+ } else {
+ printf("Computation INCORRECT,\n"
+ "\texpected %9u\n"
+ "\treal %9u\n"
+ "\toff by %9u\n",
+ thrd_WorkToDo * numthrds,
+ global_int,
+ delta);
+ }
+ }
+
+ totalRuntime += sec * 1000 + (usec / 1000);
+}
+
+
+static void
+usage(void)
+{
+ fprintf(stderr, "Usage: syncdemo -a -c<num> -t<num>\n");
+ fprintf(stderr, "\t-a set CPU affinity\n");
+ fprintf(stderr, "\t-c<num> count to <num>\n");
+ fprintf(stderr, "\t-d<num> dummy load, <num> iterations\n");
+ fprintf(stderr, "\t-t<num> number of threads to use\n");
+ fprintf(stderr, "\t-s<type> sync-type to use (none, atomic, mutex, spin)\n");
+ fprintf(stderr, "\t-C generate CVS output\n");
+ fprintf(stderr, "\t-I number of iterations\n");
+ exit(2);
+}
+
+
+/* carry out the actual test (one iteration)
+ */
+static void
+singleTest(void)
+{
+ int i;
+ pthread_t *thrs;
+
+ global_int = 0;
+ bStartRun = 0;
+
+ thrs = malloc(sizeof(pthread_t) * numthrds);
+ if (thrs == NULL) {
+ perror( "malloc" );
+ exit(1);
+ }
+
+ thrd_WorkToDo = goal / numthrds;
+
+ for (i = 0; i < numthrds; i++) {
+ if(pthread_create( &thrs[i], NULL, workerThread, (void *)(long)i )) {
+ perror( "pthread_create" );
+ procs = i;
+ break;
+ }
+ }
+
+ beginTiming();
+ bStartRun = 1; /* start the threads (they are busy-waiting so far!) */
+
+ for (i = 0; i < numthrds; i++)
+ pthread_join( thrs[i], NULL );
+
+ endTiming();
+
+ free( thrs );
+
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ int i;
+ int opt;
+
+ while((opt = getopt(argc, argv, "ac:d:i:t:s:C")) != EOF) {
+ switch((char)opt) {
+ case 'a':
+ bCPUAffinity = 1;
+ break;
+ case 'c':
+ goal = (unsigned) atol(optarg);
+ break;
+ case 'd':
+ dummyLoad = atoi(optarg);
+ break;
+ case 'i':
+ numIterations = atoi(optarg);
+ break;
+ case 't':
+ numthrds = atoi(optarg);
+ break;
+ case 'C':
+ bCSV = 1;
+ break;
+ case 's':
+ if(!strcmp(optarg, "none"))
+ syncType = none;
+ else if(!strcmp(optarg, "atomic"))
+ syncType = atomic;
+ else if(!strcmp(optarg, "cas"))
+ syncType = cas;
+ else if(!strcmp(optarg, "mutex")) {
+ syncType = mutex;
+ pthread_mutex_init(&mut, NULL);
+ } else if(!strcmp(optarg, "spin")) {
+ syncType = spinlock;
+ pthread_spin_init(&spin, PTHREAD_PROCESS_PRIVATE);
+ } else {
+ fprintf(stderr, "error: invalid sync mode '%s'\n", optarg);
+ usage();
+ }
+ break;
+ default:usage();
+ break;
+ }
+ }
+
+ /* Getting number of CPUs */
+ procs = (int)sysconf(_SC_NPROCESSORS_ONLN);
+ if (procs < 0) {
+ perror( "sysconf" );
+ return -1;
+ }
+
+ if(numthrds < 1) {
+ numthrds = procs;
+ }
+
+ totalRuntime = 0;
+ for(i = 0 ; i < numIterations ; ++i) {
+ singleTest();
+ }
+
+ printf("total runtime %ld, avg %ld\n", totalRuntime, totalRuntime / numIterations);
+ return 0;
+}
diff --git a/tools/syslogd.c b/tools/syslogd.c
index 887ffbd2..2432a28d 100644
--- a/tools/syslogd.c
+++ b/tools/syslogd.c
@@ -574,7 +574,7 @@ logmsgInternal(int iErr, int pri, uchar *msg, int flags)
* permits us to process unmodified config files which otherwise contain a
* supressor statement.
*/
- if(((Debug || NoFork) && bErrMsgToStderr) || iConfigVerify) {
+ if(((Debug == DEBUG_FULL || NoFork) && bErrMsgToStderr) || iConfigVerify) {
if(LOG_PRI(pri) == LOG_ERR)
fprintf(stderr, "rsyslogd: %s\n", msg);
}
@@ -591,6 +591,82 @@ finalize_it:
RETiRet;
}
+/* check message against ACL set
+ * rgerhards, 2009-11-16
+ */
+#if 0
+static inline rsRetVal
+chkMsgAgainstACL() {
+ /* if we reach this point, we had a good receive and can process the packet received */
+ /* check if we have a different sender than before, if so, we need to query some new values */
+ if(net.CmpHost(&frominet, frominetPrev, socklen) != 0) {
+ CHKiRet(net.cvthname(&frominet, fromHost, fromHostFQDN, fromHostIP));
+ memcpy(frominetPrev, &frominet, socklen); /* update cache indicator */
+ /* Here we check if a host is permitted to send us
+ * syslog messages. If it isn't, we do not further
+ * process the message but log a warning (if we are
+ * configured to do this).
+ * rgerhards, 2005-09-26
+ */
+ *pbIsPermitted = net.isAllowedSender((uchar*)"UDP",
+ (struct sockaddr *)&frominet, (char*)fromHostFQDN);
+
+ if(!*pbIsPermitted) {
+ DBGPRINTF("%s is not an allowed sender\n", (char*)fromHostFQDN);
+ if(glbl.GetOption_DisallowWarning) {
+ time_t tt;
+
+ datetime.GetTime(&tt);
+ if(tt > ttLastDiscard + 60) {
+ ttLastDiscard = tt;
+ errmsg.LogError(0, NO_ERRCODE,
+ "UDP message from disallowed sender %s discarded",
+ (char*)fromHost);
+ }
+ }
+ }
+ }
+}
+#endif
+
+
+/* consumes a single messages - this function is primarily used to shuffle
+ * out some code from msgConsumer(). After this function, the message is
+ * (by definition!) considered committed.
+ * rgerhards, 2009-11-16
+ */
+static inline rsRetVal
+msgConsumeOne(msg_t *pMsg, prop_t **propFromHost, prop_t **propFromHostIP) {
+ uchar fromHost[NI_MAXHOST];
+ uchar fromHostIP[NI_MAXHOST];
+ uchar fromHostFQDN[NI_MAXHOST];
+ int bIsPermitted;
+ DEFiRet;
+
+ if((pMsg->msgFlags & NEEDS_ACLCHK_U) != 0) {
+ dbgprintf("msgConsumer: UDP ACL must be checked for message (hostname-based)\n");
+ CHKiRet(net.cvthname(pMsg->rcvFrom.pfrominet, fromHost, fromHostFQDN, fromHostIP));
+ bIsPermitted = net.isAllowedSender2((uchar*)"UDP",
+ (struct sockaddr *)pMsg->rcvFrom.pfrominet, (char*)fromHostFQDN, 1);
+ if(!bIsPermitted) {
+ DBGPRINTF("Message from '%s' discarded, not a permitted sender host\n",
+ fromHostFQDN);
+ ABORT_FINALIZE(RS_RET_ERR);
+ /* save some of the info we obtained */
+ MsgSetRcvFromStr(pMsg, fromHost, ustrlen(fromHost), propFromHost);
+ CHKiRet(MsgSetRcvFromIPStr(pMsg, fromHostIP, ustrlen(fromHostIP), propFromHostIP));
+ pMsg->msgFlags &= ~NEEDS_ACLCHK_U;
+ }
+ }
+
+ if((pMsg->msgFlags & NEEDS_PARSING) != 0)
+ CHKiRet(parser.ParseMsg(pMsg));
+
+ ruleset.ProcessMsg(pMsg);
+finalize_it:
+ RETiRet;
+}
+
/* The consumer of dequeued messages. This function is called by the
* queue engine on dequeueing of a message. It runs on a SEPARATE
@@ -602,26 +678,22 @@ static rsRetVal
msgConsumer(void __attribute__((unused)) *notNeeded, batch_t *pBatch, int *pbShutdownImmediate)
{
int i;
- msg_t *pMsg;
- rsRetVal localRet;
+ prop_t *propFromHost = NULL;
+ prop_t *propFromHostIP = NULL;
DEFiRet;
assert(pBatch != NULL);
for(i = 0 ; i < pBatch->nElem && !*pbShutdownImmediate ; i++) {
- pMsg = (msg_t*) pBatch->pElem[i].pUsrp;
DBGPRINTF("msgConsumer processes msg %d/%d\n", i, pBatch->nElem);
- if((pMsg->msgFlags & NEEDS_PARSING) != 0) {
- localRet = parser.ParseMsg(pMsg);
- if(localRet == RS_RET_OK)
- ruleset.ProcessMsg(pMsg);
- } else {
- ruleset.ProcessMsg(pMsg);
- }
- /* if we reach this point, the message is considered committed (by definition!) */
+ msgConsumeOne((msg_t*) pBatch->pElem[i].pUsrp, &propFromHost, &propFromHostIP);
pBatch->pElem[i].state = BATCH_STATE_COMM;
}
+ if(propFromHost != NULL)
+ prop.Destruct(&propFromHost);
+ if(propFromHostIP != NULL)
+ prop.Destruct(&propFromHostIP);
RETiRet;
}
@@ -910,9 +982,10 @@ static void doDie(int sig)
static int iRetries = 0; /* debug aid */
dbgprintf(MSG1);
if(Debug)
+ if(Debug == DEBUG_FULL)
write(1, MSG1, sizeof(MSG1) - 1);
if(iRetries++ == 4) {
- if(Debug)
+ if(Debug == DEBUG_FULL)
write(1, MSG2, sizeof(MSG2) - 1);
abort();
}
@@ -1091,6 +1164,9 @@ static rsRetVal setMaxFiles(void __attribute__((unused)) *pVal, int iFiles)
iFiles, errStr, (long) maxFiles.rlim_max);
ABORT_FINALIZE(RS_RET_ERR_RLIM_NOFILE);
}
+#ifdef USE_UNLIMITED_SELECT
+ glbl.SetFdSetSize(howmany(iFiles, __NFDBITS) * sizeof (fd_mask));
+#endif
DBGPRINTF("Max number of files set to %d [kernel max %ld].\n", iFiles, (long) maxFiles.rlim_max);
finalize_it:
@@ -1673,6 +1749,25 @@ finalize_it:
}
+
+/* Put the rsyslog main thread to sleep for n seconds. This was introduced as
+ * a quick and dirty workaround for a privilege drop race in regard to listener
+ * startup, which itself was a result of the not-yet-done proper coding of
+ * privilege drop code (quite some effort). It may be useful for other occasions, too.
+ * is specified).
+ * rgerhards, 2009-06-12
+ */
+static rsRetVal
+putToSleep(void __attribute__((unused)) *pVal, int iNewVal)
+{
+ DEFiRet;
+ DBGPRINTF("rsyslog main thread put to sleep via $sleep %d directive...\n", iNewVal);
+ srSleep(iNewVal, 0);
+ DBGPRINTF("rsyslog main thread continues after $sleep %d\n", iNewVal);
+ RETiRet;
+}
+
+
/* Switch to either an already existing rule set or start a new one. The
* named rule set becomes the new "current" rule set (what means that new
* actions are added to it).
@@ -1929,6 +2024,7 @@ static rsRetVal loadBuildInModules(void)
CHKiRet(regCfSysLineHdlr((uchar *)"actionresumeretrycount", 0, eCmdHdlrInt, NULL, &glbliActionResumeRetryCount, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"defaultruleset", 0, eCmdHdlrGetWord, setDefaultRuleset, NULL, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"ruleset", 0, eCmdHdlrGetWord, setCurrRuleset, NULL, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"sleep", 0, eCmdHdlrInt, putToSleep, NULL, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuefilename", 0, eCmdHdlrGetWord, NULL, &pszMainMsgQFName, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuesize", 0, eCmdHdlrInt, NULL, &iMainMsgQueueSize, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuehighwatermark", 0, eCmdHdlrInt, NULL, &iMainMsgQHighWtrMark, NULL));
@@ -2102,7 +2198,7 @@ static rsRetVal mainThread()
* is still in its infancy (and not really done), we currently accept this issue.
* rgerhards, 2009-06-29
*/
- if(!(Debug || NoFork)) {
+ if(!(Debug == DEBUG_FULL || NoFork)) {
close(1);
close(2);
bErrMsgToStderr = 0;
@@ -2294,7 +2390,7 @@ doGlblProcessInit(void)
thrdInit();
- if( !(Debug || NoFork) )
+ if( !(Debug == DEBUG_FULL || NoFork) )
{
DBGPRINTF("Checking pidfile.\n");
if (!check_pid(PidFile))
@@ -2395,6 +2491,7 @@ int realMain(int argc, char **argv)
uchar *LocalHostName;
uchar *LocalDomain;
uchar *LocalFQDNName;
+ char cwdbuf[128]; /* buffer to obtain/display current working directory */
/* first, parse the command line options. We do not carry out any actual work, just
* see what we should do. This relieves us from certain anomalies and we can process
@@ -2481,8 +2578,9 @@ int realMain(int argc, char **argv)
if ((argc -= optind))
usage();
- DBGPRINTF("rsyslogd %s startup, compatibility mode %d, module path '%s'\n",
- VERSION, iCompatibilityMode, glblModPath == NULL ? "" : (char*)glblModPath);
+ DBGPRINTF("rsyslogd %s startup, compatibility mode %d, module path '%s', cwd:%s\n",
+ VERSION, iCompatibilityMode, glblModPath == NULL ? "" : (char*)glblModPath,
+ getcwd(cwdbuf, sizeof(cwdbuf)));
/* we are done with the initial option parsing and processing. Now we init the system. */