summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog274
-rw-r--r--Makefile.am11
-rw-r--r--action.c314
-rw-r--r--action.h2
-rw-r--r--configure.ac62
-rw-r--r--dirty.h1
-rw-r--r--doc/Makefile.am1
-rw-r--r--doc/how2help.html5
-rw-r--r--doc/imptcp.html5
-rw-r--r--doc/imtcp.html9
-rw-r--r--doc/imudp.html8
-rw-r--r--doc/manual.html7
-rw-r--r--doc/mmnormalize.html56
-rw-r--r--doc/property_replacer.html15
-rw-r--r--doc/rscript_abnf.html53
-rw-r--r--doc/rsyslog_conf.html75
-rw-r--r--doc/rsyslog_conf_basic_structure.html35
-rw-r--r--doc/rsyslog_conf_file_syntax_differences.html32
-rw-r--r--doc/rsyslog_conf_filter.html7
-rw-r--r--doc/rsyslog_conf_lines.html23
-rw-r--r--doc/rsyslog_conf_modules.html6
-rw-r--r--doc/rsyslog_recording_pri.html48
-rw-r--r--doc/v6compatibility.html44
-rw-r--r--parse.c7
-rw-r--r--plugins/imptcp/imptcp.c267
-rw-r--r--plugins/imtcp/imtcp.c5
-rw-r--r--plugins/imttcp/Makefile.am6
-rw-r--r--plugins/imttcp/imttcp.c1145
-rw-r--r--plugins/imudp/imudp.c4
-rw-r--r--plugins/imuxsock/imuxsock.c4
-rw-r--r--plugins/mmnormalize/Makefile.am8
-rw-r--r--plugins/mmnormalize/mmnormalize.c274
-rw-r--r--plugins/mmsnmptrapd/mmsnmptrapd.c6
-rw-r--r--plugins/omgssapi/omgssapi.c69
-rw-r--r--plugins/omhdfs/javaenv.sh14
-rw-r--r--plugins/omhdfs/omhdfs.c136
-rw-r--r--plugins/omlibdbi/omlibdbi.c109
-rw-r--r--plugins/ommail/ommail.c90
-rw-r--r--plugins/ommongodb/Makefile.am11
-rw-r--r--plugins/ommongodb/README23
-rw-r--r--plugins/ommongodb/ommongodb.c280
-rw-r--r--plugins/ommysql/ommysql.c49
-rw-r--r--plugins/ompgsql/ompgsql.c11
-rw-r--r--plugins/omprog/omprog.c33
-rw-r--r--plugins/omrelp/omrelp.c11
-rw-r--r--plugins/omruleset/omruleset.c37
-rw-r--r--plugins/omsnmp/omsnmp.c177
-rw-r--r--plugins/omstdout/omstdout.c31
-rw-r--r--plugins/omtemplate/omtemplate.c22
-rw-r--r--plugins/omtesting/omtesting.c17
-rw-r--r--plugins/omudpspoof/omudpspoof.c85
-rw-r--r--plugins/omuxsock/omuxsock.c37
-rw-r--r--rsyslog.service.in2
-rw-r--r--runtime/Makefile.am6
-rw-r--r--runtime/cfsysline.c39
-rw-r--r--runtime/cfsysline.h18
-rw-r--r--runtime/conf.c170
-rw-r--r--runtime/conf.h10
-rw-r--r--runtime/ctok.c3
-rw-r--r--runtime/ctok_token.h1
-rw-r--r--runtime/debug.c40
-rw-r--r--runtime/expr.c5
-rw-r--r--runtime/glbl.h2
-rw-r--r--runtime/module-template.h50
-rw-r--r--runtime/modules.c3
-rw-r--r--runtime/modules.h4
-rw-r--r--runtime/msg.c145
-rw-r--r--runtime/msg.h8
-rw-r--r--runtime/netstrm.c2
-rw-r--r--runtime/netstrms.c1
-rw-r--r--runtime/nsd.h12
-rw-r--r--runtime/nsd_gtls.c26
-rw-r--r--runtime/nsdpoll_ptcp.c50
-rw-r--r--runtime/nsdpoll_ptcp.h1
-rw-r--r--runtime/nspoll.c6
-rw-r--r--runtime/nspoll.h5
-rw-r--r--runtime/rsyslog.h19
-rw-r--r--runtime/rule.c53
-rw-r--r--runtime/rule.h2
-rw-r--r--runtime/stringbuf.c29
-rw-r--r--runtime/stringbuf.h2
-rw-r--r--runtime/typedefs.h35
-rw-r--r--runtime/var.h1
-rw-r--r--runtime/vm.c27
-rw-r--r--runtime/vmop.h1
-rw-r--r--tcpclt.c2
-rw-r--r--tcps_sess.c6
-rw-r--r--tcpsrv.c258
-rw-r--r--tcpsrv.h17
-rw-r--r--template.c24
-rw-r--r--template.h3
-rw-r--r--tests/Makefile.am36
-rwxr-xr-xtests/diag.sh4
-rw-r--r--tests/filewriter.c158
-rwxr-xr-xtests/imtcp-tls-basic.sh14
-rwxr-xr-xtests/sndrcv_drvr.sh1
-rwxr-xr-xtests/sndrcv_tls_anon_rebind.sh5
-rw-r--r--tests/testsuites/imtcp-tls-basic.conf21
-rw-r--r--tests/testsuites/sndrcv_tls_anon_rebind_rcvr.conf22
-rw-r--r--tests/testsuites/sndrcv_tls_anon_rebind_sender.conf20
-rw-r--r--tests/testsuites/udp-msgreduc-orgmsg-vg.conf11
-rw-r--r--tests/testsuites/udp-msgreduc-vg.conf11
-rwxr-xr-xtests/udp-msgreduc-orgmsg-vg.sh18
-rwxr-xr-xtests/udp-msgreduc-vg.sh18
-rw-r--r--tools/Makefile.am2
-rw-r--r--tools/omdiscard.c13
-rw-r--r--tools/omfile.c159
-rw-r--r--tools/omfwd.c198
-rw-r--r--tools/ompipe.c11
-rw-r--r--tools/omshell.c11
-rw-r--r--tools/omusrmsg.c23
-rw-r--r--tools/syslogd.c5
112 files changed, 4952 insertions, 958 deletions
diff --git a/ChangeLog b/ChangeLog
index 7cfc3a00..4d718d95 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,277 @@
---------------------------------------------------------------------------
+Version 6.2.1 [v6-stable], 2012-01-??
+- change plugin config interface to be compatible with pre-v6.2 system
+ The functionality was already removed (because it is superseeded by the
+ v6.3+ config language), but code was still present. I have now removed
+ those parts that affect interface. Full removal will happen in v6.3, in
+ order to limit potential regressions. However, it was considered useful
+ enough to do the interface change in v6-stable; this also eases merging
+ branches!
+- re-licensed larger parts of the codebase under the Apache license 2.0
+- bugfix: omprog made rsyslog abort on startup if not binary to
+ execute was configured
+- bugfix: imklog invalidly computed facility and severity
+ closes: http://bugzilla.adiscon.com/show_bug.cgi?id=313
+- bugfix: stopped DA queue was never processed after a restart due to a
+ regression from statistics module
+- bugfix: memory leak in array passing output module mode
+- bugfix: ommysql did not properly init/exit the mysql runtime library
+ this could lead to segfaults. Triggering condition: multiple action
+ instances using ommysql. Thanks to Tomas Heinrich for reporting this
+ problem and providing an initial patch (which my solution is based on,
+ I need to add more code to clean the mess up).
+- bugfix: rsyslog did not terminate when delayable inputs were blocked
+ due to unvailable sources. Fixes:
+ http://bugzilla.adiscon.com/show_bug.cgi?id=299
+ Thanks to Marcin M for bringing up this problem and Andre Lorbach
+ for helping to reproduce and fix it.
+---------------------------------------------------------------------------
+Version 6.2.0 [v6-stable], 2012-01-09
+- bugfix (kind of): removed numerical part from pri-text
+ see v6 compatibility document for reasons
+- bugfix: race condition when extracting program name, APPNAME, structured
+ data and PROCID (RFC5424 fields) could lead to invalid characters e.g.
+ in dynamic file names or during forwarding (general malfunction of these
+ fields in templates, mostly under heavy load)
+- bugfix: imuxsock did no longer ignore message-provided timestamp, if
+ so configured (the *default*). Lead to no longer sub-second timestamps.
+ closes: http://bugzilla.adiscon.com/show_bug.cgi?id=281
+- bugfix: omfile returns fatal error code for things that go really wrong
+ previously, RS_RET_RESUME was returned, which lead to a loop inside the
+ rule engine as omfile could not really recover.
+- bugfix: rsyslogd -v always said 64 atomics were not present
+ thanks to mono_matsuko for the patch
+- bugfix: potential abort after reading invalid X.509 certificate
+ closes: http://bugzilla.adiscon.com/show_bug.cgi?id=290
+ Thanks to Tomas Heinrich for the patch
+- $Begin, $End, $StrictScoping directives have been removed as v6.4 will
+ provide the same functionality in a far better way. So we do not want
+ to clutter the code.
+---------------------------------------------------------------------------
+Version 6.1.12 [BETA], 2011-09-01
+- bugfix/security: off-by-two bug in legacy syslog parser, CVE-2011-3200
+- bugfix: mark message processing did not work correctly
+- bugfix: potential misadressing in property replacer
+- bugfix: memcpy overflow can occur in allowed sender checkig
+ if a name is resolved to IPv4-mapped-on-IPv6 address
+ Found by Ismail Dönmez at suse
+- bugfix: The NUL-Byte for the syslogtag was not copied in MsgDup (msg.c)
+- bugfix: fixed incorrect state handling for Discard Action (transactions)
+ Note: This caused all messages in a batch to be set to COMMITTED,
+ even if they were discarded.
+---------------------------------------------------------------------------
+Version 6.1.11 [BETA] (rgerhards), 2011-07-11
+- systemd support: set stdout/stderr to null - thx to Lennart for the patch
+- added support for the ":omusrmsg:" syntax in configuring user messages
+- added support for the ":omfile:" syntax in configuring user messages
+---------------------------------------------------------------------------
+Version 6.1.10 [BETA] (rgerhards), 2011-06-22
+- bugfix: problems in failover action handling
+ closes: http://bugzilla.adiscon.com/show_bug.cgi?id=270
+ closes: http://bugzilla.adiscon.com/show_bug.cgi?id=254
+- bugfix: mutex was invalidly left unlocked during action processing
+ At least one case where this can occur is during thread shutdown, which
+ may be initiated by lower activity. In most cases, this is quite
+ unlikely to happen. However, if it does, data structures may be
+ corrupted which could lead to fatal failure and segfault. I detected
+ this via a testbench test, not a user report. But I assume that some
+ users may have had unreproducable aborts that were cause by this bug.
+---------------------------------------------------------------------------
+Version 6.1.9 [BETA] (rgerhards), 2011-06-14
+- bugfix: problems in failover action handling
+ closes: http://bugzilla.adiscon.com/show_bug.cgi?id=270
+ closes: http://bugzilla.adiscon.com/show_bug.cgi?id=254
+- bugfix: mutex was invalidly left unlocked during action processing
+ At least one case where this can occur is during thread shutdown, which
+ may be initiated by lower activity. In most cases, this is quite
+ unlikely to happen. However, if it does, data structures may be
+ corrupted which could lead to fatal failure and segfault. I detected
+ this via a testbench test, not a user report. But I assume that some
+ users may have had unreproducable aborts that were cause by this bug.
+- bugfix/improvement:$WorkDirectory now gracefully handles trailing slashes
+---------------------------------------------------------------------------
+Version 6.1.9 [BETA] (rgerhards), 2011-06-14
+- bugfix: memory leak in imtcp & subsystems under some circumstances
+ This leak is tied to error conditions which lead to incorrect cleanup
+ of some data structures. [backport from v6.3]
+- bugfix: $ActionFileDefaultTemplate did not work
+ closes: http://bugzilla.adiscon.com/show_bug.cgi?id=262
+---------------------------------------------------------------------------
+Version 6.1.8 [BETA] (rgerhards), 2011-05-20
+- official new beta version (note that in a sense 6.1.7 was already beta,
+ so we may release the first stable v6 earlier than usual)
+- new module mmsnmptrapd, a sample message modification module
+- import of minor bug fixes from v4 & v5
+---------------------------------------------------------------------------
+Version 6.1.7 [DEVEL] (rgerhards), 2011-04-15
+- added log classification capabilities (via mmnormalize & tags)
+- speeded up tcp forwarding by reducing number of API calls
+ this especially speeds up TLS processing
+- somewhat improved documentation index
+- bugfix: enhanced imudp config processing code disabled due to wrong
+ merge (affected UDP realtime capabilities)
+- bugfix (kind of): memory leak with tcp reception epoll handler
+ This was an extremely unlikely leak and, if it happend, quite small.
+ Still it is better to handle this border case.
+- bugfix: IPv6-address could not be specified in omrelp
+ this was due to improper parsing of ":"
+ closes: http://bugzilla.adiscon.com/show_bug.cgi?id=250
+---------------------------------------------------------------------------
+Version 6.1.6 [DEVEL] (rgerhards), 2011-03-14
+- enhanced omhdfs to support batching mode. This permits to increase
+ performance, as we now call the HDFS API with much larger message
+ sizes and far more infrequently
+- improved testbench
+ among others, life tests for ommysql (against a test database) have
+ been added, valgrind-based testing enhanced, ...
+- bugfix: minor memory leak in omlibdbi (< 1k per instance and run)
+- bugfix: (regression) omhdfs did no longer compile
+- bugfix: omlibdbi did not use password from rsyslog.con
+ closes: http://bugzilla.adiscon.com/show_bug.cgi?id=203
+- systemd support somewhat improved (can now take over existing log sockt)
+- bugfix: discard action did not work under some circumstances
+ fixes: http://bugzilla.adiscon.com/show_bug.cgi?id=217
+- bugfix: file descriptor leak in gnutls netstream driver
+ fixes: http://bugzilla.adiscon.com/show_bug.cgi?id=222
+- fixed compile problem in imtemplate
+ fixes: http://bugzilla.adiscon.com/show_bug.cgi?id=235
+---------------------------------------------------------------------------
+Version 6.1.5 [DEVEL] (rgerhards), 2011-03-04
+- improved testbench
+- enhanced imtcp to use a pool of worker threads to process incoming
+ messages. This enables higher processing rates, especially in the TLS
+ case (where more CPU is needed for the crypto functions)
+- added support for TLS (in anon mode) to tcpflood
+- improved TLS error reporting
+- improved TLS startup (Diffie-Hellman bits do not need to be generated,
+ as we do not support full anon key exchange -- we always need certs)
+- bugfix: fixed a memory leak and potential abort condition
+ this could happen if multiple rulesets were used and some output batches
+ contained messages belonging to more than one ruleset.
+ fixes: http://bugzilla.adiscon.com/show_bug.cgi?id=226
+ fixes: http://bugzilla.adiscon.com/show_bug.cgi?id=218
+- bugfix: memory leak when $RepeatedMsgReduction on was used
+ bug tracker: http://bugzilla.adiscon.com/show_bug.cgi?id=225
+- bugfix: potential abort condition when $RepeatedMsgReduction set to on
+ as well as potentially in a number of other places where MsgDup() was
+ used. This only happened when the imudp input module was used and it
+ depended on name resolution not yet had taken place. In other words,
+ this was a strange problem that could lead to hard to diagnose
+ instability. So if you experience instability, chances are good that
+ this fix will help.
+---------------------------------------------------------------------------
+Version 6.1.4 [DEVEL] (rgerhards), 2011-02-18
+- bugfix/omhdfs: directive $OMHDFSFileName rendered unusable
+ due to a search and replace-induced bug ;)
+- bugfix: minor race condition in action.c - considered cosmetic
+ This is considered cosmetic as multiple threads tried to write exactly
+ the same value into the same memory location without sync. The method
+ has been changed so this can no longer happen.
+- added pmsnare parser module (written by David Lang)
+- enhanced imfile to support non-cancel input termination
+- improved systemd socket activation thanks to Marius Tomaschweski
+- improved error reporting for $WorkDirectory
+ non-existance and other detectable problems are now reported,
+ and the work directory is NOT set in this case
+- bugfix: pmsnare causded abort under some conditions
+- bugfix: abort if imfile reads file line of more than 64KiB
+ Thanks to Peter Eisentraut for reporting and analysing this problem.
+ bug tracker: http://bugzilla.adiscon.com/show_bug.cgi?id=221
+- bugfix: queue engine did not properly slow down inputs in FULL_DELAY mode
+ when in disk-assisted mode. This especially affected imfile, which
+ created unnecessarily queue files if a large set of input file data was
+ to process.
+- bugfix: very long running actions could prevent shutdown under some
+ circumstances. This has now been solved, at least for common
+ situations.
+- bugfix: fixed compile problem due to empty structs
+ this occured only on some platforms/compilers. thanks to Dražen Kačar
+ for the fix
+---------------------------------------------------------------------------
+Version 6.1.3 [DEVEL] (rgerhards), 2011-02-01
+- experimental support for monogodb added
+- added $IMUDPSchedulingPolicy and $IMUDPSchedulingPriority config settings
+- added $LocalHostName config directive
+- improved tcpsrv performance by enabling multiple-entry epoll
+ so far, we always pulled a single event from the epoll interface.
+ Now 128, what should result in performance improvement (less API
+ calls) on busy systems. Most importantly affects imtcp.
+- imptcp now supports non-cancel termination mode, a plus in stability
+- imptcp speedup: multiple worker threads can now be used to read data
+- new directive $InputIMPTcpHelperThreads added
+- bugfix: fixed build problems on some platforms
+ namely those that have 32bit atomic operations but not 64 bit ones
+- bugfix: local hostname was pulled too-early, so that some config
+ directives (namely FQDN settings) did not have any effect
+- enhanced tcpflood to support multiple sender threads
+ this is required for some high-throughput scenarios (and necessary to
+ run some performance tests, because otherwise the sender is too slow).
+- added some new custom parsers (snare, aix, some Cisco "specialities")
+ thanks to David Lang
+---------------------------------------------------------------------------
+Version 6.1.2 [DEVEL] (rgerhards), 2010-12-16
+- added experimental support for log normalizaton (via liblognorm)
+ support for normalizing log messages has been added in the form of
+ mmnormalize. The core engine (property replacer, filter engine) has
+ been enhanced to support properties from normalized events.
+ Note: this is EXPERIMENTAL code. It is currently know that
+ there are issues if the functionality is used with
+ - disk-based queues
+ - asynchronous action queues
+ You can not use the new functionality together with these features.
+ This limitation will be removed in later releases. However, we
+ preferred to release early, so that one can experiment with the new
+ feature set and accepted the price that this means the full set of
+ functionality is not yet available. If not used together with
+ these features, log normalizing should be pretty stable.
+- enhanced testing tool tcpflood
+ now supports sending via UDP and the capability to run multiple
+ iterations and generate statistics data records
+- bugfix: potential abort when output modules with different parameter
+ passing modes were used in configured output modules
+---------------------------------------------------------------------------
+Version 6.1.1 [DEVEL] (rgerhards), 2010-11-30
+- bugfix(important): problem in TLS handling could cause rsyslog to loop
+ in a tight loop, effectively disabling functionality and bearing the
+ risk of unresponsiveness of the whole system.
+ Bug tracker: http://bugzilla.adiscon.com/show_bug.cgi?id=194
+- support for omhdfs officially added (import from 5.7.1)
+- merged imuxsock improvements from 5.7.1 (see there)
+- support for systemd officially added (import from 5.7.0)
+- bugfix: a couple of problems that imfile had on some platforms, namely
+ Ubuntu (not their fault, but occured there)
+- bugfix: imfile utilizes 32 bit to track offset. Most importantly,
+ this problem can not experienced on Fedora 64 bit OS (which has
+ 64 bit long's!)
+- a number of other bugfixes from older versions imported
+---------------------------------------------------------------------------
+Version 6.1.0 [DEVEL] (rgerhards), 2010-08-12
+
+*********************************** NOTE **********************************
+The v6 versions of rsyslog feature a greatly redesigned config system
+which, among others, supports scoping. However, the initial version does
+not contain the whole new system. Rather it will evolve. So it is
+expected that interfaces, even new ones, break during the initial
+6.x.y releases.
+*********************************** NOTE **********************************
+
+- added $Begin, $End and $ScriptScoping config scope statments
+ (at this time for actions only).
+- added imptcp, a simplified, Linux-specific and potentielly fast
+ syslog plain tcp input plugin (NOT supporting TLS!)
+ [ported from v4]
+---------------------------------------------------------------------------
+Version 5.9.0 [V5-DEVEL] (rgerhards), 2011-03-??
+- this begins a new devel branch for v5
+- added new config directive $InputTCPFlowControl to select if tcp
+ received messages shall be flagged as light delayable or not.
+- enhanced omhdfs to support batching mode. This permits to increase
+ performance, as we now call the HDFS API with much larger message
+ sizes and far more infrequently
+- bugfix: failover did not work correctly if repeated msg reduction was on
+ affected directive was: $ActionExecOnlyWhenPreviousIsSuspended on
+ closes: http://bugzilla.adiscon.com/show_bug.cgi?id=236
+---------------------------------------------------------------------------
Version 5.8.11 [V5-stable] 2012-05-03
- bugfix: ommysql did not properly init/exit the mysql runtime library
this could lead to segfaults. Triggering condition: multiple action
@@ -344,6 +617,7 @@ Version 5.7.0 [V5-DEVEL] (rgerhards), 2010-09-16
Version 5.6.5 [V5-STABLE] (rgerhards), 2011-03-22
- bugfix: failover did not work correctly if repeated msg reduction was on
affected directive was: $ActionExecOnlyWhenPreviousIsSuspended on
+ closes: http://bugzilla.adiscon.com/show_bug.cgi?id=236
- bugfix: omlibdbi did not use password from rsyslog.con
closes: http://bugzilla.adiscon.com/show_bug.cgi?id=203
- bugfix(kind of): tell users that config graph can currently not be
diff --git a/Makefile.am b/Makefile.am
index 48eb26ce..b7bbe1c5 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -182,6 +182,10 @@ if ENABLE_IMPTCP
SUBDIRS += plugins/imptcp
endif
+if ENABLE_IMTTCP
+SUBDIRS += plugins/imttcp
+endif
+
if ENABLE_IMDIAG
SUBDIRS += plugins/imdiag
endif
@@ -198,6 +202,10 @@ if ENABLE_RFC3195
SUBDIRS += plugins/im3195
endif
+if ENABLE_MMNORMALIZE
+SUBDIRS += plugins/mmnormalize
+endif
+
if ENABLE_ORACLE
SUBDIRS += plugins/omoracle
endif
@@ -218,6 +226,7 @@ SUBDIRS += tests
# 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-gnutls \
--enable-imfile \
--enable-snmp \
--enable-pgsql \
@@ -235,10 +244,10 @@ DISTCHECK_CONFIGURE_FLAGS= --enable-gssapi_krb5 \
--enable-omprog \
--enable-imdiag \
--enable-imptcp \
+ --enable-imttcp \
--enable-omuxsock \
--enable-extended-tests \
--enable-impstats \
- --enable-imptcp \
--enable-memcheck \
--enable-pmaixforwardedfrom \
--enable-pmcisconames \
diff --git a/action.c b/action.c
index e859cce4..6c5c9653 100644
--- a/action.c
+++ b/action.c
@@ -128,38 +128,44 @@ DEFobjCurrIf(datetime)
DEFobjCurrIf(module)
DEFobjCurrIf(errmsg)
-static int iActExecOnceInterval = 0; /* execute action once every nn seconds */
-static int iActExecEveryNthOccur = 0; /* execute action every n-th occurence (0,1=always) */
-static time_t iActExecEveryNthOccurTO = 0; /* timeout for n-occurence setting (in seconds, 0=never) */
-static int glbliActionResumeInterval = 30;
-int glbliActionResumeRetryCount = 0; /* how often should suspended actions be retried? */
-static int bActionRepMsgHasMsg = 0; /* last messsage repeated... has msg fragment in it */
-
-static int bActionWriteAllMarkMsgs = FALSE; /* should all mark messages be unconditionally written? */
-static uchar *pszActionName; /* short name for the action */
-/* action queue and its configuration parameters */
-static queueType_t ActionQueType = QUEUETYPE_DIRECT; /* type of the main message queue above */
-static int iActionQueueSize = 1000; /* size of the main message queue above */
-static int iActionQueueDeqBatchSize = 16; /* batch size for action queues */
-static int iActionQHighWtrMark = 800; /* high water mark for disk-assisted queues */
-static int iActionQLowWtrMark = 200; /* low water mark for disk-assisted queues */
-static int iActionQDiscardMark = 9800; /* begin to discard messages */
-static int iActionQDiscardSeverity = 8; /* by default, discard nothing to prevent unintentional loss */
-static int iActionQueueNumWorkers = 1; /* number of worker threads for the mm queue above */
-static uchar *pszActionQFName = NULL; /* prefix for the main message queue file */
-static int64 iActionQueMaxFileSize = 1024*1024;
-static int iActionQPersistUpdCnt = 0; /* persist queue info every n updates */
-static int bActionQSyncQeueFiles = 0; /* sync queue files */
-static int iActionQtoQShutdown = 0; /* queue shutdown */
-static int iActionQtoActShutdown = 1000; /* action shutdown (in phase 2) */
-static int iActionQtoEnq = 2000; /* timeout for queue enque */
-static int iActionQtoWrkShutdown = 60000; /* timeout for worker thread shutdown */
-static int iActionQWrkMinMsgs = 100; /* minimum messages per worker needed to start a new one */
-static int bActionQSaveOnShutdown = 1; /* save queue on shutdown (when DA enabled)? */
-static int64 iActionQueMaxDiskSpace = 0; /* max disk space allocated 0 ==> unlimited */
-static int iActionQueueDeqSlowdown = 0; /* dequeue slowdown (simple rate limiting) */
-static int iActionQueueDeqtWinFromHr = 0; /* hour begin of time frame when queue is to be dequeued */
-static int iActionQueueDeqtWinToHr = 25; /* hour begin of time frame when queue is to be dequeued */
+
+typedef struct configSettings_s {
+ int bActExecWhenPrevSusp; /* execute action only when previous one was suspended? */
+ int bActionWriteAllMarkMsgs; /* should all mark messages be unconditionally written? */
+ int iActExecOnceInterval; /* execute action once every nn seconds */
+ int iActExecEveryNthOccur; /* execute action every n-th occurence (0,1=always) */
+ time_t iActExecEveryNthOccurTO; /* timeout for n-occurence setting (in seconds, 0=never) */
+ int glbliActionResumeInterval;
+ int glbliActionResumeRetryCount; /* how often should suspended actions be retried? */
+ int bActionRepMsgHasMsg; /* last messsage repeated... has msg fragment in it */
+ uchar *pszActionName; /* short name for the action */
+ /* action queue and its configuration parameters */
+ queueType_t ActionQueType; /* type of the main message queue above */
+ int iActionQueueSize; /* size of the main message queue above */
+ int iActionQueueDeqBatchSize; /* batch size for action queues */
+ int iActionQHighWtrMark; /* high water mark for disk-assisted queues */
+ int iActionQLowWtrMark; /* low water mark for disk-assisted queues */
+ int iActionQDiscardMark; /* begin to discard messages */
+ int iActionQDiscardSeverity; /* by default, discard nothing to prevent unintentional loss */
+ int iActionQueueNumWorkers; /* number of worker threads for the mm queue above */
+ uchar *pszActionQFName; /* prefix for the main message queue file */
+ int64 iActionQueMaxFileSize;
+ int iActionQPersistUpdCnt; /* persist queue info every n updates */
+ int bActionQSyncQeueFiles; /* sync queue files */
+ int iActionQtoQShutdown; /* queue shutdown */
+ int iActionQtoActShutdown; /* action shutdown (in phase 2) */
+ int iActionQtoEnq; /* timeout for queue enque */
+ int iActionQtoWrkShutdown; /* timeout for worker thread shutdown */
+ int iActionQWrkMinMsgs; /* minimum messages per worker needed to start a new one */
+ int bActionQSaveOnShutdown; /* save queue on shutdown (when DA enabled)? */
+ int64 iActionQueMaxDiskSpace; /* max disk space allocated 0 ==> unlimited */
+ int iActionQueueDeqSlowdown; /* dequeue slowdown (simple rate limiting) */
+ int iActionQueueDeqtWinFromHr; /* hour begin of time frame when queue is to be dequeued */
+ int iActionQueueDeqtWinToHr; /* hour begin of time frame when queue is to be dequeued */
+} configSettings_t;
+
+configSettings_t cs; /* our current config settings */
+configSettings_t cs_save; /* our saved (scope!) config settings */
/* the counter below counts actions created. It is used to obtain unique IDs for the action. They
* should not be relied on for any long-term activity (e.g. disk queue names!), but they are nice
@@ -220,32 +226,32 @@ actionResetQueueParams(void)
{
DEFiRet;
- ActionQueType = QUEUETYPE_DIRECT; /* type of the main message queue above */
- iActionQueueSize = 1000; /* size of the main message queue above */
- iActionQueueDeqBatchSize = 16; /* default batch size */
- iActionQHighWtrMark = 800; /* high water mark for disk-assisted queues */
- iActionQLowWtrMark = 200; /* low water mark for disk-assisted queues */
- iActionQDiscardMark = 9800; /* begin to discard messages */
- iActionQDiscardSeverity = 8; /* discard warning and above */
- iActionQueueNumWorkers = 1; /* number of worker threads for the mm queue above */
- iActionQueMaxFileSize = 1024*1024;
- iActionQPersistUpdCnt = 0; /* persist queue info every n updates */
- bActionQSyncQeueFiles = 0;
- iActionQtoQShutdown = 0; /* queue shutdown */
- iActionQtoActShutdown = 1000; /* action shutdown (in phase 2) */
- iActionQtoEnq = 2000; /* timeout for queue enque */
- iActionQtoWrkShutdown = 60000; /* timeout for worker thread shutdown */
- iActionQWrkMinMsgs = 100; /* minimum messages per worker needed to start a new one */
- bActionQSaveOnShutdown = 1; /* save queue on shutdown (when DA enabled)? */
- iActionQueMaxDiskSpace = 0;
- iActionQueueDeqSlowdown = 0;
- iActionQueueDeqtWinFromHr = 0;
- iActionQueueDeqtWinToHr = 25; /* 25 disables time windowed dequeuing */
-
- glbliActionResumeRetryCount = 0; /* I guess it is smart to reset this one, too */
-
- d_free(pszActionQFName);
- pszActionQFName = NULL; /* prefix for the main message queue file */
+ cs.ActionQueType = QUEUETYPE_DIRECT; /* type of the main message queue above */
+ cs.iActionQueueSize = 1000; /* size of the main message queue above */
+ cs.iActionQueueDeqBatchSize = 16; /* default batch size */
+ cs.iActionQHighWtrMark = 800; /* high water mark for disk-assisted queues */
+ cs.iActionQLowWtrMark = 200; /* low water mark for disk-assisted queues */
+ cs.iActionQDiscardMark = 9800; /* begin to discard messages */
+ cs.iActionQDiscardSeverity = 8; /* discard warning and above */
+ cs.iActionQueueNumWorkers = 1; /* number of worker threads for the mm queue above */
+ cs.iActionQueMaxFileSize = 1024*1024;
+ cs.iActionQPersistUpdCnt = 0; /* persist queue info every n updates */
+ cs.bActionQSyncQeueFiles = 0;
+ cs.iActionQtoQShutdown = 0; /* queue shutdown */
+ cs.iActionQtoActShutdown = 1000; /* action shutdown (in phase 2) */
+ cs.iActionQtoEnq = 2000; /* timeout for queue enque */
+ cs.iActionQtoWrkShutdown = 60000; /* timeout for worker thread shutdown */
+ cs.iActionQWrkMinMsgs = 100; /* minimum messages per worker needed to start a new one */
+ cs.bActionQSaveOnShutdown = 1; /* save queue on shutdown (when DA enabled)? */
+ cs.iActionQueMaxDiskSpace = 0;
+ cs.iActionQueueDeqSlowdown = 0;
+ cs.iActionQueueDeqtWinFromHr = 0;
+ cs.iActionQueueDeqtWinToHr = 25; /* 25 disables time windowed dequeuing */
+
+ cs.glbliActionResumeRetryCount = 0; /* I guess it is smart to reset this one, too */
+
+ d_free(cs.pszActionQFName);
+ cs.pszActionQFName = NULL; /* prefix for the main message queue file */
RETiRet;
}
@@ -291,8 +297,8 @@ rsRetVal actionConstruct(action_t **ppThis)
ASSERT(ppThis != NULL);
CHKmalloc(pThis = (action_t*) calloc(1, sizeof(action_t)));
- pThis->iResumeInterval = glbliActionResumeInterval;
- pThis->iResumeRetryCount = glbliActionResumeRetryCount;
+ pThis->iResumeInterval = cs.glbliActionResumeInterval;
+ pThis->iResumeRetryCount = cs.glbliActionResumeRetryCount;
pThis->tLastOccur = datetime.GetTime(NULL); /* done once per action on startup only */
pthread_mutex_init(&pThis->mutActExec, NULL);
INIT_ATOMIC_HELPER_MUT(pThis->mutCAS);
@@ -351,7 +357,7 @@ actionConstructFinalize(action_t *pThis)
* msg object thread safety in this case (this costs a bit performance and thus
* is not enabled by default. -- rgerhards, 2008-02-20
*/
- if(ActionQueType != QUEUETYPE_DIRECT)
+ if(cs.ActionQueType != QUEUETYPE_DIRECT)
MsgEnableThreadSafety();
/* create queue */
@@ -360,7 +366,7 @@ actionConstructFinalize(action_t *pThis)
* to be run on multiple threads. So far, this is forbidden by the interface
* spec. -- rgerhards, 2008-01-30
*/
- CHKiRet(qqueueConstruct(&pThis->pQueue, ActionQueType, 1, iActionQueueSize,
+ CHKiRet(qqueueConstruct(&pThis->pQueue, cs.ActionQueType, 1, cs.iActionQueueSize,
(rsRetVal (*)(void*, batch_t*, int*))processBatchMain));
obj.SetName((obj_t*) pThis->pQueue, pszQName);
@@ -375,31 +381,31 @@ actionConstructFinalize(action_t *pThis)
}
qqueueSetpUsr(pThis->pQueue, pThis);
- setQPROP(qqueueSetsizeOnDiskMax, "$ActionQueueMaxDiskSpace", iActionQueMaxDiskSpace);
- setQPROP(qqueueSetiDeqBatchSize, "$ActionQueueDequeueBatchSize", iActionQueueDeqBatchSize);
- setQPROP(qqueueSetMaxFileSize, "$ActionQueueFileSize", iActionQueMaxFileSize);
- setQPROPstr(qqueueSetFilePrefix, "$ActionQueueFileName", pszActionQFName);
- setQPROP(qqueueSetiPersistUpdCnt, "$ActionQueueCheckpointInterval", iActionQPersistUpdCnt);
- setQPROP(qqueueSetbSyncQueueFiles, "$ActionQueueSyncQueueFiles", bActionQSyncQeueFiles);
- setQPROP(qqueueSettoQShutdown, "$ActionQueueTimeoutShutdown", iActionQtoQShutdown );
- setQPROP(qqueueSettoActShutdown, "$ActionQueueTimeoutActionCompletion", iActionQtoActShutdown);
- setQPROP(qqueueSettoWrkShutdown, "$ActionQueueWorkerTimeoutThreadShutdown", iActionQtoWrkShutdown);
- setQPROP(qqueueSettoEnq, "$ActionQueueTimeoutEnqueue", iActionQtoEnq);
- setQPROP(qqueueSetiHighWtrMrk, "$ActionQueueHighWaterMark", iActionQHighWtrMark);
- setQPROP(qqueueSetiLowWtrMrk, "$ActionQueueLowWaterMark", iActionQLowWtrMark);
- setQPROP(qqueueSetiDiscardMrk, "$ActionQueueDiscardMark", iActionQDiscardMark);
- setQPROP(qqueueSetiDiscardSeverity, "$ActionQueueDiscardSeverity", iActionQDiscardSeverity);
- setQPROP(qqueueSetiMinMsgsPerWrkr, "$ActionQueueWorkerThreadMinimumMessages", iActionQWrkMinMsgs);
- setQPROP(qqueueSetbSaveOnShutdown, "$ActionQueueSaveOnShutdown", bActionQSaveOnShutdown);
- setQPROP(qqueueSetiDeqSlowdown, "$ActionQueueDequeueSlowdown", iActionQueueDeqSlowdown);
- setQPROP(qqueueSetiDeqtWinFromHr, "$ActionQueueDequeueTimeBegin", iActionQueueDeqtWinFromHr);
- setQPROP(qqueueSetiDeqtWinToHr, "$ActionQueueDequeueTimeEnd", iActionQueueDeqtWinToHr);
+ setQPROP(qqueueSetsizeOnDiskMax, "$ActionQueueMaxDiskSpace", cs.iActionQueMaxDiskSpace);
+ setQPROP(qqueueSetiDeqBatchSize, "$ActionQueueDequeueBatchSize", cs.iActionQueueDeqBatchSize);
+ setQPROP(qqueueSetMaxFileSize, "$ActionQueueFileSize", cs.iActionQueMaxFileSize);
+ setQPROPstr(qqueueSetFilePrefix, "$ActionQueueFileName", cs.pszActionQFName);
+ setQPROP(qqueueSetiPersistUpdCnt, "$ActionQueueCheckpointInterval", cs.iActionQPersistUpdCnt);
+ setQPROP(qqueueSetbSyncQueueFiles, "$ActionQueueSyncQueueFiles", cs.bActionQSyncQeueFiles);
+ setQPROP(qqueueSettoQShutdown, "$ActionQueueTimeoutShutdown", cs.iActionQtoQShutdown );
+ setQPROP(qqueueSettoActShutdown, "$ActionQueueTimeoutActionCompletion", cs.iActionQtoActShutdown);
+ setQPROP(qqueueSettoWrkShutdown, "$ActionQueueWorkerTimeoutThreadShutdown", cs.iActionQtoWrkShutdown);
+ setQPROP(qqueueSettoEnq, "$ActionQueueTimeoutEnqueue", cs.iActionQtoEnq);
+ setQPROP(qqueueSetiHighWtrMrk, "$ActionQueueHighWaterMark", cs.iActionQHighWtrMark);
+ setQPROP(qqueueSetiLowWtrMrk, "$ActionQueueLowWaterMark", cs.iActionQLowWtrMark);
+ setQPROP(qqueueSetiDiscardMrk, "$ActionQueueDiscardMark", cs.iActionQDiscardMark);
+ setQPROP(qqueueSetiDiscardSeverity, "$ActionQueueDiscardSeverity", cs.iActionQDiscardSeverity);
+ setQPROP(qqueueSetiMinMsgsPerWrkr, "$ActionQueueWorkerThreadMinimumMessages", cs.iActionQWrkMinMsgs);
+ setQPROP(qqueueSetbSaveOnShutdown, "$ActionQueueSaveOnShutdown", cs.bActionQSaveOnShutdown);
+ setQPROP(qqueueSetiDeqSlowdown, "$ActionQueueDequeueSlowdown", cs.iActionQueueDeqSlowdown);
+ setQPROP(qqueueSetiDeqtWinFromHr, "$ActionQueueDequeueTimeBegin", cs.iActionQueueDeqtWinFromHr);
+ setQPROP(qqueueSetiDeqtWinToHr, "$ActionQueueDequeueTimeEnd", cs.iActionQueueDeqtWinToHr);
# undef setQPROP
# undef setQPROPstr
dbgoprint((obj_t*) pThis->pQueue, "save on shutdown %d, max disk space allowed %lld\n",
- bActionQSaveOnShutdown, iActionQueMaxDiskSpace);
+ cs.bActionQSaveOnShutdown, cs.iActionQueMaxDiskSpace);
CHKiRet(qqueueStart(pThis->pQueue));
@@ -418,7 +424,7 @@ finalize_it:
*/
rsRetVal actionSetGlobalResumeInterval(int iNewVal)
{
- glbliActionResumeInterval = iNewVal;
+ cs.glbliActionResumeInterval = iNewVal;
return RS_RET_OK;
}
@@ -1230,16 +1236,16 @@ static rsRetVal setActionQueType(void __attribute__((unused)) *pVal, uchar *pszT
DEFiRet;
if (!strcasecmp((char *) pszType, "fixedarray")) {
- ActionQueType = QUEUETYPE_FIXED_ARRAY;
+ cs.ActionQueType = QUEUETYPE_FIXED_ARRAY;
DBGPRINTF("action queue type set to FIXED_ARRAY\n");
} else if (!strcasecmp((char *) pszType, "linkedlist")) {
- ActionQueType = QUEUETYPE_LINKEDLIST;
+ cs.ActionQueType = QUEUETYPE_LINKEDLIST;
DBGPRINTF("action queue type set to LINKEDLIST\n");
} else if (!strcasecmp((char *) pszType, "disk")) {
- ActionQueType = QUEUETYPE_DISK;
+ cs.ActionQueType = QUEUETYPE_DISK;
DBGPRINTF("action queue type set to DISK\n");
} else if (!strcasecmp((char *) pszType, "direct")) {
- ActionQueType = QUEUETYPE_DIRECT;
+ cs.ActionQueType = QUEUETYPE_DIRECT;
DBGPRINTF("action queue type set to DIRECT (no queueing at all)\n");
} else {
errmsg.LogError(0, RS_RET_INVALID_PARAMS, "unknown actionqueue parameter: %s", (char *) pszType);
@@ -1705,17 +1711,17 @@ addAction(action_t **ppAction, modInfo_t *pMod, void *pModData, omodStringReques
CHKiRet(actionConstruct(&pAction)); /* create action object first */
pAction->pMod = pMod;
pAction->pModData = pModData;
- pAction->pszName = pszActionName;
- pszActionName = NULL; /* free again! */
- pAction->bWriteAllMarkMsgs = bActionWriteAllMarkMsgs;
- bActionWriteAllMarkMsgs = FALSE; /* reset */
- pAction->bExecWhenPrevSusp = bActExecWhenPrevSusp;
- pAction->iSecsExecOnceInterval = iActExecOnceInterval;
- pAction->iExecEveryNthOccur = iActExecEveryNthOccur;
- pAction->iExecEveryNthOccurTO = iActExecEveryNthOccurTO;
- pAction->bRepMsgHasMsg = bActionRepMsgHasMsg;
- iActExecEveryNthOccur = 0; /* auto-reset */
- iActExecEveryNthOccurTO = 0; /* auto-reset */
+ pAction->pszName = cs.pszActionName;
+ cs.pszActionName = NULL; /* free again! */
+ pAction->bWriteAllMarkMsgs = cs.bActionWriteAllMarkMsgs;
+ cs.bActionWriteAllMarkMsgs = FALSE; /* reset */
+ pAction->bExecWhenPrevSusp = cs.bActExecWhenPrevSusp;
+ pAction->iSecsExecOnceInterval = cs.iActExecOnceInterval;
+ pAction->iExecEveryNthOccur = cs.iActExecEveryNthOccur;
+ pAction->iExecEveryNthOccurTO = cs.iActExecEveryNthOccurTO;
+ pAction->bRepMsgHasMsg = cs.bActionRepMsgHasMsg;
+ cs.iActExecEveryNthOccur = 0; /* auto-reset */
+ cs.iActExecEveryNthOccurTO = 0; /* auto-reset */
/* check if we can obtain the template pointers - TODO: move to separate function? */
pAction->iNumTpls = OMSRgetEntryCount(pOMSR);
@@ -1803,11 +1809,63 @@ finalize_it:
static rsRetVal
resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
{
- iActExecOnceInterval = 0;
+ cs.iActExecOnceInterval = 0;
+ cs.bActExecWhenPrevSusp = 0;
return RS_RET_OK;
}
+/* initialize (current) config variables.
+ * Used at program start and when a new scope is created.
+ */
+static inline void
+initConfigVariables(void)
+{
+ cs.bActionWriteAllMarkMsgs = FALSE;
+ cs.glbliActionResumeRetryCount = 0;
+ cs.bActExecWhenPrevSusp = 0;
+ cs.iActExecOnceInterval = 0;
+ cs.iActExecEveryNthOccur = 0;
+ cs.iActExecEveryNthOccurTO = 0;
+ cs.glbliActionResumeInterval = 30;
+ cs.glbliActionResumeRetryCount = 0;
+ cs.bActionRepMsgHasMsg = 0;
+ if(cs.pszActionName != NULL) {
+ free(cs.pszActionName);
+ cs.pszActionName = NULL;
+ }
+ actionResetQueueParams();
+}
+
+
+/* save our config and create a new scope. Note that things are messed up if
+ * this is called while the config is already saved (we currently do not
+ * have a stack as the design is we need none!
+ * rgerhards, 2010-07-23
+ */
+rsRetVal
+actionNewScope(void)
+{
+ DEFiRet;
+ memcpy(&cs_save, &cs, sizeof(cs));
+ initConfigVariables();
+ RETiRet;
+}
+
+
+/* restore previously saved scope.
+ * rgerhards, 2010-07-23
+ */
+rsRetVal
+actionRestoreScope(void)
+{
+ DEFiRet;
+ memcpy(&cs, &cs_save, sizeof(cs));
+ RETiRet;
+}
+
+
+
/* TODO: we are not yet a real object, the ClassInit here just looks like it is..
*/
rsRetVal actionClassInit(void)
@@ -1819,36 +1877,40 @@ rsRetVal actionClassInit(void)
CHKiRet(objUse(module, CORE_COMPONENT));
CHKiRet(objUse(errmsg, CORE_COMPONENT));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionname", 0, eCmdHdlrGetWord, NULL, &pszActionName, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuefilename", 0, eCmdHdlrGetWord, NULL, &pszActionQFName, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuesize", 0, eCmdHdlrInt, NULL, &iActionQueueSize, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionwriteallmarkmessages", 0, eCmdHdlrBinary, NULL, &bActionWriteAllMarkMsgs, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuedequeuebatchsize", 0, eCmdHdlrInt, NULL, &iActionQueueDeqBatchSize, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuemaxdiskspace", 0, eCmdHdlrSize, NULL, &iActionQueMaxDiskSpace, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuehighwatermark", 0, eCmdHdlrInt, NULL, &iActionQHighWtrMark, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuelowwatermark", 0, eCmdHdlrInt, NULL, &iActionQLowWtrMark, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuediscardmark", 0, eCmdHdlrInt, NULL, &iActionQDiscardMark, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuediscardseverity", 0, eCmdHdlrInt, NULL, &iActionQDiscardSeverity, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuecheckpointinterval", 0, eCmdHdlrInt, NULL, &iActionQPersistUpdCnt, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuesyncqueuefiles", 0, eCmdHdlrBinary, NULL, &bActionQSyncQeueFiles, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionname", 0, eCmdHdlrGetWord, NULL, &cs.pszActionName, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuefilename", 0, eCmdHdlrGetWord, NULL, &cs.pszActionQFName, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuesize", 0, eCmdHdlrInt, NULL, &cs.iActionQueueSize, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionwriteallmarkmessages", 0, eCmdHdlrBinary, NULL, &cs.bActionWriteAllMarkMsgs, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuedequeuebatchsize", 0, eCmdHdlrInt, NULL, &cs.iActionQueueDeqBatchSize, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuemaxdiskspace", 0, eCmdHdlrSize, NULL, &cs.iActionQueMaxDiskSpace, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuehighwatermark", 0, eCmdHdlrInt, NULL, &cs.iActionQHighWtrMark, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuelowwatermark", 0, eCmdHdlrInt, NULL, &cs.iActionQLowWtrMark, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuediscardmark", 0, eCmdHdlrInt, NULL, &cs.iActionQDiscardMark, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuediscardseverity", 0, eCmdHdlrInt, NULL, &cs.iActionQDiscardSeverity, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuecheckpointinterval", 0, eCmdHdlrInt, NULL, &cs.iActionQPersistUpdCnt, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuesyncqueuefiles", 0, eCmdHdlrBinary, NULL, &cs.bActionQSyncQeueFiles, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuetype", 0, eCmdHdlrGetWord, setActionQueType, NULL, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionqueueworkerthreads", 0, eCmdHdlrInt, NULL, &iActionQueueNumWorkers, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuetimeoutshutdown", 0, eCmdHdlrInt, NULL, &iActionQtoQShutdown, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuetimeoutactioncompletion", 0, eCmdHdlrInt, NULL, &iActionQtoActShutdown, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuetimeoutenqueue", 0, eCmdHdlrInt, NULL, &iActionQtoEnq, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionqueueworkertimeoutthreadshutdown", 0, eCmdHdlrInt, NULL, &iActionQtoWrkShutdown, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionqueueworkerthreadminimummessages", 0, eCmdHdlrInt, NULL, &iActionQWrkMinMsgs, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuemaxfilesize", 0, eCmdHdlrSize, NULL, &iActionQueMaxFileSize, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuesaveonshutdown", 0, eCmdHdlrBinary, NULL, &bActionQSaveOnShutdown, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuedequeueslowdown", 0, eCmdHdlrInt, NULL, &iActionQueueDeqSlowdown, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuedequeuetimebegin", 0, eCmdHdlrInt, NULL, &iActionQueueDeqtWinFromHr, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuedequeuetimeend", 0, eCmdHdlrInt, NULL, &iActionQueueDeqtWinToHr, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionexeconlyeverynthtime", 0, eCmdHdlrInt, NULL, &iActExecEveryNthOccur, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionexeconlyeverynthtimetimeout", 0, eCmdHdlrInt, NULL, &iActExecEveryNthOccurTO, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionexeconlyonceeveryinterval", 0, eCmdHdlrInt, NULL, &iActExecOnceInterval, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"repeatedmsgcontainsoriginalmsg", 0, eCmdHdlrBinary, NULL, &bActionRepMsgHasMsg, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionqueueworkerthreads", 0, eCmdHdlrInt, NULL, &cs.iActionQueueNumWorkers, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuetimeoutshutdown", 0, eCmdHdlrInt, NULL, &cs.iActionQtoQShutdown, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuetimeoutactioncompletion", 0, eCmdHdlrInt, NULL, &cs.iActionQtoActShutdown, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuetimeoutenqueue", 0, eCmdHdlrInt, NULL, &cs.iActionQtoEnq, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionqueueworkertimeoutthreadshutdown", 0, eCmdHdlrInt, NULL, &cs.iActionQtoWrkShutdown, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionqueueworkerthreadminimummessages", 0, eCmdHdlrInt, NULL, &cs.iActionQWrkMinMsgs, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuemaxfilesize", 0, eCmdHdlrSize, NULL, &cs.iActionQueMaxFileSize, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuesaveonshutdown", 0, eCmdHdlrBinary, NULL, &cs.bActionQSaveOnShutdown, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuedequeueslowdown", 0, eCmdHdlrInt, NULL, &cs.iActionQueueDeqSlowdown, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuedequeuetimebegin", 0, eCmdHdlrInt, NULL, &cs.iActionQueueDeqtWinFromHr, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuedequeuetimeend", 0, eCmdHdlrInt, NULL, &cs.iActionQueueDeqtWinToHr, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionexeconlyeverynthtime", 0, eCmdHdlrInt, NULL, &cs.iActExecEveryNthOccur, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionexeconlyeverynthtimetimeout", 0, eCmdHdlrInt, NULL, &cs.iActExecEveryNthOccurTO, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionexeconlyonceeveryinterval", 0, eCmdHdlrInt, NULL, &cs.iActExecOnceInterval, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"repeatedmsgcontainsoriginalmsg", 0, eCmdHdlrBinary, NULL, &cs.bActionRepMsgHasMsg, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionexeconlywhenpreviousissuspended", 0, eCmdHdlrBinary, NULL, &cs.bActExecWhenPrevSusp, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionresumeretrycount", 0, eCmdHdlrInt, NULL, &cs.glbliActionResumeRetryCount, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, NULL));
+ initConfigVariables(); /* first-time init of config setings */
+
finalize_it:
RETiRet;
}
diff --git a/action.h b/action.h
index 0c08d3d6..a06b7c43 100644
--- a/action.h
+++ b/action.h
@@ -104,5 +104,7 @@ rsRetVal actionWriteToAction(action_t *pAction);
rsRetVal actionCallHUPHdlr(action_t *pAction);
rsRetVal actionClassInit(void);
rsRetVal addAction(action_t **ppAction, modInfo_t *pMod, void *pModData, omodStringRequest_t *pOMSR, int bSuspended);
+rsRetVal actionNewScope(void);
+rsRetVal actionRestoreScope(void);
#endif /* #ifndef ACTION_H_INCLUDED */
diff --git a/configure.ac b/configure.ac
index ff50984a..3edc3223 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.8.11],[rsyslog@lists.adiscon.com])
+AC_INIT([rsyslog],[6.2.0],[rsyslog@lists.adiscon.com])
AM_INIT_AUTOMAKE
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
@@ -35,6 +35,10 @@ AC_CANONICAL_HOST
PKG_PROG_PKG_CONFIG
+# modules we require
+PKG_CHECK_MODULES(LIBESTR, libestr >= 0.1.0)
+PKG_CHECK_MODULES(LIBEE, libee >= 0.3.1)
+
case "${host}" in
*-*-linux*)
os_type="linux"
@@ -697,6 +701,7 @@ AC_ARG_ENABLE(gnutls,
)
if test "x$enable_gnutls" = "xyes"; then
PKG_CHECK_MODULES(GNUTLS, gnutls >= 1.4.0)
+ AC_DEFINE([ENABLE_GNUTLS], [1], [Indicator that GnuTLS is present])
fi
AM_CONDITIONAL(ENABLE_GNUTLS, test x$enable_gnutls = xyes)
AC_SUBST(GNUTLS_CFLAGS)
@@ -799,6 +804,24 @@ AC_ARG_ENABLE(imdiag,
AM_CONDITIONAL(ENABLE_IMDIAG, test x$enable_imdiag = xyes)
+# mmnormalize
+AC_ARG_ENABLE(mmnormalize,
+ [AS_HELP_STRING([--enable-mmnormalize],[Enable building mmnormalize support @<:@default=no@:>@])],
+ [case "${enableval}" in
+ yes) enable_mmnormalize="yes" ;;
+ no) enable_mmnormalize="no" ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for --enable-mmnormalize) ;;
+ esac],
+ [enable_mmnormalize=no]
+)
+if test "x$enable_mmnormalize" = "xyes"; then
+ PKG_CHECK_MODULES(LIBLOGNORM, lognorm >= 0.3.1)
+fi
+AM_CONDITIONAL(ENABLE_MMNORMALIZE, test x$enable_mmnormalize = xyes)
+AC_SUBST(LOGNORM_CFLAGS)
+AC_SUBST(LOGNORM_LIBS)
+
+
# RELP support
AC_ARG_ENABLE(relp,
[AS_HELP_STRING([--enable-relp],[Enable RELP support @<:@default=no@:>@])],
@@ -887,6 +910,19 @@ AC_ARG_ENABLE(imptcp,
AM_CONDITIONAL(ENABLE_IMPTCP, test x$enable_imptcp = xyes)
+# settings for the ttcp input module
+AC_ARG_ENABLE(imttcp,
+ [AS_HELP_STRING([--enable-imttcp],[threaded plain tcp input module enabled @<:@default=no@:>@])],
+ [case "${enableval}" in
+ yes) enable_imttcp="yes" ;;
+ no) enable_imttcp="no" ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for --enable-imttcp) ;;
+ esac],
+ [enable_imttcp=no]
+)
+AM_CONDITIONAL(ENABLE_IMTTCP, test x$enable_imttcp = xyes)
+
+
# settings for the pstats input module
AC_ARG_ENABLE(impstats,
[AS_HELP_STRING([--enable-impstats],[periodic statistics module enabled @<:@default=no@:>@])],
@@ -1181,6 +1217,25 @@ AC_ARG_ENABLE(omhdfs,
AM_CONDITIONAL(ENABLE_OMHDFS, test x$enable_omhdfs = xyes)
+#MONGODB SUPPORT
+
+AC_ARG_ENABLE(ommongodb,
+ [AS_HELP_STRING([--enable-ommongodb],[Compiles ommongodb template module @<:@default=no@:>@])],
+ [case "${enableval}" in
+ yes) enable_ommongodb="yes" ;;
+ no) enable_ommongodb="no" ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for --enable-ommongodb) ;;
+ esac],
+ [enable_ommongodb=no]
+)
+#
+# you may want to do some library checks here - see snmp, mysql, pgsql modules
+# for samples
+#
+AM_CONDITIONAL(ENABLE_OMMONGODB, test x$enable_ommongodb = xyes)
+# end of copy template - be sure to search for omtemplate to find everything!
+
+
AC_CONFIG_FILES([Makefile \
runtime/Makefile \
tools/Makefile \
@@ -1208,6 +1263,7 @@ AC_CONFIG_FILES([Makefile \
plugins/imfile/Makefile \
plugins/imsolaris/Makefile \
plugins/imptcp/Makefile \
+ plugins/imttcp/Makefile \
plugins/impstats/Makefile \
plugins/imrelp/Makefile \
plugins/imdiag/Makefile \
@@ -1221,6 +1277,7 @@ AC_CONFIG_FILES([Makefile \
plugins/omsnmp/Makefile \
plugins/omoracle/Makefile \
plugins/omudpspoof/Makefile \
+ plugins/mmnormalize/Makefile \
plugins/sm_cust_bindcdr/Makefile \
plugins/mmsnmptrapd/Makefile \
plugins/cust1/Makefile \
@@ -1244,6 +1301,7 @@ echo
echo "---{ input plugins }---"
echo " Klog functionality enabled: $enable_klog ($os_type)"
echo " plain tcp input module enabled: $enable_imptcp"
+echo " threaded plain tcp input module enabled: $enable_imttcp"
echo " imdiag enabled: $enable_imdiag"
echo " file input module enabled: $enable_imfile"
echo " Solaris input module enabled: $enable_imsolaris"
@@ -1253,6 +1311,7 @@ echo
echo "---{ output plugins }---"
echo " Mail support enabled: $enable_mail"
echo " omprog module will be compiled: $enable_omprog"
+echo " output mongodb module will be compiled: $enable_ommongodb"
echo " omstdout module will be compiled: $enable_omstdout"
echo " omhdfs module will be compiled: $enable_omhdfs"
echo " omruleset module will be compiled: $enable_omruleset"
@@ -1269,6 +1328,7 @@ echo " pmaixforwardedfrom module w.be compiled: $enable_pmaixforwardedfrom"
echo " pmsnare module will be compiled: $enable_pmsnare"
echo
echo "---{ message modification modules }---"
+echo " mmnormalize module will be compiled: $enable_mmnormalize"
echo " mmsnmptrapd module will be compiled: $enable_mmsnmptrapd"
echo
echo "---{ strgen modules }---"
diff --git a/dirty.h b/dirty.h
index c1e75b44..0428a002 100644
--- a/dirty.h
+++ b/dirty.h
@@ -39,7 +39,6 @@ rsRetVal createMainQueue(qqueue_t **ppQueue, uchar *pszQueueName);
* we move to the next interval until we reach the largest.
* TODO: move this to action object! Only action.c and syslogd.c use it.
*/
-extern int bActExecWhenPrevSusp;
extern int MarkInterval;
extern int repeatinterval[2];
extern int bReduceRepeatMsgs;
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 91d92afd..04fda6b3 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -110,6 +110,7 @@ html_files = \
src/tls_cert.dia \
gssapi.html \
licensing.html \
+ mmnormalize.html \
ommail.html \
omuxsock.html \
omrelp.html \
diff --git a/doc/how2help.html b/doc/how2help.html
index 4f0bd57a..7fda6949 100644
--- a/doc/how2help.html
+++ b/doc/how2help.html
@@ -14,6 +14,9 @@ wish list, that would be awfully helpful!</p>
<li>spread word about rsyslog in forums and newsgroups</li>
<li>place a link to <a href="http://www.rsyslog.com">www.rsyslog.com</a>
from your home page</li>
+ <li>you may also want to tell others about the
+ <a href="http://loganalyzer.adiscon.com">log analyzer tool
+ created by the same folks as rsyslog</a> - at least, if you like it ;)
</ul>
</li>
<li>let us know about rsyslog - we are eager for feedback<ul>
@@ -54,4 +57,4 @@ wish list, that would be awfully helpful!</p>
might do!</p>
</body>
-</html
+</html>
diff --git a/doc/imptcp.html b/doc/imptcp.html
index d4228185..c7a0e599 100644
--- a/doc/imptcp.html
+++ b/doc/imptcp.html
@@ -53,6 +53,11 @@ name is not strictly necessary, but can be useful to apply filtering based on wh
the message was received from.
<li>$InputPTCPServerBindRuleset &lt;name&gt;<br>
Binds specified ruleset to next server defined.
+<li>$InputPTCPHelperThreads &lt;number&gt;<br>
+Number of helper worker threads to process incoming messages. These
+threads are utilized to pull data off the network. On a busy system, additional
+helper threads (but not more than there are CPUs/Cores) can help improving
+performance. The default value is two.
<li>$InputPTCPServerListenIP &lt;name&gt;<br>
On multi-homed machines, specifies to which local address the next listerner should
be bound.
diff --git a/doc/imtcp.html b/doc/imtcp.html
index 422bbd55..b0aaa3c1 100644
--- a/doc/imtcp.html
+++ b/doc/imtcp.html
@@ -57,6 +57,15 @@ instructs imtcp to emit a message if the remote peer closes a connection.<br>
after loading imtcp, otherwise it may have no effect.</li>
<li><b>$InputTCPServerRun</b> &lt;port&gt;<br>
Starts a TCP server on selected port</li>
+<li><b>$InputTCPFlowControl</b> &lt;<b>on</b>/off&gt;<br>
+This setting specifies whether some message flow control shall be exercised on the
+related TCP input. If set to on, messages are handled as "light delayable", which means
+the sender is throttled a bit when the queue becomes near-full. This is done in order
+to preserve some queue space for inputs that can not throttle (like UDP), but it
+may have some undesired effect in some configurations. Still, we consider this as
+a useful setting and thus it is the default. To turn the handling off, simply
+configure that explicitely.
+</li>
<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><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>
diff --git a/doc/imudp.html b/doc/imudp.html
index f0e86307..ea985b60 100644
--- a/doc/imudp.html
+++ b/doc/imudp.html
@@ -2,7 +2,7 @@
<html>
<head>
<meta http-equiv="Content-Language" content="en">
-<title>TCP Syslog Input Module</title>
+<title>UDP Syslog Input Module (imudp)</title>
</head>
<body>
@@ -35,6 +35,12 @@ You can set this value as high as you like, but do so at your own risk. The high
the value, the less precise the timestamp.
<li>$InputUDPServerBindRuleset &lt;ruleset&gt;<br>
Binds the listener to a specific <a href="multi_ruleset.html">ruleset</a>.</li>
+<li>$IMUDPSchedulingPolicy &lt;rr/fifo/other&gt;<br>
+Can be used the set the scheduler priority, if the necessary functionality
+is provided by the platform. Most useful to select "fifo" for real-time
+processing under Linux (and thus reduce chance of packet loss). Available since 4.7.4+, 5.7.3+, 6.1.3+.
+<li>$IMUDPSchedulingPriority &lt;number&gt;<br>
+Scheduling priority to use. Available since 4.7.4+, 5.7.3+, 6.1.3+.
</ul>
<b>Caveats/Known Bugs:</b>
<ul>
diff --git a/doc/manual.html b/doc/manual.html
index 2ee85570..b1c51410 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.8.11 (v5-stable branch) of rsyslog.</b>
+<p><b>This documentation is for version 6.2.0 (v6-stable branch) of rsyslog.</b>
Visit the <i><a href="http://www.rsyslog.com/status">rsyslog status page</a></i></b>
to obtain current version information and project status.
</p><p><b>If you like rsyslog, you might
@@ -32,13 +32,14 @@ between rsyslog and syslog-ng</a>.</p>
and if you are upgrading from v3, read the
<a href="v4compatibility.html">rsyslog v4 compatibility notes</a> and
if you upgrade from v4, read the
-<a href="v5compatibility.html">rsyslog v5 compatibility notes</a>.
+<a href="v5compatibility.html">rsyslog v5 compatibility notes</a>. Ther currently is
+no compatibility mode document for v6, as none is required right now.
<p>Rsyslog will work even
if you do not read the doc, but doing so will definitely improve your experience.</p>
<p><b>Follow the links below for the</b></p>
<ul>
<li><a href="troubleshoot.html">troubleshooting rsyslog problems</a></li>
-<li><a href="rsyslog_conf.html">configuration file syntax (rsyslog.conf)</a></li>
+<li><a href="rsyslog_conf.html">configuration file format (rsyslog.conf)</a></li>
<li><a href="http://www.rsyslog.com/tool-regex">a regular expression checker/generator tool for rsyslog</a></li>
<li> <a href="property_replacer.html">property replacer, an important core component</a></li>
<li><a href="bugs.html">rsyslog bug list</a></li>
diff --git a/doc/mmnormalize.html b/doc/mmnormalize.html
new file mode 100644
index 00000000..82f9b6a2
--- /dev/null
+++ b/doc/mmnormalize.html
@@ -0,0 +1,56 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head>
+<title>Log Message Normalization Module (mmnormalize)</title>
+</head>
+<body>
+<a href="rsyslog_conf_modules.html">back</a>
+
+<h1>Log Message Normalization Module</h1>
+<p><b>Module Name:&nbsp;&nbsp;&nbsp; mmnormalize</b></p>
+<p><b>Available since: </b>6.1.2+
+<p><b>Author: </b>Rainer Gerhards &lt;rgerhards@adiscon.com&gt;</p>
+<p><b>Description</b>:</p>
+<p>This module provides the capability to normalize log messages via
+<a href="http://www.liblognorm.com">liblognorm</a>. Thanks to libee, unstructured text,
+like usually found in log messages, can very quickly be parsed and put into
+a normal form. This is done so quickly, that it usually should be possible
+to normalize events in realtime.
+<p>This module is implemented via the output module interface. That means that
+mmnormalize should be called just like an action. After it has been called,
+the normalized message properties are avaialable and can be access. These properties
+are called the "CEE" properties, because liblognorm creates a format that is
+inspired by the CEE approach.
+<p>Note that mmnormalize should only be called once on each message. Behaviour is
+undifined if multiple calls to mmnormalize happen for the same message.
+</p>
+<p><b>Configuration Directives</b>:</p>
+<ul>
+<li>$mmnormalizeRuleBase &lt;rulebase-file&gt;<br>
+Specifies which rulebase file is to use. This file is loaded. If there are
+multiple mmnormalize instances, each one can use a different file. However,
+a single instance can use only a single file. This parameter MUST be given,
+because normalization can only happen based on a rulebase.
+<li>$mmnormalizeUseRawMsg &lt;on/off&gt;<br>
+Specifies if the raw message should be used for normalization (on) or just the
+MSG part of the message (off). Default is "off".
+</ul>
+<b>Caveats/Known Bugs:</b>
+<p>None known at this time.
+</ul>
+<p><b>Sample:</b></p>
+<p>This activates the module and applies normalization to all messages:<br>
+</p>
+<textarea rows="8" cols="60">$ModLoad mmnormalize
+$mmnormalizeRuleBase rulebase.rb
+*.* :mmnormalize:
+</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/property_replacer.html b/doc/property_replacer.html
index f0153f2a..f4c4238e 100644
--- a/doc/property_replacer.html
+++ b/doc/property_replacer.html
@@ -65,8 +65,7 @@ BSD syslogd. For example, when TAG is "named[12345]", programname is
</tr>
<tr>
<td><b>pri-text</b></td>
-<td>the PRI part of the message in a textual form with the numerical PRI appended in
-brackes (e.g. "local0.err<133>")</td>
+<td>the PRI part of the message in textual form (e.g. "syslog.info")</td>
</tr>
<tr>
<td><b>iut</b></td>
@@ -161,6 +160,10 @@ than messages generated somewhere.
in templates for RFC5424 support, when the character set is know to be
Unicode.</td>
</tr>
+<td><b>$uptime</b></td>
+<td>system-uptime in seconds (as reported by operating system).
+</td>
+</tr>
<tr>
<td><b>$now</b></td>
<td>The current date stamp in the format YYYY-MM-DD</td>
@@ -201,6 +204,14 @@ range from 0 to 3 (for the four quater hours that are in each hour)</td>
<td>The name of the current host as it knows itself (probably useful
for filtering in a generic way)</td>
</tr>
+<tr>
+<td><b>$!&lt;name&gt;</b></td>
+<td>This is the "bridge" to syslog message normalization (via
+<a href="mmnormalize.html">mmnormalize</a>): name is a name defined
+inside the normalization rule. It has the value selected by the rule
+or none if no rule with this field did match.
+</td>
+</tr>
</tbody>
</table>
<p>Properties starting with a $-sign are so-called system
diff --git a/doc/rscript_abnf.html b/doc/rscript_abnf.html
index d60edb5c..9172d945 100644
--- a/doc/rscript_abnf.html
+++ b/doc/rscript_abnf.html
@@ -21,7 +21,58 @@ and many other languages).</p>
<p>Below is the formal language definitionin ABNF (RFC 2234)
format: <br>
</p>
-<pre>; <span style="font-weight: bold;">all of this is a working document and may change!</span> -- rgerhards, 2008-02-24<br><br>script := *stmt<br>stmt := (if_stmt / block / vardef / run_s / load_s)<br>vardef := "var" ["scope" = ("global" / "event")] <br>block := "begin" stmt "end"<br>load_s := "load" constraint ("module") modpath params ; load mod only if expr is true<br>run_s := "run" constraint ("input") name<br>constraint:= "if" expr ; constrains some one-time commands<br>modpath := expr<br>params := ["params" *1param *("," param) "endparams"]<br>param := paramname) "=" expr<br>paramname := [*(obqualifier ".") name]<br>modpath:= ; path to module<br>?line? := cfsysline / cfli<br>cfsysline:= BOL "$" *char EOL ; how to handle the first line? (no EOL in front!)<br>BOL := ; Begin of Line - implicitely set on file beginning and after each EOL<br>EOL := 0x0a ;LF<br>if_stmt := "if" expr "then"<br>old_filter:= BOL facility "." severity ; no whitespace allowed between BOL and facility!<br>facility := "*" / "auth" / "authpriv" / "cron" / "daemon" / "kern" / "lpr" / <br> "mail" / "mark" / "news" / "security" / "syslog" / "user" / "uucp" / <br> "local0" .. "local7" / "mark"<br> ; The keyword security should not be used anymore<br> ; mark is just internal<br>severity := TBD ; not really relevant in this context<br><br>; and now the actual expression<br>expr := e_and *("or" e_and)<br>e_and := e_cmp *("and" e_cmp)<br>e_cmp := val 0*1(cmp_op val)<br>val := term *(("+" / "-" / "&amp;") term)<br>term := factor *(("*" / "/" / "%") factor)<br>factor := ["not"] ["-"] terminal<br>terminal := var / constant / function / ( "(" expr ")" )<br>function := name "(" *("," expr) ")"<br>var := "$" varname<br>varname := msgvar / sysvar<br>msgvar := name<br>sysvar := "$" name<br>name := alpha *(alnum)<br>constant := string / number<br>string := simpstr / tplstr ; tplstr will be implemented in next phase<br>simpstr := "'" *char "'" ; use your imagination for char ;)<br>tplstr := '"' template '"' ; not initially implemented<br>number := ["-"] 1*digit ; 0nn = octal, 0xnn = hex, nn = decimal<br>cmp_op := "==" / "!=" / "&lt;&gt;" / "&lt;" / "&gt;" / "&lt;=" / "&gt;=" / "contains" / "contains_i" / "startswith" / "startswith_i"<br>digit := %x30-39<br>alpha := "a" ... "z" # all letters<br>alnum :* alpha / digit / "_" /"-" # "-" necessary to cover currently-existing message properties<br></pre>
+<pre>; <span style="font-weight: bold;">all of this is a working document and may change!</span> -- rgerhards, 2008-02-24<br>
+<br>
+script := *stmt<br>
+stmt := (if_stmt / block / vardef / run_s / load_s)<br>
+vardef := "var" ["scope" = ("global" / "event")] <br>
+block := "begin" stmt "end"<br>
+load_s := "load" constraint ("module") modpath params ; load mod only if expr is true<br>
+run_s := "run" constraint ("input") name<br>
+constraint:= "if" expr ; constrains some one-time commands<br>
+modpath := expr<br>
+params := ["params" *1param *("," param) "endparams"]<br>
+param := paramname) "=" expr<br>
+paramname := [*(obqualifier ".") name]<br>
+modpath:= ; path to module<br>
+?line? := cfsysline / cfli<br>
+cfsysline:= BOL "$" *char EOL ; how to handle the first line? (no EOL in front!)<br>
+BOL := ; Begin of Line - implicitely set on file beginning and after each EOL<br>
+EOL := 0x0a ;LF<br>
+if_stmt := "if" expr "then"<br>
+old_filter:= BOL facility "." severity ; no whitespace allowed between BOL and facility!<br>
+facility := "*" / "auth" / "authpriv" / "cron" / "daemon" / "kern" / "lpr" / <br>
+"mail" / "mark" / "news" / "security" / "syslog" / "user" / "uucp" / <br>
+"local0" .. "local7" / "mark"<br>
+; The keyword security should not be used anymore<br>
+; mark is just internal<br>
+severity := TBD ; not really relevant in this context<br>
+<br>
+; and now the actual expression<br>
+expr := e_and *("or" e_and)<br>
+e_and := e_cmp *("and" e_cmp)<br>
+e_cmp := val 0*1(cmp_op val)<br>
+val := term *(("+" / "-" / "&amp;") term)<br>
+term := factor *(("*" / "/" / "%") factor)<br>
+factor := ["not"] ["-"] terminal<br>
+terminal := var / constant / function / ( "(" expr ")" )<br>
+function := name "(" *("," expr) ")"<br>
+var := "$" varname<br>
+varname := msgvar / sysvar / ceevar<br>
+msgvar := name<br>
+ceevar := "!" name<br>
+sysvar := "$" name<br>
+name := alpha *(alnum)<br>
+constant := string / number<br>
+string := simpstr / tplstr ; tplstr will be implemented in next phase<br>
+simpstr := "'" *char "'" ; use your imagination for char ;)<br>
+tplstr := '"' template '"' ; not initially implemented<br>
+number := ["-"] 1*digit ; 0nn = octal, 0xnn = hex, nn = decimal<br>
+cmp_op := "==" / "!=" / "&lt;&gt;" / "&lt;" / "&gt;" / "&lt;=" / "&gt;=" / "contains" / "contains_i" / "startswith" / "startswith_i"<br>
+digit := %x30-39<br>
+alpha := "a" ... "z" # all letters<br>
+alnum :* alpha / digit / "_" /"-" # "-" necessary to cover currently-existing message properties<br>
+</pre>
<h2>Samples</h2>
<p>Some samples of RainerScript:</p><p>define function IsLinux<br>begin<br>&nbsp; &nbsp; if $environ contains "linux" then return true else return false<br>end</p><p>load if IsLinux() 'imklog.so' params name='klog' endparams /* load klog under linux only */<br>run if IsLinux() input 'klog'<br>load 'ommysql.so'</p><p>if $message contains "error" then<br>&nbsp; action<br>&nbsp;&nbsp;&nbsp; type='ommysql.so', queue.mode='disk', queue.highwatermark = 300,<br>&nbsp; &nbsp; action.dbname='events', action.dbuser='uid',<br>&nbsp;
&nbsp; [?action.template='templatename'?] or [?action.sql='insert into
diff --git a/doc/rsyslog_conf.html b/doc/rsyslog_conf.html
index 703e7a6e..6aa2e460 100644
--- a/doc/rsyslog_conf.html
+++ b/doc/rsyslog_conf.html
@@ -1,10 +1,10 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
-<html><head><title>rsyslog.conf file</title></head>
+<html><head><title>rsyslog.conf configuration file</title></head>
<body>
<h1>rsyslog.conf configuration file</h1>
-<p><b>Rsyslogd is configured via the rsyslog.conf file</b>,
+<p><b>Rsyslog is configured via the rsyslog.conf file</b>,
typically found in /etc. By default, rsyslogd reads the file
-/etc/rsyslog.conf. This may be changed by a command line option.</p>
+/etc/rsyslog.conf. This may be changed by command line option "-f".</p>
<p><a href="http://wiki.rsyslog.com/index.php/Configuration_Samples">
Configuration file examples can be found in the rsyslog wiki</a>. Also
keep the
@@ -12,65 +12,26 @@ keep the
on your mind. These are ready-to-use
real building blocks for rsyslog configuration.
</p>
-<p>There is also one sample file provided together with the
-documentation set. If you do not like to read, be sure to have at least
-a quick look at
-<a href="rsyslog-example.conf">rsyslog-example.conf</a>.
-</p>
<p>While rsyslogd contains enhancements over standard syslogd,
efforts have been made to keep the configuration file as compatible as
possible. While, for obvious reasons, <a href="features.html">enhanced
features</a> require a different config file syntax, rsyslogd
should be able to work with a standard syslog.conf file. This is
especially useful while you are migrating from syslogd to rsyslogd.</p>
-<h2><a href="rsyslog_conf_modules.html">Modules</a></h2>
-<h2>Lines</h2>
-Lines can be continued by specifying a backslash ("\") as the last
-character of the line. There is a hard-coded maximum line length of 4K.
-If you need lines larger than that, you need to change compile-time
-settings inside rsyslog and recompile.
-<h2><a href="rsyslog_conf_global.html">Configuration Directives</a></h2>
-<h2>Basic Structure</h2>
-<p>Rsyslog supports standard sysklogd's configuration file format
-and extends it. So in general, you can take a "normal" syslog.conf and
-use it together with rsyslogd. It will understand everything. However,
-to use most of rsyslogd's unique features, you need to add extended
-configuration directives.</p>
-<p>Rsyslogd supports the classical, selector-based rule lines.
-They are still at the heart of it and all actions are initiated via
-rule lines. A rule lines is any line not starting with a $ or the
-comment sign (#). Lines starting with $ carry rsyslog-specific
-directives.</p>
-<p>Every rule line consists of two fields, a selector field and
-an action field. These two fields are separated by one or more spaces
-or tabs. The selector field specifies a pattern of facilities and
-priorities belonging to the specified action.<br>
-<br>
-Lines starting with a hash mark ("#'') and empty lines are ignored.
-</p>
-<h2><a href="rsyslog_conf_templates.html">Templates</a></h2>
-<h2><a href="rsyslog_conf_output.html">Output Channels</a></h2>
-<h2><a href="rsyslog_conf_filter.html">Filter Conditions</a></h2>
-<h2><a href="rsyslog_conf_actions.html">Actions</a></h2>
-<h2><a href="rsyslog_conf_examples.html">Examples</a></h2>
-<p>Here you will find examples for templates and selector lines. I hope
-they are self-explanatory. If not, please see
-www.monitorware.com/rsyslog/ for advise.</p>
-<h2>Configuration File Syntax Differences</h2>
-<p>Rsyslogd uses a slightly different syntax for its
-configuration file than the original BSD sources. Originally all
-messages of a specific priority and above were forwarded to the log
-file. The modifiers "='', "!'' and "!-'' were added to make rsyslogd
-more flexible and to use it in a more intuitive manner.<br>
-<br>
-The original BSD syslogd doesn't understand spaces as separators
-between the selector and the action field.<br>
-<br>
-When compared to syslogd from sysklogd package, rsyslogd offers
-additional
-<a href="features.html">features</a> (like template
-and database support). For obvious reasons, the syntax for defining
-such features is available in rsyslogd, only.</p>
+
+<p><b>Follow the links below to learn more about specific topics:</b></p>
+<ul>
+<li><a href="rsyslog_conf_modules.html">Modules</a></li>
+<li><a href="rsyslog_conf_lines.html">Lines</a></li>
+<li><a href="rsyslog_conf_global.html">Configuration Directives</a></li>
+<li><a href="rsyslog_conf_basic_structure.html">Basic Structure</a></li>
+<li><a href="rsyslog_conf_templates.html">Templates</a></li>
+<li><a href="rsyslog_conf_output.html">Output Channels</a></li>
+<li><a href="rsyslog_conf_filter.html">Filter Conditions</a></li>
+<li><a href="rsyslog_conf_actions.html">Actions</a></li>
+<li><a href="rsyslog_conf_file_syntax_differences.html">Configuration File Syntax Differences</a></li>
+<li><a href="rsyslog_conf_examples.html">Examples</a></li>
+</ul>
<p>[<a href="rsyslog_conf.html">back to top</a>]
[<a href="manual.html">manual index</a>]
@@ -82,4 +43,4 @@ Copyright &copy; 2008-2011 by <a href="http://www.gerhards.net/rainer">Rainer Ge
version 3 or higher.</font></p>
</body>
</html>
->
+
diff --git a/doc/rsyslog_conf_basic_structure.html b/doc/rsyslog_conf_basic_structure.html
new file mode 100644
index 00000000..4ce78de0
--- /dev/null
+++ b/doc/rsyslog_conf_basic_structure.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><title>Basic Structure - rsyslog.conf</title></head>
+<body>
+<p>This is a part of the rsyslog.conf documentation.</p>
+<a href="rsyslog_conf.html">Back to rsyslog.conf manual</a>
+<h1>Basic Structure</h1>
+<p>Rsyslog supports standard sysklogd's configuration file format
+and extends it. So in general, you can take a "normal" syslog.conf and
+use it together with rsyslogd. It will understand everything. However,
+to use most of rsyslogd's unique features, you need to add extended
+configuration directives.</p>
+<p>Rsyslogd supports the classical, selector-based rule lines.
+They are still at the heart of it and all actions are initiated via
+rule lines. A rule lines is any line not starting with a $ or the
+comment sign (#). Lines starting with $ carry rsyslog-specific
+directives.</p>
+<p>Every rule line consists of two fields, a selector field and
+an action field. These two fields are separated by one or more spaces
+or tabs. The selector field specifies a pattern of facilities and
+priorities belonging to the specified action.<br>
+<br>
+Lines starting with a hash mark ("#'') and empty lines are ignored.
+</p>
+
+<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>
+<p><font size="2">This documentation is part of the
+<a href="http://www.rsyslog.com/">rsyslog</a> project.<br>
+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>
+</html>
+
diff --git a/doc/rsyslog_conf_file_syntax_differences.html b/doc/rsyslog_conf_file_syntax_differences.html
new file mode 100644
index 00000000..bfac8926
--- /dev/null
+++ b/doc/rsyslog_conf_file_syntax_differences.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><title>Configuration File Syntax Differences - rsyslog.conf</title></head>
+<body>
+<p>This is a part of the rsyslog.conf documentation.</p>
+<a href="rsyslog_conf.html">Back to rsyslog.conf manual</a>
+<h1>Configuration File Syntax Differences</h1>
+<p>Rsyslogd uses a slightly different syntax for its
+configuration file than the original BSD sources. Originally all
+messages of a specific priority and above were forwarded to the log
+file. The modifiers "='', "!'' and "!-'' were added to make rsyslogd
+more flexible and to use it in a more intuitive manner.<br>
+<br>
+The original BSD syslogd doesn't understand spaces as separators
+between the selector and the action field.<br>
+<br>
+When compared to syslogd from sysklogd package, rsyslogd offers
+additional
+<a href="features.html">features</a> (like template
+and database support). For obvious reasons, the syntax for defining
+such features is available in rsyslogd, only.</p>
+
+<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>
+<p><font size="2">This documentation is part of the
+<a href="http://www.rsyslog.com/">rsyslog</a> project.<br>
+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>
+</html>
+
diff --git a/doc/rsyslog_conf_filter.html b/doc/rsyslog_conf_filter.html
index 34839616..fbced4a3 100644
--- a/doc/rsyslog_conf_filter.html
+++ b/doc/rsyslog_conf_filter.html
@@ -117,6 +117,13 @@ currently supported:</p>
the property. There must be an exact match, wildcards are not supported.</td>
</tr>
<tr>
+<td>isempty</td>
+<td>Checks if the property is empty. The value is discarded. This is
+especially useful when working with normalized data, where some fields
+may be populated based on normalization result.
+Available since 6.6.2.
+</tr>
+<tr>
<td>isequal</td>
<td>Compares the "value" string provided and the property
contents. These two values must be exactly equal to match. The
diff --git a/doc/rsyslog_conf_lines.html b/doc/rsyslog_conf_lines.html
new file mode 100644
index 00000000..0e6cc0d3
--- /dev/null
+++ b/doc/rsyslog_conf_lines.html
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><title>Lines - rsyslog.conf</title></head>
+<body>
+<p>This is a part of the rsyslog.conf documentation.</p>
+<a href="rsyslog_conf.html">Back to rsyslog.conf manual</a>
+<h1>Lines</h1>
+<p>Lines can be continued by specifying a backslash ("\") as the last
+character of the line. There is a hard-coded maximum line length of 4K.<br>
+If you need lines larger than that, you need to change compile-time
+settings inside rsyslog and recompile.
+</p>
+
+<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>
+<p><font size="2">This documentation is part of the
+<a href="http://www.rsyslog.com/">rsyslog</a> project.<br>
+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>
+</html>
+
diff --git a/doc/rsyslog_conf_modules.html b/doc/rsyslog_conf_modules.html
index 9fa35ccd..650e20ad 100644
--- a/doc/rsyslog_conf_modules.html
+++ b/doc/rsyslog_conf_modules.html
@@ -94,7 +94,7 @@ repated n times" messages emitted by some syslogds.
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
+<p>Currently, there exists only a limited set of such modules, but new ones could be written with
the methods the engine provides. They could be used, for example, to:
<ul>
<li>anonymize message content
@@ -103,8 +103,10 @@ the methods the engine provides. They could be used, for example, to:
<p>Message modification modules are usually written for one specific task and thus
usually are not generic enough to be reused. However, existing module's code is
probably an excellent starting base for writing a new module. Currently, the following
-modules existin inside the source tree
+modules exist inside the source tree:
<ul>
+<li><a href="mmnormalize.html">mmnormalize</a> - used to normalize log messages.
+Note that this actually is a <b>generic</b> module.
<li><a href="mmsnmptrapd.html">mmsnmptrapd</a> - uses information provided by snmptrapd inside
the tag to correct the original sender system and priority of messages. Implemented via
the output module interface.
diff --git a/doc/rsyslog_recording_pri.html b/doc/rsyslog_recording_pri.html
index a092980c..abcadf2a 100644
--- a/doc/rsyslog_recording_pri.html
+++ b/doc/rsyslog_recording_pri.html
@@ -45,7 +45,7 @@ percent signs is literal text, which is simply written as specified.</p>
<p>Thankfully, rsyslog provides message properties for the priority. These are
called &quot;PRI&quot;, &quot;syslogfacility&quot; and &quot;syslogpriority&quot; (case is important!). They are numerical
values. Starting with rsyslog 1.13.4, there is also a property &quot;pri-text&quot;, which
-contains the priority in friendly text format (e.g. &quot;local0.err<133>&quot;). For the rest
+contains the priority in friendly text format (e.g. &quot;syslog.info&quot;). For the rest
of this article, I assume that you run version 1.13.4 or higher.</p>
<p>Recording the priority is now a simple matter of adding the respective field
to the template. It now looks like this:</p>
@@ -83,29 +83,29 @@ A little bit of configuration is required.</p>
<p>Below is some sample data created with the template specified above. Note the
priority recording at the start of each line.</p>
<p>
-<code>kern.info&lt;6&gt;: Jun 15 18:10:38 host kernel: PCI: Sharing IRQ 11 with 00:04.0<br>
-kern.info&lt;6&gt;: Jun 15 18:10:38 host kernel: PCI: Sharing IRQ 11 with 01:00.0<br>
-kern.warn&lt;4&gt;: Jun 15 18:10:38 host kernel: Yenta IRQ list 06b8, PCI irq11<br>
-kern.warn&lt;4&gt;: Jun 15 18:10:38 host kernel: Socket status: 30000006<br>
-kern.warn&lt;4&gt;: Jun 15 18:10:38 host kernel: Yenta IRQ list 06b8, PCI irq11<br>
-kern.warn&lt;4&gt;: Jun 15 18:10:38 host kernel: Socket status: 30000010<br>
-kern.info&lt;6&gt;: Jun 15 18:10:38 host kernel: cs: IO port probe 0x0c00-0x0cff: clean.<br>
-kern.info&lt;6&gt;: Jun 15 18:10:38 host kernel: cs: IO port probe 0x0100-0x04ff: excluding 0x100-0x107 0x378-0x37f 0x4d0-0x4d7<br>
-kern.info&lt;6&gt;: Jun 15 18:10:38 host kernel: cs: IO port probe 0x0a00-0x0aff: clean.<br>
-local7.notice&lt;189&gt;: Jun 15 18:17:24 host dd: 1+0 records out<br>
-local7.notice&lt;189&gt;: Jun 15 18:17:24 host random: Saving random seed: succeeded<br>
-local7.notice&lt;189&gt;: Jun 15 18:17:25 host portmap: portmap shutdown succeeded<br>
-local7.notice&lt;189&gt;: Jun 15 18:17:25 host network: Shutting down interface eth1: succeeded<br>
-local7.notice&lt;189&gt;: Jun 15 18:17:25 host network: Shutting down loopback interface: succeeded<br>
-local7.notice&lt;189&gt;: Jun 15 18:17:25 host pcmcia: Shutting down PCMCIA services: cardmgr<br>
-user.notice&lt;13&gt;: Jun 15 18:17:25 host /etc/hotplug/net.agent: NET unregister event not supported<br>
-local7.notice&lt;189&gt;: Jun 15 18:17:27 host pcmcia: modules.<br>
-local7.notice&lt;189&gt;: Jun 15 18:17:29 host rc: Stopping pcmcia: succeeded<br>
-local7.notice&lt;189&gt;: Jun 15 18:17:30 host rc: Starting killall: succeeded<br>
-syslog.info&lt;46&gt;: Jun 15 18:17:33 host [origin software=&quot;rsyslogd&quot; swVersion=&quot;1.13.3&quot; x-pid=&quot;2464&quot;] exiting on signal 15.<br>
-syslog.info&lt;46&gt;: Jun 18 10:55:47 host [origin software=&quot;rsyslogd&quot; swVersion=&quot;1.13.3&quot; x-pid=&quot;2367&quot;][x-configInfo udpReception=&quot;Yes&quot; udpPort=&quot;514&quot; tcpReception=&quot;Yes&quot; tcpPort=&quot;1470&quot;] restart<br>
-user.notice&lt;13&gt;: Jun 18 10:55:50 host rger: test<br>
-syslog.info&lt;46&gt;: Jun 18 10:55:52 host [origin software=&quot;rsyslogd&quot; swVersion=&quot;1.13.3&quot; x-pid=&quot;2367&quot;] exiting on signal 2.</code></p>
+<code>kern.info: Jun 15 18:10:38 host kernel: PCI: Sharing IRQ 11 with 00:04.0<br>
+kern.info: Jun 15 18:10:38 host kernel: PCI: Sharing IRQ 11 with 01:00.0<br>
+kern.warn: Jun 15 18:10:38 host kernel: Yenta IRQ list 06b8, PCI irq11<br>
+kern.warn: Jun 15 18:10:38 host kernel: Socket status: 30000006<br>
+kern.warn: Jun 15 18:10:38 host kernel: Yenta IRQ list 06b8, PCI irq11<br>
+kern.warn: Jun 15 18:10:38 host kernel: Socket status: 30000010<br>
+kern.info: Jun 15 18:10:38 host kernel: cs: IO port probe 0x0c00-0x0cff: clean.<br>
+kern.info: Jun 15 18:10:38 host kernel: cs: IO port probe 0x0100-0x04ff: excluding 0x100-0x107 0x378-0x37f 0x4d0-0x4d7<br>
+kern.info: Jun 15 18:10:38 host kernel: cs: IO port probe 0x0a00-0x0aff: clean.<br>
+local7.notice: Jun 15 18:17:24 host dd: 1+0 records out<br>
+local7.notice: Jun 15 18:17:24 host random: Saving random seed: succeeded<br>
+local7.notice: Jun 15 18:17:25 host portmap: portmap shutdown succeeded<br>
+local7.notice: Jun 15 18:17:25 host network: Shutting down interface eth1: succeeded<br>
+local7.notice: Jun 15 18:17:25 host network: Shutting down loopback interface: succeeded<br>
+local7.notice: Jun 15 18:17:25 host pcmcia: Shutting down PCMCIA services: cardmgr<br>
+user.notice: Jun 15 18:17:25 host /etc/hotplug/net.agent: NET unregister event not supported<br>
+local7.notice: Jun 15 18:17:27 host pcmcia: modules.<br>
+local7.notice: Jun 15 18:17:29 host rc: Stopping pcmcia: succeeded<br>
+local7.notice: Jun 15 18:17:30 host rc: Starting killall: succeeded<br>
+syslog.info: Jun 15 18:17:33 host [origin software=&quot;rsyslogd&quot; swVersion=&quot;1.13.3&quot; x-pid=&quot;2464&quot;] exiting on signal 15.<br>
+syslog.info: Jun 18 10:55:47 host [origin software=&quot;rsyslogd&quot; swVersion=&quot;1.13.3&quot; x-pid=&quot;2367&quot;][x-configInfo udpReception=&quot;Yes&quot; udpPort=&quot;514&quot; tcpReception=&quot;Yes&quot; tcpPort=&quot;1470&quot;] restart<br>
+user.notice: Jun 18 10:55:50 host rger: test<br>
+syslog.info: Jun 18 10:55:52 host [origin software=&quot;rsyslogd&quot; swVersion=&quot;1.13.3&quot; x-pid=&quot;2367&quot;] exiting on signal 2.</code></p>
<h2>Feedback Requested</h2>
<P>I would appreciate feedback on this paper. If you have additional ideas,
comments or find bugs, please
diff --git a/doc/v6compatibility.html b/doc/v6compatibility.html
new file mode 100644
index 00000000..bc803d2a
--- /dev/null
+++ b/doc/v6compatibility.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><title>Compatibility notes for rsyslog v6</title>
+</head>
+<body>
+<h1>Compatibility Notes for rsyslog v6</h1>
+<p>
+This document describes things to keep in mind when moving from v5 to v6. It
+does not list enhancements nor does it talk about compatibility concerns introduced
+by earlier versions (for this, see their respective compatibility documents).
+</p>
+<p>Version 6 offers a better config language and some other improvements.
+As the config system has many ties into the rsyslog engine AND all plugins,
+the changes are somewhat intrusive. Note, however, that core processing has
+not been changed much in v6 and will not. So once the configuration is loaded,
+the stability of v6 is quite comparable to v5.
+</p>
+<h2>Property "pri-text"</h2>
+<p>Traditionally, this property did not only return the textual form
+of the pri ("local0.err"), but also appended the numerical value to it
+("local0.err<133>"). This sounds odd and was left unnoticed for some years.
+In October 2011, this odd behaviour was brought up on the rsyslog mailing list
+by Gregory K. Ruiz-Ade. Code review showed that the behaviour was intentional,
+but no trace of what the intention was when it was introduced could be found.
+The documentation was also unclear, it said no numerical value was present,
+but the samples had it. We agreed that the additional numerical value is
+of disadvantage. We also guessed that this property is very rarely being used,
+otherwise the problem should have been raised much earlier. However, we
+didn't want to change behaviour in older builds. So v6 was set to clean up
+the situation. In v6, text-pri will always return the textual part only
+("local0.err") and the numerical value will not be contained any longer inside
+the string. If you actually need that value, it can fairly easily be added
+via the template system.
+<p><b>If you have used this property previously and relied on the numerical
+part, you need to update your rsyslog configuration files.</b>
+<h2>Plugin ABI</h2>
+<p>The plugin interface has considerably been changed to support the new
+config language. All plugins need to be upgraded. This usually does not require
+much coding. However, if the new config language shall be supported, more
+changes must be made to plugin code. All project-supported plugins have been
+upgraded, so this compatibility issue is only of interest for you if you have
+custom plugins or use some user-contributed plugins from the rsyslog project
+that are not maintained by the project itself (omoracle is an example). Please
+expect some further plugin instablity during the initial v6 releases.
+</body></html>
diff --git a/parse.c b/parse.c
index aa5f2a52..659d49cd 100644
--- a/parse.c
+++ b/parse.c
@@ -239,7 +239,8 @@ rsRetVal parsSkipWhitespace(rsParsObj *pThis, sbool bRequireOne)
/* Parse string up to a delimiter.
*
* Input:
- * cDelim - the delimiter
+ * cDelim - the delimiter. Note that SP within a value always is a delimiter,
+ * so cDelim is actually an *additional* delimiter.
* The following two are for whitespace stripping,
* 0 means "no", 1 "yes"
* - bTrimLeading
@@ -264,13 +265,13 @@ rsRetVal parsDelimCStr(rsParsObj *pThis, cstr_t **ppCStr, char cDelim, int bTrim
pC = rsCStrGetBufBeg(pThis->pCStr) + pThis->iCurrPos;
- while(pThis->iCurrPos < rsCStrLen(pThis->pCStr) && *pC != cDelim) {
+ while(pThis->iCurrPos < rsCStrLen(pThis->pCStr) && *pC != cDelim && *pC != ' ') {
CHKiRet(cstrAppendChar(pCStr, bConvLower ? tolower(*pC) : *pC));
++pThis->iCurrPos;
++pC;
}
- if(*pC == cDelim) {
+ if(pThis->iCurrPos < cstrLen(pThis->pCStr)) { //BUGFIX!!
++pThis->iCurrPos; /* eat delimiter */
}
diff --git a/plugins/imptcp/imptcp.c b/plugins/imptcp/imptcp.c
index 91bdf8b3..92383f90 100644
--- a/plugins/imptcp/imptcp.c
+++ b/plugins/imptcp/imptcp.c
@@ -83,7 +83,8 @@ DEFobjCurrIf(datetime)
DEFobjCurrIf(errmsg)
DEFobjCurrIf(ruleset)
-
+/* forward references */
+static void * wrkr(void *myself);
/* config settings */
typedef struct configSettings_s {
@@ -92,6 +93,7 @@ typedef struct configSettings_s {
uchar *pszInputName; /* value for inputname property, NULL is OK and handled by core engine */
uchar *lstnIP; /* which IP we should listen on? */
ruleset_t *pRuleset; /* ruleset to bind listener to (use system default if unspecified) */
+ int wrkrMax; /* max number of workers (actually "helper workers") */
} configSettings_t;
static configSettings_t cs;
@@ -117,6 +119,7 @@ struct ptcpsrv_s {
ruleset_t *pRuleset;
ptcplstn_t *pLstn; /* root of our listeners */
ptcpsess_t *pSess; /* root of our sessions */
+ pthread_mutex_t mutSessLst;
};
/* the ptcp session object. Describes a single active session.
@@ -154,6 +157,20 @@ struct ptcplstn_s {
};
+/* The following structure controls the worker threads. Global data is
+ * needed for their access.
+ */
+static struct wrkrInfo_s {
+ pthread_t tid; /* the worker's thread ID */
+ pthread_cond_t run;
+ struct epoll_event *event; /* event == NULL -> idle */
+ long long unsigned numCalled; /* how often was this called */
+} wrkrInfo[16];
+static pthread_mutex_t wrkrMut;
+static pthread_cond_t wrkrIdle;
+static int wrkrRunning;
+
+
/* type of object stored in epoll descriptor */
typedef enum {
epolld_lstn,
@@ -171,20 +188,10 @@ struct epolld_s {
/* global data */
-//static permittedPeers_t *pPermPeersRoot = NULL;
+pthread_attr_t wrkrThrdAttr; /* Attribute for session threads; read only after startup */
static ptcpsrv_t *pSrvRoot = NULL;
static int epollfd = -1; /* (sole) descriptor for epoll */
static int iMaxLine; /* maximum size of a single message */
-/* we use a single static receive buffer, as this module is not multi-threaded. Keeping
- * the buffer in the data segment is probably a little bit more efficient than on the stack
- * (but at least I can't believe it will ever be less efficient ;) -- rgerhards, 2010-08-10
- * Note that we do NOT (yet?) provide a config setting to set the buffer size. For usual
- * syslog traffic, it should be large enough. Also keep in mind that we run under a virtual
- * memory system, so if we do not use large parts of the buffer, that's no issue at
- * all -- it'll just use up address space. On the other hand, it would be silly to page in
- * or page out some data just to get space for the IO buffer.
- */
-static char rcvBuf[128*1024];
/* forward definitions */
static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal);
@@ -209,6 +216,7 @@ static void
destructSrv(ptcpsrv_t *pSrv)
{
prop.Destruct(&pSrv->pInputName);
+ pthread_mutex_destroy(&pSrv->mutSessLst);
free(pSrv->port);
free(pSrv);
}
@@ -678,6 +686,7 @@ static inline void
initConfigSettings(void)
{
cs.bEmitMsgOnClose = 0;
+ cs.wrkrMax = 2;
cs.iAddtlFrameDelim = TCPSRV_NO_ADDTL_DELIMITER;
cs.pszInputName = NULL;
cs.pRuleset = NULL;
@@ -790,10 +799,12 @@ addSess(ptcpsrv_t *pSrv, int sock, prop_t *peerName, prop_t *peerIP)
/* add to start of server's listener list */
pSess->prev = NULL;
+ pthread_mutex_lock(&pSrv->mutSessLst);
pSess->next = pSrv->pSess;
if(pSrv->pSess != NULL)
pSrv->pSess->prev = pSess;
pSrv->pSess = pSess;
+ pthread_mutex_unlock(&pSrv->mutSessLst);
iRet = addEPollSock(epolld_sess, pSess, sock, &pSess->epd);
@@ -816,10 +827,8 @@ closeSess(ptcpsess_t *pSess)
CHKiRet(removeEPollSock(sock, pSess->epd));
close(sock);
+ pthread_mutex_lock(&pSess->pSrv->mutSessLst);
/* finally unlink session from structures */
-//fprintf(stderr, "closing session %d next %p, prev %p\n", pSess->sock, pSess->next, pSess->prev);
-//DBGPRINTF("imptcp: pSess->next %p\n", pSess->next);
-//DBGPRINTF("imptcp: pSess->prev %p\n", pSess->prev);
if(pSess->next != NULL)
pSess->next->prev = pSess->prev;
if(pSess->prev == NULL) {
@@ -828,6 +837,7 @@ closeSess(ptcpsess_t *pSess)
} else {
pSess->prev->next = pSess->next;
}
+ pthread_mutex_unlock(&pSess->pSrv->mutSessLst);
/* unlinked, now remove structure */
destructSess(pSess);
@@ -838,21 +848,6 @@ finalize_it:
}
-#if 0
-/* set permitted peer -- rgerhards, 2008-05-19
- */
-static rsRetVal
-setPermittedPeer(void __attribute__((unused)) *pVal, uchar *pszID)
-{
- DEFiRet;
- CHKiRet(net.AddPermittedPeer(&pPermPeersRoot, pszID));
- free(pszID); /* no longer needed, but we need to free as of interface def */
-finalize_it:
- RETiRet;
-}
-#endif
-
-
/* accept a new ruleset to bind. Checks if it exists and complains, if not */
static rsRetVal setRuleset(void __attribute__((unused)) *pVal, uchar *pszName)
{
@@ -880,6 +875,7 @@ static rsRetVal addTCPListener(void __attribute__((unused)) *pVal, uchar *pNewVa
ptcpsrv_t *pSrv;
CHKmalloc(pSrv = malloc(sizeof(ptcpsrv_t)));
+ pthread_mutex_init(&pSrv->mutSessLst, NULL);
pSrv->pSess = NULL;
pSrv->pLstn = NULL;
pSrv->bEmitMsgOnClose = cs.bEmitMsgOnClose;
@@ -911,6 +907,46 @@ finalize_it:
}
+/* destroy worker pool structures and wait for workers to terminate
+ */
+static inline void
+startWorkerPool(void)
+{
+ int i;
+ wrkrRunning = 0;
+ if(cs.wrkrMax > 16)
+ cs.wrkrMax = 16; /* TODO: make dynamic? */
+ pthread_mutex_init(&wrkrMut, NULL);
+ pthread_cond_init(&wrkrIdle, NULL);
+ for(i = 0 ; i < cs.wrkrMax ; ++i) {
+ /* init worker info structure! */
+ pthread_cond_init(&wrkrInfo[i].run, NULL);
+ wrkrInfo[i].event = NULL;
+ wrkrInfo[i].numCalled = 0;
+ pthread_create(&wrkrInfo[i].tid, &wrkrThrdAttr, wrkr, &(wrkrInfo[i]));
+ }
+
+}
+
+/* destroy worker pool structures and wait for workers to terminate
+ */
+static inline void
+stopWorkerPool(void)
+{
+ int i;
+ for(i = 0 ; i < cs.wrkrMax ; ++i) {
+ pthread_cond_signal(&wrkrInfo[i].run); /* awake wrkr if not running */
+ pthread_join(wrkrInfo[i].tid, NULL);
+ DBGPRINTF("imptcp: info: worker %d was called %llu times\n", i, wrkrInfo[i].numCalled);
+ pthread_cond_destroy(&wrkrInfo[i].run);
+ }
+ pthread_cond_destroy(&wrkrIdle);
+ pthread_mutex_destroy(&wrkrMut);
+
+}
+
+
+
/* start up all listeners
* This is a one-time stop once the module is set to start.
*/
@@ -922,7 +958,7 @@ startupServers()
pSrv = pSrvRoot;
while(pSrv != NULL) {
- DBGPRINTF("Starting up ptcp server for port %s, name '%s'\n", pSrv->port, pSrv->pszInputName);
+ DBGPRINTF("imptcp: starting up server for port %s, name '%s'\n", pSrv->port, pSrv->pszInputName);
startupSrv(pSrv);
pSrv = pSrv->pNext;
}
@@ -944,9 +980,9 @@ lstnActivity(ptcplstn_t *pLstn)
DEFiRet;
DBGPRINTF("imptcp: new connection on listen socket %d\n", pLstn->sock);
- while(1) {
+ while(glbl.GetGlobalInputTermState() == 0) {
localRet = AcceptConnReq(pLstn->sock, &newSock, &peerName, &peerIP);
- if(localRet == RS_RET_NO_MORE_DATA)
+ if(localRet == RS_RET_NO_MORE_DATA || glbl.GetGlobalInputTermState() == 1)
break;
CHKiRet(localRet);
CHKiRet(addSess(pLstn->pSrv, newSock, peerName, peerIP));
@@ -965,6 +1001,7 @@ sessActivity(ptcpsess_t *pSess)
{
int lenRcv;
int lenBuf;
+ char rcvBuf[128*1024];
DEFiRet;
DBGPRINTF("imptcp: new activity on session socket %d\n", pSess->sock);
@@ -1002,35 +1039,127 @@ finalize_it:
}
+/* This function is called to process a single request. This may
+ * be carried out by the main worker or a helper. It can be run
+ * concurrently.
+ */
+static inline void
+processWorkItem(struct epoll_event *event)
+{
+ epolld_t *epd;
+
+ epd = (epolld_t*) event->data.ptr;
+ switch(epd->typ) {
+ case epolld_lstn:
+ lstnActivity((ptcplstn_t *) epd->ptr);
+ break;
+ case epolld_sess:
+ sessActivity((ptcpsess_t *) epd->ptr);
+ break;
+ default:
+ errmsg.LogError(0, RS_RET_INTERNAL_ERROR,
+ "error: invalid epolld_type_t %d after epoll", epd->typ);
+ break;
+ }
+}
+
+
+/* This function is called to process a complete workset, that
+ * is a set of events returned from epoll.
+ */
+static inline void
+processWorkSet(int nEvents, struct epoll_event events[])
+{
+ int iEvt;
+ int i;
+ int remainEvents;
+
+ remainEvents = nEvents;
+ for(iEvt = 0 ; (iEvt < nEvents) && (glbl.GetGlobalInputTermState() == 0) ; ++iEvt) {
+ if(remainEvents == 1) {
+ /* process self, save context switch */
+ processWorkItem(events+iEvt);
+ } else {
+ pthread_mutex_lock(&wrkrMut);
+ /* check if there is a free worker */
+ for(i = 0 ; (i < cs.wrkrMax) && (wrkrInfo[i].event != NULL) ; ++i)
+ /*do search*/;
+ if(i < cs.wrkrMax) {
+ /* worker free -> use it! */
+ wrkrInfo[i].event = events+iEvt;
+ ++wrkrRunning;
+ pthread_cond_signal(&wrkrInfo[i].run);
+ pthread_mutex_unlock(&wrkrMut);
+ } else {
+ pthread_mutex_unlock(&wrkrMut);
+ /* no free worker, so we process this one ourselfs */
+ processWorkItem(events+iEvt);
+ }
+ }
+ --remainEvents;
+ }
+
+ if(nEvents > 1) {
+ /* we now need to wait until all workers finish. This is because the
+ * rest of this module can not handle the concurrency introduced
+ * by workers running during the epoll call.
+ */
+ pthread_mutex_lock(&wrkrMut);
+ while(wrkrRunning > 0) {
+ pthread_cond_wait(&wrkrIdle, &wrkrMut);
+ }
+ pthread_mutex_unlock(&wrkrMut);
+ }
+
+}
+
+
+/* worker to process incoming requests
+ */
+static void *
+wrkr(void *myself)
+{
+ struct wrkrInfo_s *me = (struct wrkrInfo_s*) myself;
+
+ pthread_mutex_lock(&wrkrMut);
+ while(1) {
+ while(me->event == NULL && glbl.GetGlobalInputTermState() == 0) {
+ pthread_cond_wait(&me->run, &wrkrMut);
+ }
+ if(glbl.GetGlobalInputTermState() == 1)
+ break;
+ pthread_mutex_unlock(&wrkrMut);
+
+ ++me->numCalled;
+ processWorkItem(me->event);
+
+ pthread_mutex_lock(&wrkrMut);
+ me->event = NULL; /* indicate we are free again */
+ --wrkrRunning;
+ pthread_cond_signal(&wrkrIdle);
+ }
+ pthread_mutex_unlock(&wrkrMut);
+
+ return NULL;
+}
+
+
/* This function is called to gather input.
*/
BEGINrunInput
- int i;
- int nfds;
- struct epoll_event events[1];
- epolld_t *epd;
+ int nEvents;
+ struct epoll_event events[128];
CODESTARTrunInput
- DBGPRINTF("imptcp now beginning to process input data\n");
- /* v5 TODO: consentual termination mode */
- while(1) {
+ startWorkerPool();
+ DBGPRINTF("imptcp: now beginning to process input data\n");
+ while(glbl.GetGlobalInputTermState() == 0) {
DBGPRINTF("imptcp going on epoll_wait\n");
- nfds = epoll_wait(epollfd, events, sizeof(events)/sizeof(struct epoll_event), -1);
- for(i = 0 ; i < nfds ; ++i) { /* support for larger batches (later, TODO) */
- epd = (epolld_t*) events[i].data.ptr;
- switch(epd->typ) {
- case epolld_lstn:
- lstnActivity((ptcplstn_t *) epd->ptr);
- break;
- case epolld_sess:
- sessActivity((ptcpsess_t *) epd->ptr);
- break;
- default:
- errmsg.LogError(0, RS_RET_INTERNAL_ERROR,
- "error: invalid epolld_type_t %d after epoll", epd->typ);
- break;
- }
- }
+ nEvents = epoll_wait(epollfd, events, sizeof(events)/sizeof(struct epoll_event), -1);
+ DBGPRINTF("imptcp: epoll returned %d events\n", nEvents);
+ processWorkSet(nEvents, events);
}
+ DBGPRINTF("imptcp: successfully terminated\n");
+ /* we stop the worker pool in AfterRun, in case we get cancelled for some reason (old Interface) */
ENDrunInput
@@ -1038,7 +1167,6 @@ ENDrunInput
BEGINwillRun
CODESTARTwillRun
/* first apply some config settings */
- //net.PrintAllowedSenders(2); /* TCP */
iMaxLine = glbl.GetMaxLine(); /* get maximum size we currently support */
if(pSrvRoot == NULL) {
@@ -1107,8 +1235,8 @@ shutdownSrv(ptcpsrv_t *pSrv)
BEGINafterRun
ptcpsrv_t *pSrv, *srvDel;
CODESTARTafterRun
- /* do cleanup here */
- //net.clearAllowedSenders(UCHAR_CONSTANT("TCP"));
+ stopWorkerPool();
+
/* we need to close everything that is still open */
pSrv = pSrvRoot;
while(pSrv != NULL) {
@@ -1124,12 +1252,7 @@ ENDafterRun
BEGINmodExit
CODESTARTmodExit
-#if 0
- if(pPermPeersRoot != NULL) {
- net.DestructPermittedPeers(&pPermPeersRoot);
- }
-#endif
-
+ pthread_attr_destroy(&wrkrThrdAttr);
/* release objects we used */
objRelease(glbl, CORE_COMPONENT);
objRelease(prop, CORE_COMPONENT);
@@ -1144,6 +1267,7 @@ static rsRetVal
resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
{
cs.bEmitMsgOnClose = 0;
+ cs.wrkrMax = 2;
cs.iAddtlFrameDelim = TCPSRV_NO_ADDTL_DELIMITER;
free(cs.pszInputName);
cs.pszInputName = NULL;
@@ -1153,10 +1277,17 @@ resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unus
}
+BEGINisCompatibleWithFeature
+CODESTARTisCompatibleWithFeature
+ if(eFeat == sFEATURENonCancelInputTermination)
+ iRet = RS_RET_OK;
+ENDisCompatibleWithFeature
+
BEGINqueryEtryPt
CODESTARTqueryEtryPt
CODEqueryEtryPt_STD_IMOD_QUERIES
+CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES
ENDqueryEtryPt
@@ -1173,6 +1304,10 @@ CODEmodInit_QueryRegCFSLineHdlr
CHKiRet(objUse(datetime, CORE_COMPONENT));
CHKiRet(objUse(ruleset, CORE_COMPONENT));
+ /* initialize "read-only" thread attributes */
+ pthread_attr_init(&wrkrThrdAttr);
+ pthread_attr_setstacksize(&wrkrThrdAttr, 2048*1024);
+
/* register config file handlers */
CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputptcpserverrun"), 0, eCmdHdlrGetWord,
addTCPListener, NULL, STD_LOADABLE_MODULE_ID));
@@ -1180,6 +1315,8 @@ CODEmodInit_QueryRegCFSLineHdlr
eCmdHdlrBinary, NULL, &cs.bEmitMsgOnClose, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputptcpserveraddtlframedelimiter"), 0, eCmdHdlrInt,
NULL, &cs.iAddtlFrameDelim, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputptcpserverhelperthreads"), 0, eCmdHdlrInt,
+ NULL, &cs.wrkrMax, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputptcpserverinputname"), 0,
eCmdHdlrGetWord, NULL, &cs.pszInputName, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputptcpserverlistenip"), 0,
diff --git a/plugins/imtcp/imtcp.c b/plugins/imtcp/imtcp.c
index 6ab39477..b537cbb8 100644
--- a/plugins/imtcp/imtcp.c
+++ b/plugins/imtcp/imtcp.c
@@ -88,6 +88,7 @@ static int iStrmDrvrMode = 0; /* mode for stream driver, driver-dependent (0 mos
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 int bUseFlowControl = 1; /* use flow control, what means indicate ourselfs a "light delayable" */
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) */
@@ -199,6 +200,7 @@ static rsRetVal addTCPListener(void __attribute__((unused)) *pVal, uchar *pNewVa
CHKiRet(tcpsrv.SetCBOnRegularClose(pOurTcpsrv, onRegularClose));
CHKiRet(tcpsrv.SetCBOnErrClose(pOurTcpsrv, onErrClose));
CHKiRet(tcpsrv.SetDrvrMode(pOurTcpsrv, iStrmDrvrMode));
+ CHKiRet(tcpsrv.SetUseFlowControl(pOurTcpsrv, bUseFlowControl));
CHKiRet(tcpsrv.SetAddtlFrameDelim(pOurTcpsrv, iAddtlFrameDelim));
CHKiRet(tcpsrv.SetbDisableLFDelim(pOurTcpsrv, bDisableLFDelim));
CHKiRet(tcpsrv.SetNotificationOnRemoteClose(pOurTcpsrv, bEmitMsgOnClose));
@@ -289,6 +291,7 @@ resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unus
iTCPSessMax = 200;
iTCPLstnMax = 20;
iStrmDrvrMode = 0;
+ bUseFlowControl = 0;
bEmitMsgOnClose = 0;
iAddtlFrameDelim = TCPSRV_NO_ADDTL_DELIMITER;
bDisableLFDelim = 0;
@@ -344,6 +347,8 @@ CODEmodInit_QueryRegCFSLineHdlr
eCmdHdlrGetWord, NULL, &pszInputName, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserverbindruleset"), 0,
eCmdHdlrGetWord, setRuleset, NULL, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpflowcontrol"), 0,
+ eCmdHdlrBinary, NULL, &bUseFlowControl, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("resetconfigvariables"), 1, eCmdHdlrCustomHandler,
resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
ENDmodInit
diff --git a/plugins/imttcp/Makefile.am b/plugins/imttcp/Makefile.am
new file mode 100644
index 00000000..9b09b4bf
--- /dev/null
+++ b/plugins/imttcp/Makefile.am
@@ -0,0 +1,6 @@
+pkglib_LTLIBRARIES = imttcp.la
+
+imttcp_la_SOURCES = imttcp.c
+imttcp_la_CPPFLAGS = -I$(top_srcdir) $(PTHREADS_CFLAGS) $(RSRT_CFLAGS)
+imttcp_la_LDFLAGS = -module -avoid-version
+imttcp_la_LIBADD =
diff --git a/plugins/imttcp/imttcp.c b/plugins/imttcp/imttcp.c
new file mode 100644
index 00000000..c7f546cc
--- /dev/null
+++ b/plugins/imttcp/imttcp.c
@@ -0,0 +1,1145 @@
+/* imttcp.c
+ * This is an experimental plain tcp input module which follows the
+ * multiple thread paradigm.
+ *
+ * WARNING
+ * This module is unfinished. It seems to work, but there also seems to be a problem
+ * if it is under large stress (e.g. tcpflood with more than 500 to 1000 concurrent
+ * connections). I quickly put together this module after I worked on a larger paper
+ * and read [1], which claims that using massively threaded applications is
+ * preferrable to an event driven approach. So I put this to test, especially as
+ * that would also lead to a much simpler programming paradigm. Unfortuantely, the
+ * performance results are devastive: while there is a very slight speedup with
+ * a low connection number (close to the number of cores on the system), there
+ * is a dramatic negative speedup if running with many threads. Even at only 50
+ * connections, rsyslog is dramatically slower (80 seconds for the same workload
+ * which was processed in 60 seconds with traditional imtcp or when running on
+ * a single connection). At 1,000 connections, the run was *extremely* slow. So
+ * this is definitely a dead-end. To be honest, Behren, condit and Brewer claim
+ * that the problem lies in the current implementation of thread libraries.
+ * As one cure, they propose user-level threads. However, as far as I could
+ * find out, User-Level threads seem not to be much faster under Linux than
+ * Kernel-Level threads (which I used in my approach).
+ *
+ * Even more convincing is, from the rsyslog PoV, that there are clear reasons
+ * why the highly threaded input must be slower:
+ * o batch sizes are smaller, leading to much more overhead
+ * o many more context switches are needed to switch between the various
+ * i/o handlers
+ * o more OS API calls are required because in this model we get more
+ * frequent wakeups on new incoming data, so we have less data available
+ * to read at each instant
+ * o more lock contention because many more threads compete on the
+ * main queue mutex
+ *
+ * All in all, this means that the approach is not the right one, at least
+ * not for rsyslog (it may work better if the input can be processed
+ * totally independent, but I have note evaluated this). So I will look into
+ * an enhanced event-based model with a small set of input workers pulling
+ * off data (I assume this is useful for e.g. TLS, as TLS transport is much
+ * more computebound than other inputs, and this computation becomes a
+ * limiting factor for the overall processing speed under some
+ * circumstances - see [2]).
+ *
+ * For obvious reasons, I will not try to finish imttcp. However, I have
+ * decided to leave it included in the source tree, so that
+ * a) someone else can build on it, if he sees value in that
+ * b) I may use it for some other tests in the future
+ *
+ * But if you intend to actually use this module unmodified, be prepared
+ * for problems.
+ *
+ * [1] R. Von Behren, J. Condit, and E. Brewer. Why events are a bad idea
+ * (for high-concurrency servers). In Proceedings of the 9th conference on Hot
+ * Topics in Operating Systems-Volume 9, page 4. USENIX Association, 2003.
+ *
+ * [2] http://kb.monitorware.com/tls-limited-17800-messages-per-second-t10598.html
+ *
+ * File begun on 2011-01-24 by RGerhards
+ *
+ * Copyright 2007-2011 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"
+#if !defined(HAVE_EPOLL_CREATE)
+# error imttcp requires OS support for epoll - can not build
+ /* imttcp gains speed by using modern Linux capabilities. As such,
+ * it can only be build on platforms supporting the epoll API.
+ */
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/epoll.h>
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#include "rsyslog.h"
+#include "cfsysline.h"
+#include "prop.h"
+#include "dirty.h"
+#include "module-template.h"
+#include "unicode-helper.h"
+#include "glbl.h"
+#include "prop.h"
+#include "errmsg.h"
+#include "srUtils.h"
+#include "datetime.h"
+#include "ruleset.h"
+#include "msg.h"
+#include "net.h" /* for permittedPeers, may be removed when this is removed */
+
+/* the define is from tcpsrv.h, we need to find a new (but easier!!!) abstraction layer some time ... */
+#define TCPSRV_NO_ADDTL_DELIMITER -1 /* specifies that no additional delimiter is to be used in TCP framing */
+
+
+MODULE_TYPE_INPUT
+MODULE_TYPE_NOKEEP
+
+/* static data */
+DEF_IMOD_STATIC_DATA
+DEFobjCurrIf(glbl)
+DEFobjCurrIf(net)
+DEFobjCurrIf(prop)
+DEFobjCurrIf(datetime)
+DEFobjCurrIf(errmsg)
+DEFobjCurrIf(ruleset)
+
+
+
+/* config settings */
+typedef struct configSettings_s {
+ int bEmitMsgOnClose; /* emit an informational message on close by remote peer */
+ int iAddtlFrameDelim; /* addtl frame delimiter, e.g. for netscreen, default none */
+ uchar *pszInputName; /* value for inputname property, NULL is OK and handled by core engine */
+ uchar *lstnIP; /* which IP we should listen on? */
+ ruleset_t *pRuleset; /* ruleset to bind listener to (use system default if unspecified) */
+} configSettings_t;
+
+static configSettings_t cs;
+
+/* data elements describing our running config */
+typedef struct ttcpsrv_s ttcpsrv_t;
+typedef struct ttcplstn_s ttcplstn_t;
+typedef struct ttcpsess_s ttcpsess_t;
+typedef struct epolld_s epolld_t;
+
+/* the ttcp server (listener) object
+ * Note that the object contains support for forming a linked list
+ * of them. It does not make sense to do this seperately.
+ */
+struct ttcpsrv_s {
+ ttcpsrv_t *pNext; /* linked list maintenance */
+ uchar *port; /* Port to listen to */
+ uchar *lstnIP; /* which IP we should listen on? */
+ int bEmitMsgOnClose;
+ int iAddtlFrameDelim;
+ uchar *pszInputName;
+ prop_t *pInputName; /* InputName in (fast to process) property format */
+ ruleset_t *pRuleset;
+ ttcplstn_t *pLstn; /* root of our listeners */
+ ttcpsess_t *pSess; /* root of our sessions */
+ pthread_mutex_t mutSess; /* mutex for session list updates */
+};
+
+/* the ttcp session object. Describes a single active session.
+ * includes support for doubly-linked list.
+ */
+struct ttcpsess_s {
+ ttcpsrv_t *pSrv; /* our server */
+ ttcpsess_t *prev, *next;
+ int sock;
+ pthread_t tid;
+//--- from tcps_sess.h
+ int iMsg; /* index of next char to store in msg */
+ int bAtStrtOfFram; /* are we at the very beginning of a new frame? */
+ enum {
+ eAtStrtFram,
+ eInOctetCnt,
+ eInMsg
+ } inputState; /* our current state */
+ int iOctetsRemain; /* Number of Octets remaining in message */
+ TCPFRAMINGMODE eFraming;
+ uchar *pMsg; /* message (fragment) received */
+ prop_t *peerName; /* host name we received messages from */
+ prop_t *peerIP;
+//--- END from tcps_sess.h
+};
+
+
+/* the ttcp listener object. Describes a single active listener.
+ */
+struct ttcplstn_s {
+ ttcpsrv_t *pSrv; /* our server */
+ ttcplstn_t *prev, *next;
+ int sock;
+ pthread_t tid; /* ID of our listener thread */
+};
+
+
+/* type of object stored in epoll descriptor */
+typedef enum {
+ epolld_lstn,
+ epolld_sess
+} epolld_type_t;
+
+/* an epoll descriptor. contains all information necessary to process
+ * the result of epoll.
+ */
+struct epolld_s {
+ epolld_type_t typ;
+ void *ptr;
+ struct epoll_event ev;
+};
+
+
+/* global data */
+static ttcpsrv_t *pSrvRoot = NULL;
+static int iMaxLine; /* maximum size of a single message */
+pthread_attr_t sessThrdAttr; /* Attribute for session threads; read only after startup */
+
+/* forward definitions */
+static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal);
+static rsRetVal addLstn(ttcpsrv_t *pSrv, int sock);
+static void * sessThrd(void *arg);
+
+
+/* some simple constructors/destructors */
+static void
+destructSess(ttcpsess_t *pSess)
+{
+ free(pSess->pMsg);
+ prop.Destruct(&pSess->peerName);
+ prop.Destruct(&pSess->peerIP);
+ /* TODO: make these inits compile-time switch depending: */
+ pSess->pMsg = NULL;
+ free(pSess);
+}
+
+static void
+destructSrv(ttcpsrv_t *pSrv)
+{
+ prop.Destruct(&pSrv->pInputName);
+ free(pSrv->port);
+ free(pSrv);
+}
+
+
+/* common initialisation for new threads */
+static inline void
+initThrd(void)
+{
+ /* block all signals */
+ sigset_t sigSet;
+ sigfillset(&sigSet);
+ pthread_sigmask(SIG_BLOCK, &sigSet, NULL);
+
+ /* but ignore SIGTTN, which we (ab)use to signal the thread to shutdown -- rgerhards, 2009-07-20 */
+ sigemptyset(&sigSet);
+ sigaddset(&sigSet, SIGTTIN);
+ pthread_sigmask(SIG_UNBLOCK, &sigSet, NULL);
+
+}
+
+
+
+/****************************************** TCP SUPPORT FUNCTIONS ***********************************/
+/* We may later think about moving this into a helper library again. But the whole point
+ * so far was to keep everything related close togehter. -- rgerhards, 2010-08-10
+ */
+
+
+/* Start up a server. That means all of its listeners are created.
+ * Does NOT yet accept/process any incoming data (but binds ports). Hint: this
+ * code is to be executed before dropping privileges.
+ */
+static rsRetVal
+createSrv(ttcpsrv_t *pSrv)
+{
+ DEFiRet;
+ int error, maxs, on = 1;
+ int sock = -1;
+ int numSocks;
+ struct addrinfo hints, *res = NULL, *r;
+ uchar *lstnIP;
+
+ lstnIP = pSrv->lstnIP == NULL ? UCHAR_CONSTANT("") : pSrv->lstnIP;
+
+ DBGPRINTF("imttcp creating listen socket on server '%s', port %s\n", lstnIP, pSrv->port);
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = glbl.GetDefPFFamily();
+ hints.ai_socktype = SOCK_STREAM;
+
+ error = getaddrinfo((char*)pSrv->lstnIP, (char*) pSrv->port, &hints, &res);
+ if(error) {
+ DBGPRINTF("error %d querying server '%s', port '%s'\n", error, pSrv->lstnIP, pSrv->port);
+ ABORT_FINALIZE(RS_RET_INVALID_PORT);
+ }
+
+ /* Count max number of sockets we may open */
+ for(maxs = 0, r = res; r != NULL ; r = r->ai_next, maxs++)
+ /* EMPTY */;
+
+ numSocks = 0; /* num of sockets counter at start of array */
+ for(r = res; r != NULL ; r = r->ai_next) {
+ sock = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
+ if(sock < 0) {
+ if(!(r->ai_family == PF_INET6 && errno == EAFNOSUPPORT))
+ DBGPRINTF("error %d creating tcp listen socket", errno);
+ /* it is debatable if PF_INET with EAFNOSUPPORT should
+ * also be ignored...
+ */
+ continue;
+ }
+
+#ifdef IPV6_V6ONLY
+ if(r->ai_family == AF_INET6) {
+ int iOn = 1;
+ if(setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
+ (char *)&iOn, sizeof (iOn)) < 0) {
+ close(sock);
+ sock = -1;
+ continue;
+ }
+ }
+#endif
+ if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) < 0 ) {
+ DBGPRINTF("error %d setting tcp socket option\n", errno);
+ close(sock);
+ sock = -1;
+ continue;
+ }
+
+ /* We need to enable BSD compatibility. Otherwise an attacker
+ * could flood our log files by sending us tons of ICMP errors.
+ */
+#ifndef BSD
+ if(net.should_use_so_bsdcompat()) {
+ if (setsockopt(sock, SOL_SOCKET, SO_BSDCOMPAT,
+ (char *) &on, sizeof(on)) < 0) {
+ errmsg.LogError(errno, NO_ERRCODE, "TCP setsockopt(BSDCOMPAT)");
+ close(sock);
+ sock = -1;
+ continue;
+ }
+ }
+#endif
+
+ if( (bind(sock, r->ai_addr, r->ai_addrlen) < 0)
+#ifndef IPV6_V6ONLY
+ && (errno != EADDRINUSE)
+#endif
+ ) {
+ /* TODO: check if *we* bound the socket - else we *have* an error! */
+ DBGPRINTF("error %d while binding tcp socket", errno);
+ close(sock);
+ sock = -1;
+ continue;
+ }
+
+ if(listen(sock, 511) < 0) {
+ DBGPRINTF("tcp listen error %d, suspending\n", errno);
+ close(sock);
+ sock = -1;
+ continue;
+ }
+
+ /* if we reach this point, we were able to obtain a valid socket, so we can
+ * create our listener object. -- rgerhards, 2010-08-10
+ */
+ CHKiRet(addLstn(pSrv, sock));
+ ++numSocks;
+ }
+
+ if(numSocks != maxs)
+ DBGPRINTF("We could initialize %d TCP listen sockets out of %d we received "
+ "- this may or may not be an error indication.\n", numSocks, maxs);
+
+ if(numSocks == 0) {
+ DBGPRINTF("No TCP listen sockets could successfully be initialized");
+ ABORT_FINALIZE(RS_RET_COULD_NOT_BIND);
+ }
+
+finalize_it:
+ if(res != NULL)
+ freeaddrinfo(res);
+
+ if(iRet != RS_RET_OK) {
+ if(sock != -1)
+ close(sock);
+ }
+
+ RETiRet;
+}
+
+
+/* Set pRemHost based on the address provided. This is to be called upon accept()ing
+ * a connection request. It must be provided by the socket we received the
+ * message on as well as a NI_MAXHOST size large character buffer for the FQDN.
+ * Please see http://www.hmug.org/man/3/getnameinfo.php (under Caveats)
+ * for some explanation of the code found below. If we detect a malicious
+ * hostname, we return RS_RET_MALICIOUS_HNAME and let the caller decide
+ * on how to deal with that.
+ * rgerhards, 2008-03-31
+ */
+static rsRetVal
+getPeerNames(prop_t **peerName, prop_t **peerIP, struct sockaddr *pAddr)
+{
+ int error;
+ uchar szIP[NI_MAXHOST] = "";
+ uchar szHname[NI_MAXHOST] = "";
+ struct addrinfo hints, *res;
+
+ DEFiRet;
+
+ error = getnameinfo(pAddr, SALEN(pAddr), (char*)szIP, sizeof(szIP), NULL, 0, NI_NUMERICHOST);
+
+ if(error) {
+ DBGPRINTF("Malformed from address %s\n", gai_strerror(error));
+ strcpy((char*)szHname, "???");
+ strcpy((char*)szIP, "???");
+ ABORT_FINALIZE(RS_RET_INVALID_HNAME);
+ }
+
+ if(!glbl.GetDisableDNS()) {
+ error = getnameinfo(pAddr, SALEN(pAddr), (char*)szHname, NI_MAXHOST, NULL, 0, NI_NAMEREQD);
+ if(error == 0) {
+ memset (&hints, 0, sizeof (struct addrinfo));
+ hints.ai_flags = AI_NUMERICHOST;
+ hints.ai_socktype = SOCK_STREAM;
+ /* we now do a lookup once again. This one should fail,
+ * because we should not have obtained a non-numeric address. If
+ * we got a numeric one, someone messed with DNS!
+ */
+ if(getaddrinfo((char*)szHname, NULL, &hints, &res) == 0) {
+ freeaddrinfo (res);
+ /* OK, we know we have evil, so let's indicate this to our caller */
+ snprintf((char*)szHname, NI_MAXHOST, "[MALICIOUS:IP=%s]", szIP);
+ DBGPRINTF("Malicious PTR record, IP = \"%s\" HOST = \"%s\"", szIP, szHname);
+ iRet = RS_RET_MALICIOUS_HNAME;
+ }
+ } else {
+ strcpy((char*)szHname, (char*)szIP);
+ }
+ } else {
+ strcpy((char*)szHname, (char*)szIP);
+ }
+
+ /* We now have the names, so now let's allocate memory and store them permanently. */
+ CHKiRet(prop.Construct(peerName));
+ CHKiRet(prop.SetString(*peerName, szHname, ustrlen(szHname)));
+ CHKiRet(prop.ConstructFinalize(*peerName));
+ CHKiRet(prop.Construct(peerIP));
+ CHKiRet(prop.SetString(*peerIP, szIP, ustrlen(szIP)));
+ CHKiRet(prop.ConstructFinalize(*peerIP));
+
+finalize_it:
+ RETiRet;
+}
+
+
+
+/* accept an incoming connection request
+ * rgerhards, 2008-04-22
+ */
+static rsRetVal
+AcceptConnReq(int sock, int *newSock, prop_t **peerName, prop_t **peerIP)
+{
+ struct sockaddr_storage addr;
+ socklen_t addrlen = sizeof(addr);
+ int iNewSock = -1;
+
+ DEFiRet;
+
+ iNewSock = accept(sock, (struct sockaddr*) &addr, &addrlen);
+ if(iNewSock < 0) {
+ if(errno == EAGAIN || errno == EWOULDBLOCK)
+ ABORT_FINALIZE(RS_RET_NO_MORE_DATA);
+ ABORT_FINALIZE(RS_RET_ACCEPT_ERR);
+ }
+
+ CHKiRet(getPeerNames(peerName, peerIP, (struct sockaddr*) &addr));
+
+ *newSock = iNewSock;
+
+finalize_it:
+ if(iRet != RS_RET_OK) {
+ /* the close may be redundant, but that doesn't hurt... */
+ if(iNewSock != -1)
+ close(iNewSock);
+ }
+
+ RETiRet;
+}
+
+
+/* This is a helper for submitting the message to the rsyslog core.
+ * It does some common processing, including resetting the various
+ * state variables to a "processed" state.
+ * Note that this function is also called if we had a buffer overflow
+ * due to a too-long message. So far, there is no indication this
+ * happened and it may be worth thinking about different handling
+ * of this case (what obviously would require a change to this
+ * function or some related code).
+ * rgerhards, 2009-04-23
+ * EXTRACT from tcps_sess.c
+ */
+static rsRetVal
+doSubmitMsg(ttcpsess_t *pThis, struct syslogTime *stTime, time_t ttGenTime, multi_submit_t *pMultiSub)
+{
+ msg_t *pMsg;
+ DEFiRet;
+
+ if(pThis->iMsg == 0) {
+ DBGPRINTF("discarding zero-sized message\n");
+ FINALIZE;
+ }
+
+ /* we now create our own message object and submit it to the queue */
+ CHKiRet(msgConstructWithTime(&pMsg, stTime, ttGenTime));
+ MsgSetRawMsg(pMsg, (char*)pThis->pMsg, pThis->iMsg);
+ MsgSetInputName(pMsg, pThis->pSrv->pInputName);
+ MsgSetFlowControlType(pMsg, eFLOWCTL_LIGHT_DELAY);
+ pMsg->msgFlags = NEEDS_PARSING | PARSE_HOSTNAME;
+ MsgSetRcvFrom(pMsg, pThis->peerName);
+ CHKiRet(MsgSetRcvFromIP(pMsg, pThis->peerIP));
+ MsgSetRuleset(pMsg, pThis->pSrv->pRuleset);
+
+ if(pMultiSub == NULL) {
+ CHKiRet(submitMsg(pMsg));
+ } else {
+ pMultiSub->ppMsgs[pMultiSub->nElem++] = pMsg;
+ if(pMultiSub->nElem == pMultiSub->maxElem)
+ CHKiRet(multiSubmitMsg(pMultiSub));
+ }
+
+
+finalize_it:
+ /* reset status variables */
+ pThis->bAtStrtOfFram = 1;
+ pThis->iMsg = 0;
+
+ RETiRet;
+}
+
+
+/* process the data received. As TCP is stream based, we need to process the
+ * data inside a state machine. The actual data received is passed in byte-by-byte
+ * from DataRcvd, and this function here compiles messages from them and submits
+ * the end result to the queue. Introducing this function fixes a long-term bug ;)
+ * rgerhards, 2008-03-14
+ * EXTRACT from tcps_sess.c
+ */
+static inline rsRetVal
+processDataRcvd(ttcpsess_t *pThis, char c, struct syslogTime *stTime, time_t ttGenTime, multi_submit_t *pMultiSub)
+{
+ DEFiRet;
+
+ if(pThis->inputState == eAtStrtFram) {
+ if(isdigit((int) c)) {
+ pThis->inputState = eInOctetCnt;
+ pThis->iOctetsRemain = 0;
+ pThis->eFraming = TCP_FRAMING_OCTET_COUNTING;
+ } else {
+ pThis->inputState = eInMsg;
+ pThis->eFraming = TCP_FRAMING_OCTET_STUFFING;
+ }
+ }
+
+ if(pThis->inputState == eInOctetCnt) {
+ if(isdigit(c)) {
+ pThis->iOctetsRemain = pThis->iOctetsRemain * 10 + c - '0';
+ } else { /* done with the octet count, so this must be the SP terminator */
+ DBGPRINTF("TCP Message with octet-counter, size %d.\n", pThis->iOctetsRemain);
+ if(c != ' ') {
+ errmsg.LogError(0, NO_ERRCODE, "Framing Error in received TCP message: "
+ "delimiter is not SP but has ASCII value %d.\n", c);
+ }
+ if(pThis->iOctetsRemain < 1) {
+ /* TODO: handle the case where the octet count is 0! */
+ DBGPRINTF("Framing Error: invalid octet count\n");
+ errmsg.LogError(0, NO_ERRCODE, "Framing Error in received TCP message: "
+ "invalid octet count %d.\n", pThis->iOctetsRemain);
+ } else if(pThis->iOctetsRemain > iMaxLine) {
+ /* while we can not do anything against it, we can at least log an indication
+ * that something went wrong) -- rgerhards, 2008-03-14
+ */
+ DBGPRINTF("truncating message with %d octets - max msg size is %d\n",
+ pThis->iOctetsRemain, iMaxLine);
+ errmsg.LogError(0, NO_ERRCODE, "received oversize message: size is %d bytes, "
+ "max msg size is %d, truncating...\n", pThis->iOctetsRemain, iMaxLine);
+ }
+ pThis->inputState = eInMsg;
+ }
+ } else {
+ assert(pThis->inputState == eInMsg);
+ if(pThis->iMsg >= iMaxLine) {
+ /* emergency, we now need to flush, no matter if we are at end of message or not... */
+ DBGPRINTF("error: message received is larger than max msg size, we split it\n");
+ doSubmitMsg(pThis, stTime, ttGenTime, pMultiSub);
+ /* we might think if it is better to ignore the rest of the
+ * message than to treat it as a new one. Maybe this is a good
+ * candidate for a configuration parameter...
+ * rgerhards, 2006-12-04
+ */
+ }
+
+ if(( (c == '\n')
+ || ((pThis->pSrv->iAddtlFrameDelim != TCPSRV_NO_ADDTL_DELIMITER) && (c == pThis->pSrv->iAddtlFrameDelim))
+ ) && pThis->eFraming == TCP_FRAMING_OCTET_STUFFING) { /* record delimiter? */
+ doSubmitMsg(pThis, stTime, ttGenTime, pMultiSub);
+ pThis->inputState = eAtStrtFram;
+ } else {
+ /* IMPORTANT: here we copy the actual frame content to the message - for BOTH framing modes!
+ * If we have a message that is larger than the max msg size, we truncate it. This is the best
+ * we can do in light of what the engine supports. -- rgerhards, 2008-03-14
+ */
+ if(pThis->iMsg < iMaxLine) {
+ *(pThis->pMsg + pThis->iMsg++) = c;
+ }
+ }
+
+ if(pThis->eFraming == TCP_FRAMING_OCTET_COUNTING) {
+ /* do we need to find end-of-frame via octet counting? */
+ pThis->iOctetsRemain--;
+ if(pThis->iOctetsRemain < 1) {
+ /* we have end of frame! */
+ doSubmitMsg(pThis, stTime, ttGenTime, pMultiSub);
+ pThis->inputState = eAtStrtFram;
+ }
+ }
+ }
+
+ RETiRet;
+}
+
+
+/* Processes the data received via a TCP session. If there
+ * is no other way to handle it, data is discarded.
+ * Input parameter data is the data received, iLen is its
+ * len as returned from recv(). iLen must be 1 or more (that
+ * is errors must be handled by caller!). iTCPSess must be
+ * the index of the TCP session that received the data.
+ * rgerhards 2005-07-04
+ * And another change while generalizing. We now return either
+ * RS_RET_OK, which means the session should be kept open
+ * or anything else, which means it must be closed.
+ * rgerhards, 2008-03-01
+ * As a performance optimization, we pick up the timestamp here. Acutally,
+ * this *is* the *correct* reception step for all the data we received, because
+ * we have just received a bunch of data! -- rgerhards, 2009-06-16
+ * EXTRACT from tcps_sess.c
+ */
+#define NUM_MULTISUB 1024
+static rsRetVal
+DataRcvd(ttcpsess_t *pThis, char *pData, size_t iLen)
+{
+ multi_submit_t multiSub;
+ msg_t *pMsgs[NUM_MULTISUB];
+ struct syslogTime stTime;
+ time_t ttGenTime;
+ char *pEnd;
+ DEFiRet;
+
+ assert(pData != NULL);
+ assert(iLen > 0);
+
+ datetime.getCurrTime(&stTime, &ttGenTime);
+ multiSub.ppMsgs = pMsgs;
+ multiSub.maxElem = NUM_MULTISUB;
+ multiSub.nElem = 0;
+
+ /* We now copy the message to the session buffer. */
+ pEnd = pData + iLen; /* this is one off, which is intensional */
+
+ while(pData < pEnd) {
+ CHKiRet(processDataRcvd(pThis, *pData++, &stTime, ttGenTime, &multiSub));
+ }
+
+ if(multiSub.nElem > 0) {
+ /* submit anything that was not yet submitted */
+ CHKiRet(multiSubmitMsg(&multiSub));
+ }
+
+finalize_it:
+ RETiRet;
+}
+#undef NUM_MULTISUB
+
+
+/****************************************** --END-- TCP SUPPORT FUNCTIONS ***********************************/
+
+
+static inline void
+initConfigSettings(void)
+{
+ cs.bEmitMsgOnClose = 0;
+ cs.iAddtlFrameDelim = TCPSRV_NO_ADDTL_DELIMITER;
+ cs.pszInputName = NULL;
+ cs.pRuleset = NULL;
+ cs.lstnIP = NULL;
+}
+
+
+/* add a listener to the server
+ */
+static rsRetVal
+addLstn(ttcpsrv_t *pSrv, int sock)
+{
+ DEFiRet;
+ ttcplstn_t *pLstn;
+
+ CHKmalloc(pLstn = malloc(sizeof(ttcplstn_t)));
+ pLstn->pSrv = pSrv;
+ pLstn->sock = sock;
+
+ /* add to start of server's listener list */
+ pLstn->prev = NULL;
+ pLstn->next = pSrv->pLstn;
+ if(pSrv->pLstn != NULL)
+ pSrv->pLstn->prev = pLstn;
+ pSrv->pLstn = pLstn;
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* add a session to the server
+ */
+static rsRetVal
+addSess(ttcpsrv_t *pSrv, int sock, prop_t *peerName, prop_t *peerIP)
+{
+ DEFiRet;
+ ttcpsess_t *pSess = NULL;
+
+ CHKmalloc(pSess = malloc(sizeof(ttcpsess_t)));
+ CHKmalloc(pSess->pMsg = malloc(iMaxLine * sizeof(uchar)));
+ pSess->pSrv = pSrv;
+ pSess->sock = sock;
+ pSess->inputState = eAtStrtFram;
+ pSess->iMsg = 0;
+ pSess->bAtStrtOfFram = 1;
+ pSess->peerName = peerName;
+ pSess->peerIP = peerIP;
+
+ /* add to start of server's listener list */
+ pSess->prev = NULL;
+ pthread_mutex_lock(&pSrv->mutSess);
+ pSess->next = pSrv->pSess;
+ if(pSrv->pSess != NULL)
+ pSrv->pSess->prev = pSess;
+ pSrv->pSess = pSess;
+ pthread_mutex_unlock(&pSrv->mutSess);
+
+ /* finally run session handler */
+ pthread_create(&pSess->tid, &sessThrdAttr, sessThrd, (void*) pSess);
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* close/remove a session
+ * NOTE: we must first remove the fd from the epoll set and then close it -- else we
+ * get an error "bad file descriptor" from epoll.
+ */
+static inline rsRetVal
+closeSess(ttcpsess_t *pSess)
+{
+ int sock;
+ DEFiRet;
+
+ sock = pSess->sock;
+ close(sock);
+
+ /* finally unlink session from structures */
+ pthread_mutex_lock(&pSess->pSrv->mutSess);
+ if(pSess->next != NULL)
+ pSess->next->prev = pSess->prev;
+ if(pSess->prev == NULL) {
+ /* need to update root! */
+ pSess->pSrv->pSess = pSess->next;
+ } else {
+ pSess->prev->next = pSess->next;
+ }
+ pthread_mutex_unlock(&pSess->pSrv->mutSess);
+
+ /* unlinked, now remove structure */
+ destructSess(pSess);
+
+ RETiRet;
+}
+
+
+/* accept a new ruleset to bind. Checks if it exists and complains, if not */
+static rsRetVal setRuleset(void __attribute__((unused)) *pVal, uchar *pszName)
+{
+ ruleset_t *pRuleset;
+ rsRetVal localRet;
+ DEFiRet;
+
+ localRet = ruleset.GetRuleset(&pRuleset, pszName);
+ if(localRet == RS_RET_NOT_FOUND) {
+ errmsg.LogError(0, NO_ERRCODE, "error: ruleset '%s' not found - ignored", pszName);
+ }
+ CHKiRet(localRet);
+ cs.pRuleset = pRuleset;
+ DBGPRINTF("imttcp current bind ruleset %p: '%s'\n", pRuleset, pszName);
+
+finalize_it:
+ free(pszName); /* no longer needed */
+ RETiRet;
+}
+
+
+static rsRetVal addTCPListener(void __attribute__((unused)) *pVal, uchar *pNewVal)
+{
+ DEFiRet;
+ ttcpsrv_t *pSrv;
+
+ CHKmalloc(pSrv = malloc(sizeof(ttcpsrv_t)));
+ pthread_mutex_init(&pSrv->mutSess, NULL);
+ pSrv->pSess = NULL;
+ pSrv->pLstn = NULL;
+ pSrv->bEmitMsgOnClose = cs.bEmitMsgOnClose;
+ pSrv->port = pNewVal;
+ pSrv->iAddtlFrameDelim = cs.iAddtlFrameDelim;
+ cs.pszInputName = NULL; /* moved over to pSrv, we do not own */
+ pSrv->lstnIP = cs.lstnIP;
+ cs.lstnIP = NULL; /* moved over to pSrv, we do not own */
+ pSrv->pRuleset = cs.pRuleset;
+ pSrv->pszInputName = (cs.pszInputName == NULL) ? UCHAR_CONSTANT("imttcp") : cs.pszInputName;
+ CHKiRet(prop.Construct(&pSrv->pInputName));
+ CHKiRet(prop.SetString(pSrv->pInputName, pSrv->pszInputName, ustrlen(pSrv->pszInputName)));
+ CHKiRet(prop.ConstructFinalize(pSrv->pInputName));
+
+ /* add to linked list */
+ pSrv->pNext = pSrvRoot;
+ pSrvRoot = pSrv;
+
+ /* all config vars are auto-reset -- this also is very useful with the
+ * new config format effort (v6).
+ */
+ resetConfigVariables(NULL, NULL);
+
+finalize_it:
+ if(iRet != RS_RET_OK) {
+ errmsg.LogError(0, NO_ERRCODE, "error %d trying to add listener", iRet);
+ }
+ RETiRet;
+}
+
+
+/* create up all listeners
+ * This is a one-time stop once the module is set to start.
+ */
+static inline rsRetVal
+createServers()
+{
+ DEFiRet;
+ ttcpsrv_t *pSrv;
+
+ pSrv = pSrvRoot;
+ while(pSrv != NULL) {
+ DBGPRINTF("Starting up ttcp server for port %s, name '%s'\n", pSrv->port, pSrv->pszInputName);
+ createSrv(pSrv);
+ pSrv = pSrv->pNext;
+ }
+
+ RETiRet;
+}
+
+
+/* This function implements the thread to be used for listeners.
+ * The function terminates if shutdown is required.
+ */
+static void *
+lstnThrd(void *arg)
+{
+ ttcplstn_t *pLstn = (ttcplstn_t *) arg;
+ rsRetVal iRet = RS_RET_OK;
+ int newSock;
+ prop_t *peerName;
+ prop_t *peerIP;
+ rsRetVal localRet;
+
+ initThrd();
+
+ while(glbl.GetGlobalInputTermState() == 0) {
+ localRet = AcceptConnReq(pLstn->sock, &newSock, &peerName, &peerIP);
+ if(glbl.GetGlobalInputTermState() == 1)
+ break; /* terminate input! */
+ CHKiRet(localRet);
+ DBGPRINTF("imttcp: new connection %d on listen socket %d\n", newSock, pLstn->sock);
+ CHKiRet(addSess(pLstn->pSrv, newSock, peerName, peerIP));
+ }
+
+finalize_it:
+ close(pLstn->sock);
+ DBGPRINTF("imttcp shutdown listen socket %d\n", pLstn->sock);
+ /* Note: we do NOT unlink the deleted session. While this sounds not 100% clean,
+ * it is fine with the current implementation as we will never reuse these elements.
+ * However, it make sense (and not cost notable performance) to do it "right"...
+ */
+ return NULL;
+}
+
+
+/* This function implements the thread to be used for a session
+ * The function terminates if shutdown is required.
+ */
+static void *
+sessThrd(void *arg)
+{
+ ttcpsess_t *pSess = (ttcpsess_t*) arg;
+ rsRetVal iRet = RS_RET_OK;
+ int lenRcv;
+ int lenBuf;
+ char rcvBuf[64*1024];
+
+ initThrd();
+
+ while(glbl.GetGlobalInputTermState() == 0) {
+ lenBuf = sizeof(rcvBuf);
+ lenRcv = recv(pSess->sock, rcvBuf, lenBuf, 0);
+
+ if(glbl.GetGlobalInputTermState() == 1)
+ ABORT_FINALIZE(RS_RET_FORCE_TERM);
+
+ if(lenRcv > 0) {
+ /* have data, process it */
+ DBGPRINTF("imttcp: data(%d) on socket %d: %s\n", lenRcv, pSess->sock, rcvBuf);
+ CHKiRet(DataRcvd(pSess, rcvBuf, lenRcv));
+ } else if (lenRcv == 0) {
+ /* session was closed, do clean-up */
+ if(pSess->pSrv->bEmitMsgOnClose) {
+ uchar *peerName;
+ int lenPeer;
+ prop.GetString(pSess->peerName, &peerName, &lenPeer);
+ errmsg.LogError(0, RS_RET_PEER_CLOSED_CONN, "imttcp session %d closed by remote peer %s.\n",
+ pSess->sock, peerName);
+ }
+ break;
+ } else {
+ if(errno == EAGAIN)
+ break;
+ DBGPRINTF("imttcp: error on session socket %d - closing.\n", pSess->sock);
+ break;
+ }
+ }
+
+finalize_it:
+ DBGPRINTF("imttcp: session thread terminates, socket %d\n", pSess->sock);
+ closeSess(pSess); /* try clean-up by dropping session */
+ return NULL;
+}
+
+/* startup all listeners
+ */
+static inline rsRetVal
+startupListeners()
+{
+ DEFiRet;
+ ttcpsrv_t *pSrv;
+ ttcplstn_t *pLstn;
+
+ pSrv = pSrvRoot;
+ while(pSrv != NULL) {
+ for(pLstn = pSrv->pLstn ; pLstn != NULL ; pLstn = pLstn->next) {
+ pthread_create(&pLstn->tid, NULL, lstnThrd, (void*) pLstn);
+ }
+ pSrv = pSrv->pNext;
+ }
+
+ RETiRet;
+}
+
+/* This function is called to gather input.
+ */
+BEGINrunInput
+ struct timeval tvSelectTimeout;
+CODESTARTrunInput
+ DBGPRINTF("imttcp: now beginning to process input data\n");
+ CHKiRet(startupListeners());
+
+ // TODO: this loop is a quick hack, do it right!
+ while(glbl.GetGlobalInputTermState() == 0) {
+ tvSelectTimeout.tv_sec = 86400 /*1 day*/;
+ tvSelectTimeout.tv_usec = 0;
+ select(1, NULL, NULL, NULL, &tvSelectTimeout);
+ }
+finalize_it: ;
+ENDrunInput
+
+
+/* initialize and return if will run or not */
+BEGINwillRun
+CODESTARTwillRun
+ /* first apply some config settings */
+ iMaxLine = glbl.GetMaxLine(); /* get maximum size we currently support */
+
+ if(pSrvRoot == NULL) {
+ errmsg.LogError(0, RS_RET_NO_LSTN_DEFINED, "error: no ttcp server defined, module can not run.");
+ ABORT_FINALIZE(RS_RET_NO_RUN);
+ }
+
+ /* start up servers, but do not yet read input data */
+ CHKiRet(createServers());
+ DBGPRINTF("imttcp started up, but not yet receiving data\n");
+finalize_it:
+ENDwillRun
+
+
+/* completely shut down a server. All we need to do is unblock the
+ * various session and listerner threads as they then check the termination
+ * praedicate themselves.
+ */
+static inline void
+shutdownSrv(ttcpsrv_t *pSrv)
+{
+ ttcplstn_t *pLstn;
+ ttcplstn_t *pLstnDel;
+ ttcpsess_t *pSess;
+ pthread_t tid;
+
+ pLstn = pSrv->pLstn;
+ while(pLstn != NULL) {
+ tid = pLstn->tid; /* pSess will be destructed! */
+ pthread_kill(tid, SIGTTIN);
+ DBGPRINTF("imttcp: termination request for listen thread %x\n", (unsigned) tid);
+ pthread_join(tid, NULL);
+ DBGPRINTF("imttcp: listen thread %x terminated \n", (unsigned) tid);
+ pLstnDel = pLstn;
+ pLstn = pLstn->next;
+ free(pLstnDel);
+ }
+
+ pSess = pSrv->pSess;
+ while(pSess != NULL) {
+ tid = pSess->tid; /* pSess will be destructed! */
+ pSess = pSess->next;
+ pthread_kill(tid, SIGTTIN);
+ DBGPRINTF("imttcp: termination request for session thread %x\n", (unsigned) tid);
+ //pthread_join(tid, NULL);
+ DBGPRINTF("imttcp: session thread %x terminated \n", (unsigned) tid);
+ }
+}
+
+
+BEGINafterRun
+ ttcpsrv_t *pSrv, *srvDel;
+CODESTARTafterRun
+ /* do cleanup here */
+ /* we need to close everything that is still open */
+ pSrv = pSrvRoot;
+ while(pSrv != NULL) {
+ srvDel = pSrv;
+ pSrv = pSrv->pNext;
+ shutdownSrv(srvDel);
+ destructSrv(srvDel);
+ }
+ENDafterRun
+
+
+BEGINmodExit
+CODESTARTmodExit
+ pthread_attr_destroy(&sessThrdAttr);
+
+ /* release objects we used */
+ objRelease(glbl, CORE_COMPONENT);
+ objRelease(prop, CORE_COMPONENT);
+ objRelease(net, LM_NET_FILENAME);
+ objRelease(datetime, CORE_COMPONENT);
+ objRelease(errmsg, CORE_COMPONENT);
+ objRelease(ruleset, CORE_COMPONENT);
+ENDmodExit
+
+
+static rsRetVal
+resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
+{
+ cs.bEmitMsgOnClose = 0;
+ cs.iAddtlFrameDelim = TCPSRV_NO_ADDTL_DELIMITER;
+ free(cs.pszInputName);
+ cs.pszInputName = NULL;
+ free(cs.lstnIP);
+ cs.lstnIP = NULL;
+ return RS_RET_OK;
+}
+
+
+
+BEGINqueryEtryPt
+CODESTARTqueryEtryPt
+CODEqueryEtryPt_STD_IMOD_QUERIES
+ENDqueryEtryPt
+
+
+BEGINmodInit()
+CODESTARTmodInit
+ *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
+CODEmodInit_QueryRegCFSLineHdlr
+ initConfigSettings();
+ /* request objects we use */
+ CHKiRet(objUse(glbl, CORE_COMPONENT));
+ CHKiRet(objUse(prop, CORE_COMPONENT));
+ CHKiRet(objUse(net, LM_NET_FILENAME));
+ CHKiRet(objUse(errmsg, CORE_COMPONENT));
+ CHKiRet(objUse(datetime, CORE_COMPONENT));
+ CHKiRet(objUse(ruleset, CORE_COMPONENT));
+
+ /* initialize "read-only" thread attributes */
+ pthread_attr_init(&sessThrdAttr);
+ pthread_attr_setdetachstate(&sessThrdAttr, PTHREAD_CREATE_DETACHED);
+ pthread_attr_setstacksize(&sessThrdAttr, 200*1024);
+
+ /* register config file handlers */
+ CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputttcpserverrun"), 0, eCmdHdlrGetWord,
+ addTCPListener, NULL, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputttcpservernotifyonconnectionclose"), 0,
+ eCmdHdlrBinary, NULL, &cs.bEmitMsgOnClose, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputttcpserveraddtlframedelimiter"), 0, eCmdHdlrInt,
+ NULL, &cs.iAddtlFrameDelim, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputttcpserverinputname"), 0,
+ eCmdHdlrGetWord, NULL, &cs.pszInputName, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputttcpserverlistenip"), 0,
+ eCmdHdlrGetWord, NULL, &cs.lstnIP, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputttcpserverbindruleset"), 0,
+ eCmdHdlrGetWord, setRuleset, NULL, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("resetconfigvariables"), 1, eCmdHdlrCustomHandler,
+ resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
+ENDmodInit
+
+
+/* vim:set ai:
+ */
diff --git a/plugins/imudp/imudp.c b/plugins/imudp/imudp.c
index a5002591..e68bcf37 100644
--- a/plugins/imudp/imudp.c
+++ b/plugins/imudp/imudp.c
@@ -675,9 +675,9 @@ CODEmodInit_QueryRegCFSLineHdlr
CHKiRet(omsdRegCFSLineHdlr((uchar *)"udpserveraddress", 0, eCmdHdlrGetWord,
NULL, &pszBindAddr, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"imudpschedulingpolicy", 0, eCmdHdlrGetWord,
- &set_scheduling_policy, &pszSchedPolicy, STD_LOADABLE_MODULE_ID));
+ &set_scheduling_policy, NULL, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"imudpschedulingpriority", 0, eCmdHdlrInt,
- &set_scheduling_priority, &iSchedPrio, STD_LOADABLE_MODULE_ID));
+ &set_scheduling_priority, NULL, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"udpservertimerequery", 0, eCmdHdlrInt,
NULL, &iTimeRequery, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler,
diff --git a/plugins/imuxsock/imuxsock.c b/plugins/imuxsock/imuxsock.c
index 9ad24213..251f4786 100644
--- a/plugins/imuxsock/imuxsock.c
+++ b/plugins/imuxsock/imuxsock.c
@@ -970,10 +970,10 @@ CODEmodInit_QueryRegCFSLineHdlr
NULL, &bUseFlowCtl, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensocketcreatepath", 0, eCmdHdlrBinary,
NULL, &bCreatePath, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensocketusepidfromsystem", 0, eCmdHdlrBinary,
- NULL, &bWritePid, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"addunixlistensocket", 0, eCmdHdlrGetWord,
addLstnSocketName, NULL, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensocketusepidfromsystem", 0, eCmdHdlrBinary,
+ NULL, &bWritePid, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"imuxsockratelimitinterval", 0, eCmdHdlrInt,
NULL, &ratelimitInterval, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"imuxsockratelimitburst", 0, eCmdHdlrInt,
diff --git a/plugins/mmnormalize/Makefile.am b/plugins/mmnormalize/Makefile.am
new file mode 100644
index 00000000..0a3b5ba5
--- /dev/null
+++ b/plugins/mmnormalize/Makefile.am
@@ -0,0 +1,8 @@
+pkglib_LTLIBRARIES = mmnormalize.la
+
+mmnormalize_la_SOURCES = mmnormalize.c
+mmnormalize_la_CPPFLAGS = $(RSRT_CFLAGS) $(PTHREADS_CFLAGS) $(LIBLOGNORM_CFLAGS) $(LIBEE_CFLAGS)
+mmnormalize_la_LDFLAGS = -module -avoid-version $(LIBLOGNORM_LIBS) $(LIBEE_LIBS)
+mmnormalize_la_LIBADD =
+
+EXTRA_DIST =
diff --git a/plugins/mmnormalize/mmnormalize.c b/plugins/mmnormalize/mmnormalize.c
new file mode 100644
index 00000000..adba0efe
--- /dev/null
+++ b/plugins/mmnormalize/mmnormalize.c
@@ -0,0 +1,274 @@
+/* mmnormalize.c
+ * This is a message modification module. It normalizes the input message with
+ * the help of liblognorm. The messages EE event structure is updated.
+ *
+ * NOTE: read comments in module-template.h for details on the calling interface!
+ *
+ * File begun on 2010-01-01 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 <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <signal.h>
+#include <errno.h>
+#include <unistd.h>
+#include <libestr.h>
+#include <libee/libee.h>
+#include <liblognorm.h>
+#include "conf.h"
+#include "syslogd-types.h"
+#include "template.h"
+#include "module-template.h"
+#include "errmsg.h"
+#include "cfsysline.h"
+#include "dirty.h"
+
+MODULE_TYPE_OUTPUT
+MODULE_TYPE_NOKEEP
+
+static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal);
+
+/* static data */
+DEFobjCurrIf(errmsg);
+
+/* internal structures
+ */
+DEF_OMOD_STATIC_DATA
+
+typedef struct _instanceData {
+ sbool bUseRawMsg; /**< use %rawmsg% instead of %msg% */
+ ln_ctx ctxln; /**< context to be used for liblognorm */
+ ee_ctx ctxee; /**< context to be used for libee */
+} instanceData;
+
+typedef struct configSettings_s {
+ uchar *rulebase; /**< name of normalization rulebase to use */
+ sbool bUseRawMsg; /**< use %rawmsg% instead of %msg% */
+} configSettings_t;
+
+SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */
+
+BEGINinitConfVars /* (re)set config variables to default values */
+CODESTARTinitConfVars
+ resetConfigVariables(NULL, NULL);
+ENDinitConfVars
+
+
+BEGINcreateInstance
+CODESTARTcreateInstance
+ENDcreateInstance
+
+
+BEGINisCompatibleWithFeature
+CODESTARTisCompatibleWithFeature
+ENDisCompatibleWithFeature
+
+
+BEGINfreeInstance
+CODESTARTfreeInstance
+ ee_exitCtx(pData->ctxee);
+ ln_exitCtx(pData->ctxln);
+ENDfreeInstance
+
+
+BEGINdbgPrintInstInfo
+CODESTARTdbgPrintInstInfo
+ dbgprintf("mmnormalize\n");
+ENDdbgPrintInstInfo
+
+
+BEGINtryResume
+CODESTARTtryResume
+ENDtryResume
+
+BEGINdoAction
+ msg_t *pMsg;
+ es_str_t *str;
+ uchar *buf;
+ int len;
+ int r;
+CODESTARTdoAction
+ pMsg = (msg_t*) ppString[0];
+ /* note that we can performance-optimize the interface, but this also
+ * requires changes to the libraries. For now, we accept message
+ * duplication. -- rgerhards, 2010-12-01
+ */
+ if(pData->bUseRawMsg) {
+ getRawMsg(pMsg, &buf, &len);
+ } else {
+ buf = getMSG(pMsg);
+ len = getMSGLen(pMsg);
+ }
+ str = es_newStrFromCStr((char*)buf, len);
+ r = ln_normalize(pData->ctxln, str, &pMsg->event);
+ if(r != 0) {
+ DBGPRINTF("error %d during ln_normalize\n", r);
+ }
+ es_deleteStr(str);
+ /***DEBUG***/ // TODO: remove after initial testing - 2010-12-01
+ {
+ char *cstr;
+ ee_fmtEventToJSON(pMsg->event, &str);
+ cstr = es_str2cstr(str, NULL);
+ dbgprintf("mmnormalize generated: %s\n", cstr);
+ free(cstr);
+ es_deleteStr(str);
+ }
+ /***END DEBUG***/
+ENDdoAction
+
+
+BEGINparseSelectorAct
+CODESTARTparseSelectorAct
+CODE_STD_STRING_REQUESTparseSelectorAct(1)
+ /* first check if this config line is actually for us */
+ if(strncmp((char*) p, ":mmnormalize:", sizeof(":mmnormalize:") - 1)) {
+ ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED);
+ }
+
+ if(cs.rulebase == NULL) {
+ errmsg.LogError(0, RS_RET_NO_RULESET, "error: no normalization rulebase was specified, use "
+ "$MMNormalizeSampleDB directive first!");
+ ABORT_FINALIZE(RS_RET_NO_RULESET);
+ }
+
+ /* ok, if we reach this point, we have something for us */
+ p += sizeof(":mmnormalize:") - 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 call the function below because we need to call it via our interface definition. However,
+ * the format specified (if any) is always ignored.
+ */
+ CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_TPL_AS_MSG, (uchar*) "RSYSLOG_FileFormat"));
+
+ /* finally build the instance */
+ if((pData->ctxee = ee_initCtx()) == NULL) {
+ errmsg.LogError(0, RS_RET_NO_RULESET, "error: could not initialize libee ctx, cannot "
+ "activate action");
+ ABORT_FINALIZE(RS_RET_ERR_LIBEE_INIT);
+ }
+
+ if((pData->ctxln = ln_initCtx()) == NULL) {
+ errmsg.LogError(0, RS_RET_NO_RULESET, "error: could not initialize liblognorm ctx, cannot "
+ "activate action");
+ ee_exitCtx(pData->ctxee);
+ ABORT_FINALIZE(RS_RET_ERR_LIBLOGNORM_INIT);
+ }
+ ln_setEECtx(pData->ctxln, pData->ctxee);
+ if(ln_loadSamples(pData->ctxln, (char*) cs.rulebase) != 0) {
+ errmsg.LogError(0, RS_RET_NO_RULESET, "error: normalization rulebase '%s' could not be loaded "
+ "cannot activate action", cs.rulebase);
+ ee_exitCtx(pData->ctxee);
+ ln_exitCtx(pData->ctxln);
+ ABORT_FINALIZE(RS_RET_ERR_LIBLOGNORM_SAMPDB_LOAD);
+ }
+ pData->bUseRawMsg = cs.bUseRawMsg;
+
+ /* all config vars auto-reset! */
+ cs.bUseRawMsg = 0;
+ free(cs.rulebase);
+ cs.rulebase = NULL;
+CODE_STD_FINALIZERparseSelectorAct
+ENDparseSelectorAct
+
+
+BEGINmodExit
+CODESTARTmodExit
+ objRelease(errmsg, CORE_COMPONENT);
+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;
+ cs.rulebase = NULL;
+ cs.bUseRawMsg = 0;
+ RETiRet;
+}
+
+/* set the rulebase name */
+static rsRetVal
+setRuleBase(void __attribute__((unused)) *pVal, uchar *pszName)
+{
+ DEFiRet;
+ cs.rulebase = pszName;
+ pszName = NULL;
+ RETiRet;
+}
+
+BEGINmodInit()
+ rsRetVal localRet;
+ rsRetVal (*pomsrGetSupportedTplOpts)(unsigned long *pOpts);
+ unsigned long opts;
+ int bMsgPassingSupported;
+CODESTARTmodInit
+SCOPINGmodInit
+ *ipIFVersProvided = CURR_MOD_IF_VERSION;
+ /* we only support the current interface specification */
+CODEmodInit_QueryRegCFSLineHdlr
+ /* check if the rsyslog core supports parameter passing code */
+ bMsgPassingSupported = 0;
+ localRet = pHostQueryEtryPt((uchar*)"OMSRgetSupportedTplOpts",
+ &pomsrGetSupportedTplOpts);
+ if(localRet == RS_RET_OK) {
+ /* found entry point, so let's see if core supports msg passing */
+ CHKiRet((*pomsrGetSupportedTplOpts)(&opts));
+ if(opts & OMSR_TPL_AS_MSG)
+ bMsgPassingSupported = 1;
+ } else if(localRet != RS_RET_ENTRY_POINT_NOT_FOUND) {
+ ABORT_FINALIZE(localRet); /* Something else went wrong, not acceptable */
+ }
+
+ if(!bMsgPassingSupported) {
+ DBGPRINTF("mmnormalize: msg-passing is not supported by rsyslog core, "
+ "can not continue.\n");
+ ABORT_FINALIZE(RS_RET_NO_MSG_PASSING);
+ }
+
+ CHKiRet(objUse(errmsg, CORE_COMPONENT));
+
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"mmnormalizerulebase", 0, eCmdHdlrGetWord,
+ setRuleBase, NULL, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"mmnormalizeuserawmsg", 0, eCmdHdlrInt,
+ NULL, &cs.bUseRawMsg, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler,
+ resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
+ENDmodInit
+
+/* vi:set ai:
+ */
diff --git a/plugins/mmsnmptrapd/mmsnmptrapd.c b/plugins/mmsnmptrapd/mmsnmptrapd.c
index 767829d6..bbe2619f 100644
--- a/plugins/mmsnmptrapd/mmsnmptrapd.c
+++ b/plugins/mmsnmptrapd/mmsnmptrapd.c
@@ -76,10 +76,7 @@ typedef struct configSettings_s {
uchar *pszTagName; /**< name of tag start value that indicates snmptrapd initiated message */
uchar *pszSeverityMapping; /**< severitystring to numerical code mapping for snmptrapd string */
} configSettings_t;
-configSettings_t cs;
-//TODO: enable for v6
-#if 0
SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */
BEGINinitConfVars /* (re)set config variables to default values */
@@ -88,7 +85,6 @@ CODESTARTinitConfVars
cs.pszSeverityMapping = NULL;
resetConfigVariables(NULL, NULL);
ENDinitConfVars
-#endif
BEGINcreateInstance
@@ -389,7 +385,7 @@ BEGINmodInit()
unsigned long opts;
int bMsgPassingSupported;
CODESTARTmodInit
-//TODO v6: add SCOPINGmodInit
+SCOPINGmodInit
*ipIFVersProvided = CURR_MOD_IF_VERSION;
/* we only support the current interface specification */
CODEmodInit_QueryRegCFSLineHdlr
diff --git a/plugins/omgssapi/omgssapi.c b/plugins/omgssapi/omgssapi.c
index 21c540b7..25995248 100644
--- a/plugins/omgssapi/omgssapi.c
+++ b/plugins/omgssapi/omgssapi.c
@@ -61,6 +61,8 @@ MODULE_TYPE_OUTPUT
MODULE_TYPE_NOKEEP
+static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal);
+
/* internal structures
*/
DEF_OMOD_STATIC_DATA
@@ -86,12 +88,24 @@ typedef struct _instanceData {
} instanceData;
/* config data */
-static uchar *pszTplName = NULL; /* name of the default template to use */
-static char *gss_base_service_name = NULL;
-static enum gss_mode_t {
+
+typedef enum gss_mode_e {
GSSMODE_MIC,
GSSMODE_ENC
-} gss_mode = GSSMODE_ENC;
+} gss_mode_t;
+
+typedef struct configSettings_s {
+ uchar *pszTplName; /* name of the default template to use */
+ char *gss_base_service_name;
+ gss_mode_t gss_mode;
+} configSettings_t;
+
+SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */
+
+BEGINinitConfVars /* (re)set config variables to default values */
+CODESTARTinitConfVars
+ resetConfigVariables(NULL, NULL);
+ENDinitConfVars
/* get the syslog forward port from selector_t. The passed in
* struct must be one that is setup for forwarding.
@@ -142,10 +156,8 @@ CODESTARTfreeInstance
/* this is meant to be done when module is unloaded,
but since this module is static...
*/
- if (gss_base_service_name != NULL) {
- free(gss_base_service_name);
- gss_base_service_name = NULL;
- }
+ free(cs.gss_base_service_name);
+ cs.gss_base_service_name = NULL;
/* final cleanup */
tcpclt.Destruct(&pData->pTCPClt);
@@ -192,7 +204,7 @@ static rsRetVal TCPSendGSSInit(void *pvData)
if(pData->sock > 0)
ABORT_FINALIZE(RS_RET_OK);
- base = (gss_base_service_name == NULL) ? "host" : gss_base_service_name;
+ base = (cs.gss_base_service_name == NULL) ? "host" : cs.gss_base_service_name;
out_tok.length = strlen(pData->f_hname) + strlen(base) + 2;
CHKmalloc(out_tok.value = MALLOC(out_tok.length));
strcpy(out_tok.value, base);
@@ -216,10 +228,10 @@ static rsRetVal TCPSendGSSInit(void *pvData)
sess_flags = &pData->gss_flags;
*sess_flags = GSS_C_MUTUAL_FLAG;
- if (gss_mode == GSSMODE_MIC) {
+ if (cs.gss_mode == GSSMODE_MIC) {
*sess_flags |= GSS_C_INTEG_FLAG;
}
- if (gss_mode == GSSMODE_ENC) {
+ if (cs.gss_mode == GSSMODE_ENC) {
*sess_flags |= GSS_C_CONF_FLAG;
}
dbgprintf("GSS-API requested context flags:\n");
@@ -300,7 +312,7 @@ static rsRetVal TCPSendGSSSend(void *pvData, char *msg, size_t len)
context = &pData->gss_context;
in_buf.value = msg;
in_buf.length = len;
- maj_stat = gss_wrap(&min_stat, *context, (gss_mode == GSSMODE_ENC) ? 1 : 0, GSS_C_QOP_DEFAULT,
+ maj_stat = gss_wrap(&min_stat, *context, (cs.gss_mode == GSSMODE_ENC) ? 1 : 0, GSS_C_QOP_DEFAULT,
&in_buf, NULL, &out_buf);
if (maj_stat != GSS_S_COMPLETE) {
gssutil.display_status("wrapping message", maj_stat, min_stat);
@@ -602,7 +614,7 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1)
/* process template */
CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS,
- (pszTplName == NULL) ? (uchar*)"RSYSLOG_TraditionalForwardFormat" : pszTplName));
+ (cs.pszTplName == NULL) ? (uchar*)"RSYSLOG_TraditionalForwardFormat" : cs.pszTplName));
/* first set the pData->eDestState */
memset(&hints, 0, sizeof(hints));
@@ -639,9 +651,9 @@ CODESTARTmodExit
objRelease(gssutil, LM_GSSUTIL_FILENAME);
objRelease(tcpclt, LM_TCPCLT_FILENAME);
- if(pszTplName != NULL) {
- free(pszTplName);
- pszTplName = NULL;
+ if(cs.pszTplName != NULL) {
+ free(cs.pszTplName);
+ cs.pszTplName = NULL;
}
ENDmodExit
@@ -658,10 +670,10 @@ static rsRetVal setGSSMode(void __attribute__((unused)) *pVal, uchar *mode)
DEFiRet;
if (!strcmp((char *) mode, "integrity")) {
- gss_mode = GSSMODE_MIC;
+ cs.gss_mode = GSSMODE_MIC;
dbgprintf("GSS-API gssmode set to GSSMODE_MIC\n");
} else if (!strcmp((char *) mode, "encryption")) {
- gss_mode = GSSMODE_ENC;
+ cs.gss_mode = GSSMODE_ENC;
dbgprintf("GSS-API gssmode set to GSSMODE_ENC\n");
} else {
errmsg.LogError(0, RS_RET_INVALID_PARAMS, "unknown gssmode parameter: %s", (char *) mode);
@@ -675,21 +687,18 @@ static rsRetVal setGSSMode(void __attribute__((unused)) *pVal, uchar *mode)
static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
{
- gss_mode = GSSMODE_ENC;
- if (gss_base_service_name != NULL) {
- free(gss_base_service_name);
- gss_base_service_name = NULL;
- }
- if(pszTplName != NULL) {
- free(pszTplName);
- pszTplName = NULL;
- }
+ cs.gss_mode = GSSMODE_ENC;
+ free(cs.gss_base_service_name);
+ cs.gss_base_service_name = NULL;
+ free(cs.pszTplName);
+ cs.pszTplName = NULL;
return RS_RET_OK;
}
BEGINmodInit()
CODESTARTmodInit
+SCOPINGmodInit
*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
CODEmodInit_QueryRegCFSLineHdlr
CHKiRet(objUse(errmsg, CORE_COMPONENT));
@@ -697,9 +706,9 @@ CODEmodInit_QueryRegCFSLineHdlr
CHKiRet(objUse(gssutil, LM_GSSUTIL_FILENAME));
CHKiRet(objUse(tcpclt, LM_TCPCLT_FILENAME));
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"gssforwardservicename", 0, eCmdHdlrGetWord, NULL, &gss_base_service_name, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"gssmode", 0, eCmdHdlrGetWord, setGSSMode, &gss_mode, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"actiongssforwarddefaulttemplate", 0, eCmdHdlrGetWord, NULL, &pszTplName, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"gssforwardservicename", 0, eCmdHdlrGetWord, NULL, &cs.gss_base_service_name, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"gssmode", 0, eCmdHdlrGetWord, setGSSMode, &cs.gss_mode, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"actiongssforwarddefaulttemplate", 0, eCmdHdlrGetWord, NULL, &cs.pszTplName, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
ENDmodInit
diff --git a/plugins/omhdfs/javaenv.sh b/plugins/omhdfs/javaenv.sh
new file mode 100644
index 00000000..d07a8473
--- /dev/null
+++ b/plugins/omhdfs/javaenv.sh
@@ -0,0 +1,14 @@
+# This is a sample file for environment settings on Fedora 13
+# that made me compile & run omhdfs. I really *hate* the way
+# java uses environment variables... Hopefully this file will
+# help building and testing omhdfs in the future (there is also
+# some more information in the rsyslog wiki).
+# rgerhards, 2011-03-11
+# this now works, but don't ask my why ;)
+#export JAVA_HOME=/usr/java/jdk1.6.0_21/bin/java
+export PATH=/usr/java/jdk1.6.0_21/bin:$PATH
+export JAVA_INCLUDES="-I/usr/java/jdk1.6.0_21/include -I/usr/java/jdk1.6.0_21/include/linux"
+export JAVA_LIBS="-L/usr/java/jdk1.6.0_21/jre/lib/i386 -ljava -ljvm -lverify"
+export HADOOP_HOME=/usr/lib/hadoop
+export CLASSPATH=/usr/lib/jvm/java-6-sun/lib:/usr/lib/hadoop/lib:/usr/lib/hadoop/hadoop-ant-0.20.2+320.jar:/usr/lib/hadoop/hadoop-core-0.20.2+320.jar:/usr/lib/hadoop/hadoop-examples-0.20.2+320.jar:/usr/lib/hadoop/hadoop-test-0.20.2+320.jar:/usr/lib/hadoop/hadoop-tools-0.20.2+320.jar/usr/lib/hadoop/lib/commons-cli-1.2.jar:/usr/lib/hadoop/lib/commons-codec-1.3.jar:/usr/lib/hadoop/lib/commons-el-1.0.jar:/usr/lib/hadoop/lib/commons-httpclient-3.0.1.jar:/usr/lib/hadoop/lib/commons-logging-1.0.4.jar:/usr/lib/hadoop/lib/commons-logging-api-1.0.4.jar:/usr/lib/hadoop/lib/commons-net-1.4.1.jar:/usr/lib/hadoop/lib/core-3.1.1.jar:/usr/lib/hadoop/lib/hadoop-fairscheduler-0.20.2+320.jar:/usr/lib/hadoop/lib/hadoop-scribe-log4j-0.20.2+320.jar:/usr/lib/hadoop/lib/hsqldb-1.8.0.10.jar:/usr/lib/hadoop/lib/hsqldb.jar:/usr/lib/hadoop/lib/jackson-core-asl-1.0.1.jar:/usr/lib/hadoop/lib/jackson-mapper-asl-1.0.1.jar:/usr/lib/hadoop/lib/jasper-compiler-5.5.12.jar:/usr/lib/hadoop/lib/jasper-runtime-5.5.12.jar:/usr/lib/hadoop/lib/jets3t-0.6.1.jar:/usr/lib/hadoop/lib/jetty-6.1.14.jar:/usr/lib/hadoop/lib/jetty-util-6.1.14.jar:/usr/lib/hadoop/lib/junit-4.5.jar:/usr/lib/hadoop/lib/kfs-0.2.2.jar:/usr/lib/hadoop/lib/libfb303.jar:/usr/lib/hadoop/lib/libthrift.jar:/usr/lib/hadoop/lib/log4j-1.2.15.jar:/usr/lib/hadoop/lib/mockito-all-1.8.2.jar:/usr/lib/hadoop/lib/mysql-connector-java-5.0.8-bin.jar:/usr/lib/hadoop/lib/oro-2.0.8.jar:/usr/lib/hadoop/lib/servlet-api-2.5-6.1.14.jar:/usr/lib/hadoop/lib/slf4j-api-1.4.3.jar:/usr/lib/hadoop/lib/slf4j-log4j12-1.4.3.jar:/usr/lib/hadoop/lib/xmlenc-0.52.jar:/etc/hadoop/conf
+###export CLASSPATH="/usr/lib/hadoop/hadoop-0.20.2+320-ant.jar: /usr/lib/hadoop/hadoop-0.20.2+320-core.jar: /usr/lib/hadoop/hadoop-0.20.2+320-examples.jar: /usr/lib/hadoop/hadoop-0.20.2+320-test.jar: /usr/lib/hadoop/hadoop-0.20.2+320-tools.jar: /usr/lib/hadoop/hadoop-ant-0.20.2+320.jar: /usr/lib/hadoop/hadoop-core-0.20.2+320.jar: /usr/lib/hadoop/hadoop-examples-0.20.2+320.jar: /usr/lib/hadoop/hadoop-test-0.20.2+320.jar: /usr/lib/hadoop/hadoop-tools-0.20.2+320.jar:/usr/lib/hadoop/lib: /usr/lib/hadoop/lib/commons-cli-1.2.jar: /usr/lib/hadoop/lib/commons-codec-1.3.jar: /usr/lib/hadoop/lib/commons-el-1.0.jar: /usr/lib/hadoop/lib/commons-httpclient-3.0.1.jar: /usr/lib/hadoop/lib/commons-logging-1.0.4.jar: /usr/lib/hadoop/lib/commons-logging-api-1.0.4.jar: /usr/lib/hadoop/lib/commons-net-1.4.1.jar: /usr/lib/hadoop/lib/core-3.1.1.jar: /usr/lib/hadoop/lib/hadoop-fairscheduler-0.20.2+320.jar: /usr/lib/hadoop/lib/hadoop-scribe-log4j-0.20.2+320.jar: /usr/lib/hadoop/lib/hsqldb-1.8.0.10.jar: /usr/lib/hadoop/lib/hsqldb.jar: /usr/lib/hadoop/lib/jackson-core-asl-1.0.1.jar: /usr/lib/hadoop/lib/jackson-mapper-asl-1.0.1.jar: /usr/lib/hadoop/lib/jasper-compiler-5.5.12.jar: /usr/lib/hadoop/lib/jasper-runtime-5.5.12.jar: /usr/lib/hadoop/lib/jets3t-0.6.1.jar: /usr/lib/hadoop/lib/jetty-6.1.14.jar: /usr/lib/hadoop/lib/jetty-util-6.1.14.jar: /usr/lib/hadoop/lib/junit-4.5.jar: /usr/lib/hadoop/lib/kfs-0.2.2.jar: /usr/lib/hadoop/lib/libfb303.jar: /usr/lib/hadoop/lib/libthrift.jar: /usr/lib/hadoop/lib/log4j-1.2.15.jar: /usr/lib/hadoop/lib/mockito-all-1.8.2.jar: /usr/lib/hadoop/lib/mysql-connector-java-5.0.8-bin.jar: /usr/lib/hadoop/lib/oro-2.0.8.jar: /usr/lib/hadoop/lib/servlet-api-2.5-6.1.14.jar: /usr/lib/hadoop/lib/slf4j-api-1.4.3.jar: /usr/lib/hadoop/lib/slf4j-log4j12-1.4.3.jar: /usr/lib/hadoop/lib/xmlenc-0.52.jar:/etc/hadoop/conf:/usr/lib/hadoop/lib"
diff --git a/plugins/omhdfs/omhdfs.c b/plugins/omhdfs/omhdfs.c
index 8b72747f..58b78a3d 100644
--- a/plugins/omhdfs/omhdfs.c
+++ b/plugins/omhdfs/omhdfs.c
@@ -60,12 +60,18 @@ DEFobjCurrIf(errmsg)
/* global data */
static struct hashtable *files; /* holds all file objects that we know */
-/* globals for default values */
-static uchar *fileName = NULL;
-static uchar *hdfsHost = NULL;
-static uchar *dfltTplName = NULL; /* default template name to use */
-int hdfsPort = 0;
-/* end globals for default values */
+typedef struct configSettings_s {
+ uchar *fileName;
+ uchar *hdfsHost;
+ uchar *dfltTplName; /* default template name to use */
+ int hdfsPort;
+} configSettings_t;
+
+SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */
+
+BEGINinitConfVars /* (re)set config variables to default values */
+CODESTARTinitConfVars
+ENDinitConfVars
typedef struct {
uchar *name;
@@ -80,6 +86,8 @@ typedef struct {
typedef struct _instanceData {
file_t *pFile;
+ uchar ioBuf[64*1024];
+ unsigned offsBuf;
} instanceData;
/* forward definitions (down here, need data types) */
@@ -260,7 +268,8 @@ fileOpen(file_t *pFile)
if(errno == ENOENT) {
DBGPRINTF("omhdfs: ENOENT trying to append to '%s', now trying create\n",
pFile->name);
- pFile->fh = hdfsOpenFile(pFile->fs, (char*)pFile->name, O_WRONLY|O_CREAT, 0, 0, 0);
+ pFile->fh = hdfsOpenFile(pFile->fs,
+ (char*)pFile->name, O_WRONLY|O_CREAT, 0, 0, 0);
}
}
if(pFile->fh == NULL) {
@@ -275,12 +284,15 @@ finalize_it:
}
+/* Note: lenWrite is reset to zero on successful write! */
static inline rsRetVal
-fileWrite(file_t *pFile, uchar *buf)
+fileWrite(file_t *pFile, uchar *buf, size_t *lenWrite)
{
- size_t lenWrite;
DEFiRet;
+ if(*lenWrite == 0)
+ FINALIZE;
+
if(pFile->nUsers > 1)
d_pthread_mutex_lock(&pFile->mut);
@@ -294,18 +306,18 @@ fileWrite(file_t *pFile, uchar *buf)
}
}
- lenWrite = strlen((char*) buf);
- tSize num_written_bytes = hdfsWrite(pFile->fs, pFile->fh, buf, lenWrite);
- if((unsigned) num_written_bytes != lenWrite) {
- errmsg.LogError(errno, RS_RET_ERR_HDFS_WRITE, "omhdfs: failed to write %s, expected %lu bytes, "
- "written %lu\n", pFile->name, (unsigned long) lenWrite,
+dbgprintf("XXXXX: omhdfs writing %u bytes\n", *lenWrite);
+ tSize num_written_bytes = hdfsWrite(pFile->fs, pFile->fh, buf, *lenWrite);
+ if((unsigned) num_written_bytes != *lenWrite) {
+ errmsg.LogError(errno, RS_RET_ERR_HDFS_WRITE,
+ "omhdfs: failed to write %s, expected %lu bytes, "
+ "written %lu\n", pFile->name, (unsigned long) *lenWrite,
(unsigned long) num_written_bytes);
ABORT_FINALIZE(RS_RET_SUSPENDED);
}
+ *lenWrite = 0;
finalize_it:
- if(pFile->nUsers > 1)
- d_pthread_mutex_unlock(&pFile->mut);
RETiRet;
}
@@ -333,6 +345,40 @@ finalize_it:
/* ---END FILE OBJECT---------------------------------------------------- */
+/* This adds data to the output buffer and performs an actual write
+ * if the new data does not fit into the buffer. Note that we never write
+ * partial data records. Other actions may write into the same file, and if
+ * we would write partial records, data could become severely mixed up.
+ * Note that we must check of some new data arrived is large than our
+ * buffer. In that case, the new data will written with its own
+ * write operation.
+ */
+static inline rsRetVal
+addData(instanceData *pData, uchar *buf)
+{
+ unsigned len;
+ DEFiRet;
+
+ len = strlen((char*)buf);
+ if(pData->offsBuf + len < sizeof(pData->ioBuf)) {
+ /* new data fits into remaining buffer */
+ memcpy((char*) pData->ioBuf + pData->offsBuf, buf, len);
+ pData->offsBuf += len;
+ } else {
+dbgprintf("XXXXX: not enough room, need to flush\n");
+ CHKiRet(fileWrite(pData->pFile, pData->ioBuf, &pData->offsBuf));
+ if(len >= sizeof(pData->ioBuf)) {
+ CHKiRet(fileWrite(pData->pFile, buf, &len));
+ } else {
+ memcpy((char*) pData->ioBuf + pData->offsBuf, buf, len);
+ pData->offsBuf += len;
+ }
+ }
+
+ iRet = RS_RET_DEFER_COMMIT;
+finalize_it:
+ RETiRet;
+}
BEGINcreateInstance
CODESTARTcreateInstance
@@ -358,13 +404,31 @@ CODESTARTtryResume
}
ENDtryResume
+
+BEGINbeginTransaction
+CODESTARTbeginTransaction
+dbgprintf("omhdfs: beginTransaction\n");
+ENDbeginTransaction
+
+
BEGINdoAction
CODESTARTdoAction
- DBGPRINTF("omuxsock: action to to write to %s\n", pData->pFile->name);
- iRet = fileWrite(pData->pFile, ppString[0]);
+ DBGPRINTF("omhdfs: action to to write to %s\n", pData->pFile->name);
+ iRet = addData(pData, ppString[0]);
+dbgprintf("omhdfs: done doAction\n");
ENDdoAction
+BEGINendTransaction
+CODESTARTendTransaction
+dbgprintf("omhdfs: endTransaction\n");
+ if(pData->offsBuf != 0) {
+ DBGPRINTF("omhdfs: data unwritten at end of transaction, persisting...\n");
+ iRet = fileWrite(pData->pFile, pData->ioBuf, &pData->offsBuf);
+ }
+ENDendTransaction
+
+
BEGINparseSelectorAct
file_t *pFile;
int r;
@@ -381,22 +445,22 @@ CODESTARTparseSelectorAct
CHKiRet(createInstance(&pData));
CODE_STD_STRING_REQUESTparseSelectorAct(1)
CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, 0,
- (dfltTplName == NULL) ? (uchar*)"RSYSLOG_FileFormat" : dfltTplName));
+ (cs.dfltTplName == NULL) ? (uchar*)"RSYSLOG_FileFormat" : cs.dfltTplName));
- if(fileName == NULL) {
+ if(cs.fileName == NULL) {
errmsg.LogError(0, RS_RET_ERR_HDFS_OPEN, "omhdfs: no file name specified, can not continue");
ABORT_FINALIZE(RS_RET_FILE_NOT_SPECIFIED);
}
- pFile = hashtable_search(files, fileName);
+ pFile = hashtable_search(files, cs.fileName);
if(pFile == NULL) {
/* we need a new file object, this one not seen before */
CHKiRet(fileObjConstruct(&pFile));
- CHKmalloc(pFile->name = fileName);
- CHKmalloc(keybuf = ustrdup(fileName));
- fileName = NULL; /* re-set, data passed to file object */
- CHKmalloc(pFile->hdfsHost = strdup((hdfsHost == NULL) ? "default" : (char*) hdfsHost));
- pFile->hdfsPort = hdfsPort;
+ CHKmalloc(pFile->name = cs.fileName);
+ CHKmalloc(keybuf = ustrdup(cs.fileName));
+ cs.fileName = NULL; /* re-set, data passed to file object */
+ CHKmalloc(pFile->hdfsHost = strdup((cs.hdfsHost == NULL) ? "default" : (char*) cs.hdfsHost));
+ pFile->hdfsPort = cs.hdfsPort;
fileOpen(pFile);
if(pFile->fh == NULL){
errmsg.LogError(0, RS_RET_ERR_HDFS_OPEN, "omhdfs: failed to open %s - "
@@ -409,6 +473,7 @@ CODESTARTparseSelectorAct
}
fileObjAddUser(pFile);
pData->pFile = pFile;
+ pData->offsBuf = 0;
CODE_STD_FINALIZERparseSelectorAct
ENDparseSelectorAct
@@ -438,8 +503,12 @@ ENDdoHUP
*/
static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
{
- hdfsHost = NULL;
- hdfsPort = 0;
+ cs.hdfsHost = NULL;
+ cs.hdfsPort = 0;
+ free(cs.fileName);
+ cs.fileName = NULL;
+ free(cs.dfltTplName);
+ cs.dfltTplName = NULL;
return RS_RET_OK;
}
@@ -455,10 +524,12 @@ ENDmodExit
BEGINqueryEtryPt
CODESTARTqueryEtryPt
CODEqueryEtryPt_STD_OMOD_QUERIES
+CODEqueryEtryPt_TXIF_OMOD_QUERIES /* we support the transactional interface! */
CODEqueryEtryPt_doHUP
ENDqueryEtryPt
+
BEGINmodInit()
CODESTARTmodInit
*ipIFVersProvided = CURR_MOD_IF_VERSION;
@@ -467,10 +538,11 @@ CODEmodInit_QueryRegCFSLineHdlr
CHKmalloc(files = create_hashtable(20, hash_from_string, key_equals_string,
fileObjDestruct4Hashtable));
- CHKiRet(regCfSysLineHdlr((uchar *)"omhdfsfilename", 0, eCmdHdlrGetWord, NULL, &fileName, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"omhdfshost", 0, eCmdHdlrGetWord, NULL, &hdfsHost, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"omhdfsport", 0, eCmdHdlrInt, NULL, &hdfsPort, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"omhdfsdefaulttemplate", 0, eCmdHdlrGetWord, NULL, &dfltTplName, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"omhdfsfilename", 0, eCmdHdlrGetWord, NULL, &cs.fileName, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"omhdfshost", 0, eCmdHdlrGetWord, NULL, &cs.hdfsHost, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"omhdfsport", 0, eCmdHdlrInt, NULL, &cs.hdfsPort, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"omhdfsdefaulttemplate", 0, eCmdHdlrGetWord, NULL, &cs.dfltTplName, NULL));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
+ DBGPRINTF("omhdfs: module compiled with rsyslog version %s.\n", VERSION);
CODEmodInit_QueryRegCFSLineHdlr
ENDmodInit
diff --git a/plugins/omlibdbi/omlibdbi.c b/plugins/omlibdbi/omlibdbi.c
index 4b97da86..2c67229b 100644
--- a/plugins/omlibdbi/omlibdbi.c
+++ b/plugins/omlibdbi/omlibdbi.c
@@ -68,14 +68,29 @@ typedef struct _instanceData {
unsigned uLastDBErrno; /* last errno returned by libdbi or 0 if all is well */
} instanceData;
+typedef struct configSettings_s {
+ uchar *dbiDrvrDir; /* global: where do the dbi drivers reside? */
+ uchar *drvrName; /* driver to use */
+ uchar *host; /* host to connect to */
+ uchar *usrName; /* user name for connect */
+ uchar *pwd; /* password for connect */
+ uchar *dbName; /* database to use */
+} configSettings_t;
+
+SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */
+
+BEGINinitConfVars /* (re)set config variables to default values */
+CODESTARTinitConfVars
+ cs.dbiDrvrDir = NULL;
+ cs.drvrName = NULL;
+ cs.host = NULL;
+ cs.usrName = NULL;
+ cs.pwd = NULL;
+ cs.dbName = NULL;
+ENDinitConfVars
+
/* config settings */
-static uchar *dbiDrvrDir = NULL;/* global: where do the dbi drivers reside? */
-static uchar *drvrName = NULL; /* driver to use */
-static uchar *host = NULL; /* host to connect to */
-static uchar *usrName = NULL; /* user name for connect */
-static uchar *pwd = NULL; /* password for connect */
-static uchar *dbName = NULL; /* database to use */
#ifdef HAVE_DBI_R
static dbi_inst dbiInst;
#endif
@@ -168,9 +183,9 @@ static rsRetVal initConn(instanceData *pData, int bSilent)
if(bDbiInitialized == 0) {
/* we need to init libdbi first */
# ifdef HAVE_DBI_R
- iDrvrsLoaded = dbi_initialize_r((char*) dbiDrvrDir, &dbiInst);
+ iDrvrsLoaded = dbi_initialize_r((char*) cs.dbiDrvrDir, &dbiInst);
# else
- iDrvrsLoaded = dbi_initialize((char*) dbiDrvrDir);
+ iDrvrsLoaded = dbi_initialize((char*) cs.dbiDrvrDir);
# endif
if(iDrvrsLoaded == 0) {
errmsg.LogError(0, RS_RET_SUSPENDED, "libdbi error: libdbi or libdbi drivers not present on this system - suspending.");
@@ -278,23 +293,23 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1)
CHKiRet(createInstance(&pData));
/* no create the instance based on what we currently have */
- if(drvrName == NULL) {
+ if(cs.drvrName == NULL) {
errmsg.LogError(0, RS_RET_NO_DRIVERNAME, "omlibdbi: no db driver name given - action can not be created");
ABORT_FINALIZE(RS_RET_NO_DRIVERNAME);
}
- if((pData->drvrName = (uchar*) strdup((char*)drvrName)) == NULL) ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
+ if((pData->drvrName = (uchar*) strdup((char*)cs.drvrName)) == NULL) ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
/* NULL values are supported because drivers have different needs.
* They will err out on connect. -- rgerhards, 2008-02-15
*/
- if(host != NULL)
- if((pData->host = (uchar*) strdup((char*)host)) == NULL) ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
- if(usrName != NULL)
- if((pData->usrName = (uchar*) strdup((char*)usrName)) == NULL) ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
- if(dbName != NULL)
- if((pData->dbName = (uchar*) strdup((char*)dbName)) == NULL) ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
- if(pwd != NULL)
- if((pData->pwd = (uchar*) strdup((char*)pwd)) == NULL) ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
+ if(cs.host != NULL)
+ if((pData->host = (uchar*) strdup((char*)cs.host)) == NULL) ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
+ if(cs.usrName != NULL)
+ if((pData->usrName = (uchar*) strdup((char*)cs.usrName)) == NULL) ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
+ if(cs.dbName != NULL)
+ if((pData->dbName = (uchar*) strdup((char*)cs.dbName)) == NULL) ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
+ if(cs.pwd != NULL)
+ if((pData->pwd = (uchar*) strdup((char*)cs.pwd)) == NULL) ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_RQD_TPL_OPT_SQL, (uchar*) " StdDBFmt"));
@@ -326,53 +341,35 @@ ENDqueryEtryPt
static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
{
DEFiRet;
-
- if(dbiDrvrDir != NULL) {
- free(dbiDrvrDir);
- dbiDrvrDir = NULL;
- }
-
- if(drvrName != NULL) {
- free(drvrName);
- drvrName = NULL;
- }
-
- if(host != NULL) {
- free(host);
- host = NULL;
- }
-
- if(usrName != NULL) {
- free(usrName);
- usrName = NULL;
- }
-
- if(pwd != NULL) {
- free(pwd);
- pwd = NULL;
- }
-
- if(dbName != NULL) {
- free(dbName);
- dbName = NULL;
- }
-
+ free(cs.dbiDrvrDir);
+ cs.dbiDrvrDir = NULL;
+ free(cs.drvrName);
+ cs.drvrName = NULL;
+ free(cs.host);
+ cs.host = NULL;
+ free(cs.usrName);
+ cs.usrName = NULL;
+ free(cs.pwd);
+ cs.pwd = NULL;
+ free(cs.dbName);
+ cs.dbName = NULL;
RETiRet;
}
BEGINmodInit()
CODESTARTmodInit
+SCOPINGmodInit
*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
CODEmodInit_QueryRegCFSLineHdlr
CHKiRet(objUse(errmsg, CORE_COMPONENT));
- CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionlibdbidriverdirectory", 0, eCmdHdlrGetWord, NULL, &dbiDrvrDir, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionlibdbidriver", 0, eCmdHdlrGetWord, NULL, &drvrName, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionlibdbihost", 0, eCmdHdlrGetWord, NULL, &host, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionlibdbiusername", 0, eCmdHdlrGetWord, NULL, &usrName, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionlibdbipassword", 0, eCmdHdlrGetWord, NULL, &pwd, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionlibdbidbname", 0, eCmdHdlrGetWord, NULL, &dbName, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr( (uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionlibdbidriverdirectory", 0, eCmdHdlrGetWord, NULL, &cs.dbiDrvrDir, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionlibdbidriver", 0, eCmdHdlrGetWord, NULL, &cs.drvrName, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionlibdbihost", 0, eCmdHdlrGetWord, NULL, &cs.host, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionlibdbiusername", 0, eCmdHdlrGetWord, NULL, &cs.usrName, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionlibdbipassword", 0, eCmdHdlrGetWord, NULL, &cs.pwd, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionlibdbidbname", 0, eCmdHdlrGetWord, NULL, &cs.dbName, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
DBGPRINTF("omlibdbi compiled with version %s loaded, libdbi version %s\n", VERSION, dbi_version());
ENDmodInit
diff --git a/plugins/ommail/ommail.c b/plugins/ommail/ommail.c
index 468d8db2..05cc96d5 100644
--- a/plugins/ommail/ommail.c
+++ b/plugins/ommail/ommail.c
@@ -70,12 +70,6 @@ struct toRcpt_s {
uchar *pszTo;
toRcpt_t *pNext;
};
-static toRcpt_t *lstRcpt = NULL;
-static uchar *pszSrv = NULL;
-static uchar *pszSrvPort = NULL;
-static uchar *pszFrom = NULL;
-static uchar *pszSubject = NULL;
-static int bEnableBody = 1; /* should a mail body be generated? (set to 0 eg for SMS gateways) */
typedef struct _instanceData {
int iMode; /* 0 - smtp, 1 - sendmail */
@@ -95,6 +89,27 @@ typedef struct _instanceData {
} md; /* mode-specific data */
} instanceData;
+typedef struct configSettings_s {
+ toRcpt_t *lstRcpt;
+ uchar *pszSrv;
+ uchar *pszSrvPort;
+ uchar *pszFrom;
+ uchar *pszSubject;
+ int bEnableBody; /* should a mail body be generated? (set to 0 eg for SMS gateways) */
+} configSettings_t;
+
+SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */
+
+BEGINinitConfVars /* (re)set config variables to default values */
+CODESTARTinitConfVars
+ cs.lstRcpt = NULL;
+ cs.pszSrv = NULL;
+ cs.pszSrvPort = NULL;
+ cs.pszFrom = NULL;
+ cs.pszSubject = NULL;
+ cs.bEnableBody = 1; /* should a mail body be generated? (set to 0 eg for SMS gateways) */
+ENDinitConfVars
+
/* forward definitions (as few as possible) */
static rsRetVal Send(int sock, char *msg, size_t len);
static rsRetVal readResponse(instanceData *pData, int *piState, int iExpected);
@@ -128,8 +143,8 @@ addRcpt(void __attribute__((unused)) *pVal, uchar *pNewVal)
CHKmalloc(pNew = calloc(1, sizeof(toRcpt_t)));
pNew->pszTo = pNewVal;
- pNew->pNext = lstRcpt;
- lstRcpt = pNew;
+ pNew->pNext = cs.lstRcpt;
+ cs.lstRcpt = pNew;
dbgprintf("ommail::addRcpt adds recipient %s\n", pNewVal);
@@ -608,32 +623,32 @@ CODESTARTparseSelectorAct
/* TODO: check strdup() result */
- if(pszFrom == NULL) {
+ if(cs.pszFrom == NULL) {
errmsg.LogError(0, RS_RET_MAIL_NO_FROM, "no sender address given - specify $ActionMailFrom");
ABORT_FINALIZE(RS_RET_MAIL_NO_FROM);
}
- if(lstRcpt == NULL) {
+ if(cs.lstRcpt == NULL) {
errmsg.LogError(0, RS_RET_MAIL_NO_TO, "no recipient address given - specify $ActionMailTo");
ABORT_FINALIZE(RS_RET_MAIL_NO_TO);
}
- pData->md.smtp.pszFrom = (uchar*) strdup((char*)pszFrom);
- pData->md.smtp.lstRcpt = lstRcpt; /* we "hand over" this memory */
- lstRcpt = NULL; /* note: this is different from pre-3.21.2 versions! */
+ pData->md.smtp.pszFrom = (uchar*) strdup((char*)cs.pszFrom);
+ pData->md.smtp.lstRcpt = cs.lstRcpt; /* we "hand over" this memory */
+ cs.lstRcpt = NULL; /* note: this is different from pre-3.21.2 versions! */
- if(pszSubject == NULL) {
+ if(cs.pszSubject == NULL) {
/* if no subject is configured, we need just one template string */
CODE_STD_STRING_REQUESTparseSelectorAct(1)
} else {
CODE_STD_STRING_REQUESTparseSelectorAct(2)
pData->bHaveSubject = 1;
- CHKiRet(OMSRsetEntry(*ppOMSR, 1, (uchar*)strdup((char*) pszSubject), OMSR_NO_RQD_TPL_OPTS));
+ CHKiRet(OMSRsetEntry(*ppOMSR, 1, (uchar*)strdup((char*) cs.pszSubject), OMSR_NO_RQD_TPL_OPTS));
}
- if(pszSrv != NULL)
- pData->md.smtp.pszSrv = (uchar*) strdup((char*)pszSrv);
- if(pszSrvPort != NULL)
- pData->md.smtp.pszSrvPort = (uchar*) strdup((char*)pszSrvPort);
- pData->bEnableBody = bEnableBody;
+ if(cs.pszSrv != NULL)
+ pData->md.smtp.pszSrv = (uchar*) strdup((char*)cs.pszSrv);
+ if(cs.pszSrvPort != NULL)
+ pData->md.smtp.pszSrvPort = (uchar*) strdup((char*)cs.pszSrvPort);
+ pData->bEnableBody = cs.bEnableBody;
/* process template */
CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, (uchar*) "RSYSLOG_FileFormat"));
@@ -646,20 +661,14 @@ static rsRetVal freeConfigVariables(void)
{
DEFiRet;
- if(pszSrv != NULL) {
- free(pszSrv);
- pszSrv = NULL;
- }
- if(pszSrvPort != NULL) {
- free(pszSrvPort);
- pszSrvPort = NULL;
- }
- if(pszFrom != NULL) {
- free(pszFrom);
- pszFrom = NULL;
- }
- lstRcptDestruct(lstRcpt);
- lstRcpt = NULL;
+ free(cs.pszSrv);
+ cs.pszSrv = NULL;
+ free(cs.pszSrvPort);
+ cs.pszSrvPort = NULL;
+ free(cs.pszFrom);
+ cs.pszFrom = NULL;
+ lstRcptDestruct(cs.lstRcpt);
+ cs.lstRcpt = NULL;
RETiRet;
}
@@ -688,7 +697,7 @@ ENDqueryEtryPt
static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
{
DEFiRet;
- bEnableBody = 1;
+ cs.bEnableBody = 1;
iRet = freeConfigVariables();
RETiRet;
}
@@ -696,6 +705,7 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a
BEGINmodInit()
CODESTARTmodInit
+SCOPINGmodInit
*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
CODEmodInit_QueryRegCFSLineHdlr
/* tell which objects we need */
@@ -705,12 +715,12 @@ CODEmodInit_QueryRegCFSLineHdlr
dbgprintf("ommail version %s initializing\n", VERSION);
- CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionmailsmtpserver", 0, eCmdHdlrGetWord, NULL, &pszSrv, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionmailsmtpport", 0, eCmdHdlrGetWord, NULL, &pszSrvPort, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionmailfrom", 0, eCmdHdlrGetWord, NULL, &pszFrom, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionmailsmtpserver", 0, eCmdHdlrGetWord, NULL, &cs.pszSrv, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionmailsmtpport", 0, eCmdHdlrGetWord, NULL, &cs.pszSrvPort, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionmailfrom", 0, eCmdHdlrGetWord, NULL, &cs.pszFrom, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionmailto", 0, eCmdHdlrGetWord, addRcpt, NULL, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionmailsubject", 0, eCmdHdlrGetWord, NULL, &pszSubject, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionmailenablebody", 0, eCmdHdlrBinary, NULL, &bEnableBody, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionmailsubject", 0, eCmdHdlrGetWord, NULL, &cs.pszSubject, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionmailenablebody", 0, eCmdHdlrBinary, NULL, &cs.bEnableBody, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr( (uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
ENDmodInit
diff --git a/plugins/ommongodb/Makefile.am b/plugins/ommongodb/Makefile.am
new file mode 100644
index 00000000..1b0e23a1
--- /dev/null
+++ b/plugins/ommongodb/Makefile.am
@@ -0,0 +1,11 @@
+mongodir = ./mongo-c-driver/src
+pkglib_LTLIBRARIES = ommongodb.la
+
+ommongodb_la_SOURCES = ommongodb.c
+ommongodb_la_SOURCES += $(mongodir)/bson.c $(mongodir)/mongo.c $(mongodir)/md5.c $(mongodir)/numbers.c
+
+ommongodb_la_CPPFLAGS = -DMONGO_HAVE_STDINT -Imongo-c-driver/src $(RSRT_CFLAGS) $(PTHREADS_CFLAGS)
+ommongodb_la_LDFLAGS = -module -avoid-version
+ommongodb_la_LIBADD =
+
+EXTRA_DIST =
diff --git a/plugins/ommongodb/README b/plugins/ommongodb/README
new file mode 100644
index 00000000..cea3f3bc
--- /dev/null
+++ b/plugins/ommongodb/README
@@ -0,0 +1,23 @@
+plugin to use MongoDB as backend.
+
+tested in ubuntu 10.04 and ubuntu 10.10
+
+configuration:
+
+in your /etc/rsyslog.conf, together with other modules:
+$ModLoad ommongodb # provides mongodb support
+
+then in your /etc/rsyslog.d (check your distribution way to organize the configuration..) you create a file 10-mongodb.conf with the following content:
+
+#the format for the driver is :ommongodb:ip:db:collection;StdMongoDBFmt
+#if you want to change what is logged in the db, the template, you must change the source code since the keys are hardcoded
+$template StdMongoDBFmt,"%msg%%syslogfacility%%HOSTNAME%%syslogpriority%"
+*.* :ommongodb:127.0.0.1,syslog,logs;StdMongoDBFmt
+
+
+TODO
+we must ensure that the collection is a capped collection
+refactor my code :-)
+
+email Victor Pereira <victor.pereira@bigrails.com>
+twitter twitter.com/vpereira
diff --git a/plugins/ommongodb/ommongodb.c b/plugins/ommongodb/ommongodb.c
new file mode 100644
index 00000000..8e19105f
--- /dev/null
+++ b/plugins/ommongodb/ommongodb.c
@@ -0,0 +1,280 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <assert.h>
+#include <signal.h>
+#include <time.h>
+#include "bson.h"
+#include "mongo.h"
+#include "config.h"
+#include "rsyslog.h"
+#include "conf.h"
+#include "syslogd-types.h"
+#include "srUtils.h"
+#include "template.h"
+#include "module-template.h"
+#include "errmsg.h"
+#include "cfsysline.h"
+#include "mongo-c-driver/src/mongo.h"
+
+#define countof(X) ( (size_t) ( sizeof(X)/sizeof*(X) ) )
+
+#define DEFAULT_SERVER "127.0.0.1"
+#define DEFAULT_DATABASE "syslog"
+#define DEFAULT_COLLECTION "log"
+#define DEFAULT_DB_COLLECTION "syslog.log"
+
+//i just defined some constants, i couldt not find the limit
+#define MONGO_DB_NAME_SIZE 128
+#define MONGO_COLLECTION_NAME_SIZE 128
+
+MODULE_TYPE_OUTPUT
+/* internal structures
+ */
+DEF_OMOD_STATIC_DATA
+DEFobjCurrIf(errmsg)
+
+typedef struct _instanceData {
+ mongo_connection conn[1]; /* ptr */
+ mongo_connection_options opts[1];
+ mongo_conn_return status;
+ char db[MONGO_DB_NAME_SIZE];
+ char collection[MONGO_COLLECTION_NAME_SIZE];
+ char dbcollection[MONGO_DB_NAME_SIZE + MONGO_COLLECTION_NAME_SIZE + 1];
+ unsigned uLastMongoDBErrno;
+ //unsigned iSrvPort; /* sample: server port */
+} instanceData;
+
+char db[_DB_MAXDBLEN+2];
+static int iSrvPort = 27017;
+BEGINcreateInstance
+CODESTARTcreateInstance
+ENDcreateInstance
+
+
+BEGINisCompatibleWithFeature
+CODESTARTisCompatibleWithFeature
+ /* use this to specify if select features are supported by this
+ * plugin. If not, the framework will handle that. Currently, only
+ * RepeatedMsgReduction ("last message repeated n times") is optional.
+ */
+ if(eFeat == sFEATURERepeatedMsgReduction)
+ iRet = RS_RET_OK;
+ENDisCompatibleWithFeature
+
+static void closeMongoDB(instanceData *pData)
+{
+ ASSERT(pData != NULL);
+
+ if(pData->conn != NULL) {
+ mongo_destroy( pData->conn );
+ memset(pData->conn,0x00,sizeof(mongo_connection));
+ }
+}
+
+BEGINfreeInstance
+CODESTARTfreeInstance
+ closeMongoDB(pData);
+ENDfreeInstance
+
+BEGINdbgPrintInstInfo
+CODESTARTdbgPrintInstInfo
+ /* nothing special here */
+ENDdbgPrintInstInfo
+
+/* log a database error with descriptive message.
+ * We check if we have a valid MongoDB handle. If not, we simply
+ * report an error
+ */
+static void reportDBError(instanceData *pData, int bSilent)
+{
+ char errMsg[512];
+ bson ErrObj;
+
+ ASSERT(pData != NULL);
+
+ /* output log message */
+ errno = 0;
+ if(pData->conn == NULL) {
+ errmsg.LogError(0, NO_ERRCODE, "unknown DB error occured - could not obtain MongoDB handle");
+ } else { /* we can ask mysql for the error description... */
+ //we should handle the error. if bSilent is set then we should print as debug
+ mongo_cmd_get_last_error(pData->conn, pData->db, &ErrObj);
+ bson_destroy(&ErrObj);
+ }
+
+ return;
+}
+
+/* The following function is responsible for initializing a
+ * MySQL connection.
+ * Initially added 2004-10-28 mmeckelein
+ */
+static rsRetVal initMongoDB(instanceData *pData, int bSilent)
+{
+ DEFiRet;
+
+ ASSERT(pData != NULL);
+ ASSERT(pData->conn == NULL);
+
+ //I'm trying to fallback to a default here
+ if(pData->opts->port == 0)
+ pData->opts->port = 27017;
+
+ if(pData->opts->host == 0x00)
+ strcpy(pData->opts->host,DEFAULT_SERVER);
+
+ if(pData->dbcollection == 0x00)
+ strcpy(pData->dbcollection,DEFAULT_DB_COLLECTION);
+
+ pData->status = mongo_connect(pData->conn, pData->opts );
+
+ switch (pData->status) {
+ case mongo_conn_success:
+ fprintf(stderr, "connection succeeded\n" );
+ iRet = RS_RET_OK;
+ break;
+ case mongo_conn_bad_arg:
+ errmsg.LogError(0, RS_RET_SUSPENDED, "can not initialize MongoDB handle");
+ fprintf(stderr, "bad arguments\n" );
+ iRet = RS_RET_SUSPENDED;
+ break;
+ case mongo_conn_no_socket:
+ errmsg.LogError(0, RS_RET_SUSPENDED, "can not initialize MongoDB handle");
+ fprintf(stderr, "no socket\n" );
+ iRet = RS_RET_SUSPENDED;
+ break;
+ case mongo_conn_fail:
+ errmsg.LogError(0, RS_RET_SUSPENDED, "can not initialize MongoDB handle");
+ fprintf(stderr, "connection failed\n" );
+ iRet = RS_RET_SUSPENDED;
+ break;
+ case mongo_conn_not_master:
+ errmsg.LogError(0, RS_RET_SUSPENDED, "can not initialize MongoDB handle");
+ fprintf(stderr, "not master\n" );
+ iRet = RS_RET_SUSPENDED;
+ break;
+ }
+ RETiRet;
+}
+
+//we must implement it
+rsRetVal writeMongoDB(uchar *psz, instanceData *pData)
+{
+ char mydate[32];
+ char **szParams;
+ bson b[1];
+ bson_buffer buf[1];
+ bson_buffer_init( buf );
+ bson_append_new_oid(buf, "_id" );
+ memset(mydate,0x00,32);
+
+
+ DEFiRet;
+
+ ASSERT(psz != NULL);
+ ASSERT(pData != NULL);
+
+
+ /* see if we are ready to proceed */
+ if(pData->conn == NULL) {
+ CHKiRet(initMongoDB(pData, 0));
+ }
+
+szParams = (char**)(void*) psz;
+//We can make it beter
+//if you change the fields in your template, we must update it here
+//there is any C_metaprogramming_ninja there? :-)
+if(countof(szParams) > 0)
+{
+ bson_append_string( buf, "msg", szParams[0]);
+ bson_append_string( buf, "facility",szParams[1]);
+ bson_append_string( buf, "hostname", szParams[2] );
+ bson_append_string(buf, "priority",szParams[3]);
+ bson_append_int(buf,"count",countof(szParams));
+ bson_from_buffer( b, buf );
+ mongo_insert(pData->conn, pData->dbcollection, b );
+}
+
+if(b)
+ bson_destroy(b);
+
+
+ finalize_it:
+ if(iRet == RS_RET_OK) {
+ pData->uLastMongoDBErrno = 0; /* reset error for error supression */
+ }
+
+
+ RETiRet;
+}
+
+BEGINtryResume
+CODESTARTtryResume
+ if(pData->conn == NULL) {
+ iRet = initMongoDB(pData, 1);
+ }
+ENDtryResume
+
+BEGINdoAction
+CODESTARTdoAction
+ iRet = writeMongoDB(ppString[0], pData);
+ENDdoAction
+
+BEGINparseSelectorAct
+ //int iMongoDBPropErr = 0;
+CODESTARTparseSelectorAct
+CODE_STD_STRING_REQUESTparseSelectorAct(1)
+
+ if(!strncmp((char*) p, ":ommongodb:", sizeof(":ommongodb:") - 1)) {
+ p += sizeof(":ommongodb:") - 1; /* eat indicator sequence (-1 because of '\0'!) */
+ } else {
+ ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED);
+ }
+
+ CHKiRet(createInstance(&pData));
+
+ if(getSubString(&p, pData->opts->host, MAXHOSTNAMELEN+1, ','))
+ strcpy(pData->opts->host,DEFAULT_SERVER);
+
+ //we must define the max db name
+ if(getSubString(&p,pData->db,255,','))
+ strcpy(pData->db,DEFAULT_DATABASE);
+ if(getSubString(&p,pData->collection,255,';'))
+ strcpy(pData->collection,DEFAULT_COLLECTION);
+ if(*(p-1) == ';')
+ --p;
+
+
+ CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_TPL_AS_ARRAY, (uchar*) " StdMongoDBFmt"));
+
+
+ pData->opts->port = (unsigned) iSrvPort; /* set configured port */
+ sprintf(pData->dbcollection,"%s.%s",pData->db,pData->collection);
+ CHKiRet(initMongoDB(pData, 0));
+
+CODE_STD_FINALIZERparseSelectorAct
+ENDparseSelectorAct
+
+
+BEGINmodExit
+CODESTARTmodExit
+ENDmodExit
+
+
+BEGINqueryEtryPt
+CODESTARTqueryEtryPt
+CODEqueryEtryPt_STD_OMOD_QUERIES
+ENDqueryEtryPt
+
+BEGINmodInit()
+CODESTARTmodInit
+ *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
+CODEmodInit_QueryRegCFSLineHdlr
+ CHKiRet(objUse(errmsg, CORE_COMPONENT));
+ INITChkCoreFeature(bCoreSupportsBatching, CORE_FEATURE_BATCHING);
+ DBGPRINTF("ompgsql: module compiled with rsyslog version %s.\n", VERSION);
+ DBGPRINTF("ompgsql: %susing transactional output interface.\n", bCoreSupportsBatching ? "" : "not ");
+ENDmodInit \ No newline at end of file
diff --git a/plugins/ommysql/ommysql.c b/plugins/ommysql/ommysql.c
index 7ff89f5a..79fd1b9e 100644
--- a/plugins/ommysql/ommysql.c
+++ b/plugins/ommysql/ommysql.c
@@ -46,27 +46,37 @@
MODULE_TYPE_OUTPUT
MODULE_TYPE_NOKEEP
+static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal);
+
/* internal structures
*/
DEF_OMOD_STATIC_DATA
DEFobjCurrIf(errmsg)
typedef struct _instanceData {
- MYSQL *f_hmysql; /* handle to MySQL */
+ MYSQL *f_hmysql; /* handle to MySQL */
char f_dbsrv[MAXHOSTNAMELEN+1]; /* IP or hostname of DB server*/
unsigned int f_dbsrvPort; /* port of MySQL server */
char f_dbname[_DB_MAXDBLEN+1]; /* DB name */
char f_dbuid[_DB_MAXUNAMELEN+1]; /* DB user */
char f_dbpwd[_DB_MAXPWDLEN+1]; /* DB user's password */
- unsigned uLastMySQLErrno; /* last errno returned by MySQL or 0 if all is well */
- uchar * f_configfile; /* MySQL Client Configuration File */
- uchar * f_configsection; /* MySQL Client Configuration Section */
+ unsigned uLastMySQLErrno; /* last errno returned by MySQL or 0 if all is well */
+ uchar * f_configfile; /* MySQL Client Configuration File */
+ uchar * f_configsection; /* MySQL Client Configuration Section */
} instanceData;
-/* config variables */
-static uchar * pszMySQLConfigFile = NULL; /* MySQL Client Configuration File */
-static uchar * pszMySQLConfigSection = NULL; /* MySQL Client Configuration Section */
-static int iSrvPort = 0; /* database server port */
+typedef struct configSettings_s {
+ int iSrvPort; /* database server port */
+ uchar *pszMySQLConfigFile; /* MySQL Client Configuration File */
+ uchar *pszMySQLConfigSection; /* MySQL Client Configuration Section */
+} configSettings_t;
+
+SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */
+
+BEGINinitConfVars /* (re)set config variables to default values */
+CODESTARTinitConfVars
+ resetConfigVariables(NULL, NULL);
+ENDinitConfVars
BEGINcreateInstance
@@ -306,9 +316,9 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1)
errmsg.LogError(0, RS_RET_INVALID_PARAMS, "Trouble with MySQL connection properties. -MySQL logging disabled");
ABORT_FINALIZE(RS_RET_INVALID_PARAMS);
} else {
- pData->f_dbsrvPort = (unsigned) iSrvPort; /* set configured port */
- pData->f_configfile = pszMySQLConfigFile;
- pData->f_configsection = pszMySQLConfigSection;
+ pData->f_dbsrvPort = (unsigned) cs.iSrvPort; /* set configured port */
+ pData->f_configfile = cs.pszMySQLConfigFile;
+ pData->f_configsection = cs.pszMySQLConfigSection;
pData->f_hmysql = NULL; /* initialize, but connect only on first message (important for queued mode!) */
}
@@ -337,16 +347,17 @@ ENDqueryEtryPt
static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
{
DEFiRet;
- iSrvPort = 0; /* zero is the default port */
- free(pszMySQLConfigFile);
- pszMySQLConfigFile = NULL;
- free(pszMySQLConfigSection);
- pszMySQLConfigSection = NULL;
+ cs.iSrvPort = 0; /* zero is the default port */
+ free(cs.pszMySQLConfigFile);
+ cs.pszMySQLConfigFile = NULL;
+ free(cs.pszMySQLConfigSection);
+ cs.pszMySQLConfigSection = NULL;
RETiRet;
}
BEGINmodInit()
CODESTARTmodInit
+SCOPINGmodInit
*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
CODEmodInit_QueryRegCFSLineHdlr
CHKiRet(objUse(errmsg, CORE_COMPONENT));
@@ -365,10 +376,10 @@ CODEmodInit_QueryRegCFSLineHdlr
}
/* register our config handlers */
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionommysqlserverport", 0, eCmdHdlrInt, NULL, &iSrvPort, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionommysqlserverport", 0, eCmdHdlrInt, NULL, &cs.iSrvPort, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"ommysqlconfigfile",0,eCmdHdlrGetWord,NULL,&cs.pszMySQLConfigFile,STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"ommysqlconfigsection",0,eCmdHdlrGetWord,NULL,&cs.pszMySQLConfigSection,STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"ommysqlconfigfile",0,eCmdHdlrGetWord,NULL,&pszMySQLConfigFile,STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"ommysqlconfigsection",0,eCmdHdlrGetWord,NULL,&pszMySQLConfigSection,STD_LOADABLE_MODULE_ID));
ENDmodInit
/* vi:set ai:
diff --git a/plugins/ompgsql/ompgsql.c b/plugins/ompgsql/ompgsql.c
index ea4b4b75..df9cc3fe 100644
--- a/plugins/ompgsql/ompgsql.c
+++ b/plugins/ompgsql/ompgsql.c
@@ -65,6 +65,16 @@ typedef struct _instanceData {
ConnStatusType eLastPgSQLStatus; /* last status from postgres */
} instanceData;
+typedef struct configSettings_s {
+ EMPTY_STRUCT
+} configSettings_t;
+
+SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */
+
+BEGINinitConfVars /* (re)set config variables to default values */
+CODESTARTinitConfVars
+ENDinitConfVars
+
static rsRetVal writePgSQL(uchar *psz, instanceData *pData);
@@ -357,6 +367,7 @@ ENDqueryEtryPt
BEGINmodInit()
CODESTARTmodInit
+SCOPINGmodInit
*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
CODEmodInit_QueryRegCFSLineHdlr
CHKiRet(objUse(errmsg, CORE_COMPONENT));
diff --git a/plugins/omprog/omprog.c b/plugins/omprog/omprog.c
index 12e94251..ae086a14 100644
--- a/plugins/omprog/omprog.c
+++ b/plugins/omprog/omprog.c
@@ -58,8 +58,18 @@ typedef struct _instanceData {
int bIsRunning; /* is binary currently running? 0-no, 1-yes */
} instanceData;
+typedef struct configSettings_s {
+ uchar *szBinary; /* name of binary to call */
+} configSettings_t;
+
+SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */
+
+BEGINinitConfVars /* (re)set config variables to default values */
+CODESTARTinitConfVars
+ cs.szBinary = NULL; /* name of binary to call */
+ENDinitConfVars
+
/* config settings */
-static uchar *szBinary = NULL; /* name of binary to call */
BEGINcreateInstance
CODESTARTcreateInstance
@@ -300,13 +310,13 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1)
p += sizeof(":omprog:") - 1; /* eat indicator sequence (-1 because of '\0'!) */
CHKiRet(createInstance(&pData));
- if(szBinary == NULL) {
+ if(cs.szBinary == NULL) {
errmsg.LogError(0, RS_RET_CONF_RQRD_PARAM_MISSING,
"no binary to execute specified");
ABORT_FINALIZE(RS_RET_CONF_RQRD_PARAM_MISSING);
}
- CHKmalloc(pData->szBinary = (uchar*) strdup((char*)szBinary));
+ CHKmalloc(pData->szBinary = (uchar*) strdup((char*)cs.szBinary));
/* check if a non-standard template is to be applied */
if(*(p-1) == ';')
--p;
@@ -317,10 +327,8 @@ ENDparseSelectorAct
BEGINmodExit
CODESTARTmodExit
- if(szBinary != NULL) {
- free(szBinary);
- szBinary = NULL;
- }
+ free(cs.szBinary);
+ cs.szBinary = NULL;
CHKiRet(objRelease(errmsg, CORE_COMPONENT));
finalize_it:
ENDmodExit
@@ -338,22 +346,19 @@ ENDqueryEtryPt
static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
{
DEFiRet;
-
- if(szBinary != NULL) {
- free(szBinary);
- szBinary = NULL;
- }
-
+ free(cs.szBinary);
+ cs.szBinary = NULL;
RETiRet;
}
BEGINmodInit()
CODESTARTmodInit
+SCOPINGmodInit
*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
CODEmodInit_QueryRegCFSLineHdlr
CHKiRet(objUse(errmsg, CORE_COMPONENT));
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionomprogbinary", 0, eCmdHdlrGetWord, NULL, &szBinary, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionomprogbinary", 0, eCmdHdlrGetWord, NULL, &cs.szBinary, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
CODEmodInit_QueryRegCFSLineHdlr
ENDmodInit
diff --git a/plugins/omrelp/omrelp.c b/plugins/omrelp/omrelp.c
index 95c15f5d..3411c6d1 100644
--- a/plugins/omrelp/omrelp.c
+++ b/plugins/omrelp/omrelp.c
@@ -64,6 +64,16 @@ typedef struct _instanceData {
relpClt_t *pRelpClt; /* relp client for this instance */
} instanceData;
+typedef struct configSettings_s {
+ EMPTY_STRUCT
+} configSettings_t;
+
+SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */
+
+BEGINinitConfVars /* (re)set config variables to default values */
+CODESTARTinitConfVars
+ENDinitConfVars
+
/* get the syslog forward port from selector_t. The passed in
* struct must be one that is setup for forwarding.
* rgerhards, 2007-06-28
@@ -336,6 +346,7 @@ ENDqueryEtryPt
BEGINmodInit()
CODESTARTmodInit
+SCOPINGmodInit
*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
CODEmodInit_QueryRegCFSLineHdlr
/* create our relp engine */
diff --git a/plugins/omruleset/omruleset.c b/plugins/omruleset/omruleset.c
index c439bd83..a31a778a 100644
--- a/plugins/omruleset/omruleset.c
+++ b/plugins/omruleset/omruleset.c
@@ -51,6 +51,8 @@
MODULE_TYPE_OUTPUT
MODULE_TYPE_NOKEEP
+static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal);
+
/* static data */
DEFobjCurrIf(ruleset);
DEFobjCurrIf(errmsg);
@@ -60,8 +62,6 @@ DEFobjCurrIf(errmsg);
DEF_OMOD_STATIC_DATA
/* config variables */
-ruleset_t *pRuleset = NULL; /* ruleset to enqueue message to (NULL = Default, not recommended) */
-uchar *pszRulesetName = NULL;
typedef struct _instanceData {
@@ -69,6 +69,18 @@ typedef struct _instanceData {
uchar *pszRulesetName; /* primarily for debugging/display purposes */
} instanceData;
+typedef struct configSettings_s {
+ ruleset_t *pRuleset; /* ruleset to enqueue message to (NULL = Default, not recommended) */
+ uchar *pszRulesetName;
+} configSettings_t;
+
+SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */
+
+BEGINinitConfVars /* (re)set config variables to default values */
+CODESTARTinitConfVars
+ resetConfigVariables(NULL, NULL);
+ENDinitConfVars
+
BEGINcreateInstance
CODESTARTcreateInstance
@@ -119,12 +131,12 @@ setRuleset(void __attribute__((unused)) *pVal, uchar *pszName)
rsRetVal localRet;
DEFiRet;
- localRet = ruleset.GetRuleset(&pRuleset, pszName);
+ localRet = ruleset.GetRuleset(&cs.pRuleset, pszName);
if(localRet == RS_RET_NOT_FOUND) {
errmsg.LogError(0, RS_RET_RULESET_NOT_FOUND, "error: ruleset '%s' not found - ignored", pszName);
}
CHKiRet(localRet);
- pszRulesetName = pszName; /* save for later display purposes */
+ cs.pszRulesetName = pszName; /* save for later display purposes */
finalize_it:
if(iRet != RS_RET_OK) { /* cleanup needed? */
@@ -143,7 +155,7 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1)
ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED);
}
- if(pRuleset == NULL) {
+ if(cs.pRuleset == NULL) {
errmsg.LogError(0, RS_RET_NO_RULESET, "error: no ruleset was specified, use "
"$ActionOmrulesetRulesetName directive first!");
ABORT_FINALIZE(RS_RET_NO_RULESET);
@@ -161,17 +173,17 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1)
* the format specified (if any) is always ignored.
*/
CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, iTplOpts, (uchar*) "RSYSLOG_FileFormat"));
- pData->pRuleset = pRuleset;
- pData->pszRulesetName = pszRulesetName;
- pRuleset = NULL; /* re-set, because there is a high risk of unwanted behavior if we leave it in! */
- pszRulesetName = NULL; /* note: we must not free, as we handed over this pointer to the instanceDat to the instanceDataa! */
+ pData->pRuleset = cs.pRuleset;
+ pData->pszRulesetName = cs.pszRulesetName;
+ cs.pRuleset = NULL; /* re-set, because there is a high risk of unwanted behavior if we leave it in! */
+ cs.pszRulesetName = NULL; /* note: we must not free, as we handed over this pointer to the instanceDat to the instanceDataa! */
CODE_STD_FINALIZERparseSelectorAct
ENDparseSelectorAct
BEGINmodExit
CODESTARTmodExit
- free(pszRulesetName);
+ free(cs.pszRulesetName);
objRelease(errmsg, CORE_COMPONENT);
objRelease(ruleset, CORE_COMPONENT);
ENDmodExit
@@ -189,7 +201,9 @@ ENDqueryEtryPt
static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
{
DEFiRet;
- pRuleset = NULL;
+ cs.pRuleset = NULL;
+ free(cs.pszRulesetName);
+ cs.pszRulesetName = NULL;
RETiRet;
}
@@ -200,6 +214,7 @@ BEGINmodInit()
unsigned long opts;
int bMsgPassingSupported; /* does core support template passing as an array? */
CODESTARTmodInit
+SCOPINGmodInit
*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
CODEmodInit_QueryRegCFSLineHdlr
/* check if the rsyslog core supports parameter passing code */
diff --git a/plugins/omsnmp/omsnmp.c b/plugins/omsnmp/omsnmp.c
index 11870579..0a4279bc 100644
--- a/plugins/omsnmp/omsnmp.c
+++ b/plugins/omsnmp/omsnmp.c
@@ -58,27 +58,6 @@ static oid objid_sysdescr[] = { 1, 3, 6, 1, 2, 1, 1, 1, 0 };
static oid objid_snmptrap[] = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 };
static oid objid_sysuptime[] = { 1, 3, 6, 1, 2, 1, 1, 3, 0 };
-static uchar* pszTransport = NULL; /* default transport */
-static uchar* pszTarget = NULL;
-/* note using an unsigned for a port number is not a good idea from an IPv6 point of view */
-static int iPort = 0;
-static int iSNMPVersion = 1; /* 0 Means SNMPv1, 1 Means SNMPv2c */
-static uchar* pszCommunity = NULL;
-static uchar* pszEnterpriseOID = NULL;
-static uchar* pszSnmpTrapOID = NULL;
-static uchar* pszSyslogMessageOID = NULL;
-static int iSpecificType = 0;
-static int iTrapType = SNMP_TRAP_ENTERPRISESPECIFIC;/*Default is SNMP_TRAP_ENTERPRISESPECIFIC */
-/*
- Possible Values
- SNMP_TRAP_COLDSTART (0)
- SNMP_TRAP_WARMSTART (1)
- SNMP_TRAP_LINKDOWN (2)
- SNMP_TRAP_LINKUP (3)
- SNMP_TRAP_AUTHFAIL (4)
- SNMP_TRAP_EGPNEIGHBORLOSS (5)
- SNMP_TRAP_ENTERPRISESPECIFIC (6)
-*/
typedef struct _instanceData {
uchar szTransport[OMSNMP_MAXTRANSPORLENGTH+1]; /* Transport - Can be udp, tcp, udp6, tcp6 and other types supported by NET-SNMP */
@@ -103,6 +82,46 @@ typedef struct _instanceData {
netsnmp_session *snmpsession; /* Holds to SNMP Session, NULL if not initialized */
} instanceData;
+typedef struct configSettings_s {
+ uchar* pszTransport; /* default transport */
+ uchar* pszTarget;
+ /* note using an unsigned for a port number is not a good idea from an IPv6 point of view */
+ int iPort;
+ int iSNMPVersion; /* 0 Means SNMPv1, 1 Means SNMPv2c */
+ uchar* pszCommunity;
+ uchar* pszEnterpriseOID;
+ uchar* pszSnmpTrapOID;
+ uchar* pszSyslogMessageOID;
+ int iSpecificType;
+ int iTrapType; /*Default is SNMP_TRAP_ENTERPRISESPECIFIC */
+ /*
+ Possible Values
+ SNMP_TRAP_COLDSTART (0)
+ SNMP_TRAP_WARMSTART (1)
+ SNMP_TRAP_LINKDOWN (2)
+ SNMP_TRAP_LINKUP (3)
+ SNMP_TRAP_AUTHFAIL (4)
+ SNMP_TRAP_EGPNEIGHBORLOSS (5)
+ SNMP_TRAP_ENTERPRISESPECIFIC (6)
+ */
+} configSettings_t;
+
+SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */
+
+BEGINinitConfVars /* (re)set config variables to default values */
+CODESTARTinitConfVars
+ cs.pszTransport = NULL;
+ cs.pszTarget = NULL;
+ cs.iPort = 0;
+ cs.iSNMPVersion = 1;
+ cs.pszCommunity = NULL;
+ cs.pszEnterpriseOID = NULL;
+ cs.pszSnmpTrapOID = NULL;
+ cs.pszSyslogMessageOID = NULL;
+ cs.iSpecificType = 0;
+ cs.iTrapType = SNMP_TRAP_ENTERPRISESPECIFIC;
+ENDinitConfVars
+
BEGINcreateInstance
CODESTARTcreateInstance
ENDcreateInstance
@@ -349,72 +368,72 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1)
FINALIZE;
/* Check Transport */
- if (pszTransport == NULL) {
+ if (cs.pszTransport == NULL) {
/*
* Default transport is UDP. Other values supported by NETSNMP are possible as well
*/
strncpy( (char*) pData->szTransport, "udp", sizeof("udp") );
} else {
/* Copy Transport */
- strncpy( (char*) pData->szTransport, (char*) pszTransport, strlen((char*) pszTransport) );
+ strncpy( (char*) pData->szTransport, (char*) cs.pszTransport, strlen((char*) cs.pszTransport) );
}
/* Check Target */
- if (pszTarget == NULL) {
+ if (cs.pszTarget == NULL) {
ABORT_FINALIZE( RS_RET_PARAM_ERROR );
} else {
/* Copy Target */
- CHKmalloc(pData->szTarget = (uchar*) strdup((char*)pszTarget));
+ CHKmalloc(pData->szTarget = (uchar*) strdup((char*)cs.pszTarget));
}
/* Copy Community */
- if (pszCommunity == NULL) /* Failsave */
+ if (cs.pszCommunity == NULL) /* Failsave */
strncpy( (char*) pData->szCommunity, "public", sizeof("public") );
else /* Copy Target */
- strncpy( (char*) pData->szCommunity, (char*) pszCommunity, strlen((char*) pszCommunity) );
+ strncpy( (char*) pData->szCommunity, (char*) cs.pszCommunity, strlen((char*) cs.pszCommunity) );
/* Copy Enterprise OID */
- if (pszEnterpriseOID == NULL) /* Failsave */
+ if (cs.pszEnterpriseOID == NULL) /* Failsave */
strncpy( (char*) pData->szEnterpriseOID, "1.3.6.1.4.1.3.1.1", sizeof("1.3.6.1.4.1.3.1.1") );
else /* Copy Target */
- strncpy( (char*) pData->szEnterpriseOID, (char*) pszEnterpriseOID, strlen((char*) pszEnterpriseOID) );
+ strncpy( (char*) pData->szEnterpriseOID, (char*) cs.pszEnterpriseOID, strlen((char*) cs.pszEnterpriseOID) );
/* Copy SnmpTrap OID */
- if (pszSnmpTrapOID == NULL) /* Failsave */
+ if (cs.pszSnmpTrapOID == NULL) /* Failsave */
strncpy( (char*) pData->szSnmpTrapOID, "1.3.6.1.4.1.19406.1.2.1", sizeof("1.3.6.1.4.1.19406.1.2.1") );
else /* Copy Target */
- strncpy( (char*) pData->szSnmpTrapOID, (char*) pszSnmpTrapOID, strlen((char*) pszSnmpTrapOID) );
+ strncpy( (char*) pData->szSnmpTrapOID, (char*) cs.pszSnmpTrapOID, strlen((char*) cs.pszSnmpTrapOID) );
/* Copy SyslogMessage OID */
- if (pszSyslogMessageOID == NULL) /* Failsave */
+ if (cs.pszSyslogMessageOID == NULL) /* Failsave */
strncpy( (char*) pData->szSyslogMessageOID, "1.3.6.1.4.1.19406.1.1.2.1", sizeof("1.3.6.1.4.1.19406.1.1.2.1") );
else /* Copy Target */
- strncpy( (char*) pData->szSyslogMessageOID, (char*) pszSyslogMessageOID, strlen((char*) pszSyslogMessageOID) );
+ strncpy( (char*) pData->szSyslogMessageOID, (char*) cs.pszSyslogMessageOID, strlen((char*) cs.pszSyslogMessageOID) );
/* Copy Port */
- if ( iPort == 0) /* If no Port is set we use the default Port 162 */
+ if ( cs.iPort == 0) /* If no Port is set we use the default Port 162 */
pData->iPort = 162;
else
- pData->iPort = iPort;
+ pData->iPort = cs.iPort;
/* Set SNMPVersion */
- if ( iSNMPVersion < 0 || iSNMPVersion > 1) /* Set default to 1 if out of range */
+ if ( cs.iSNMPVersion < 0 || cs.iSNMPVersion > 1) /* Set default to 1 if out of range */
pData->iSNMPVersion = 1;
else
- pData->iSNMPVersion = iSNMPVersion;
+ pData->iSNMPVersion = cs.iSNMPVersion;
/* Copy SpecificType */
- if ( iSpecificType == 0) /* If no iSpecificType is set, we use the default 0 */
+ if ( cs.iSpecificType == 0) /* If no iSpecificType is set, we use the default 0 */
pData->iSpecificType = 0;
else
- pData->iSpecificType = iSpecificType;
+ pData->iSpecificType = cs.iSpecificType;
/* Copy TrapType */
- if ( iTrapType < 0 && iTrapType >= 6) /* Only allow values from 0 to 6 !*/
+ if ( cs.iTrapType < 0 && cs.iTrapType >= 6) /* Only allow values from 0 to 6 !*/
pData->iTrapType = SNMP_TRAP_ENTERPRISESPECIFIC;
else
- pData->iTrapType = iTrapType;
+ pData->iTrapType = cs.iTrapType;
/* Create string for session peername! */
snprintf((char*)szTargetAndPort, sizeof(szTargetAndPort), "%s:%s:%d", pData->szTransport, pData->szTarget, pData->iPort);
@@ -453,48 +472,31 @@ ENDparseSelectorAct
static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
{
DEFiRet;
-
- if (pszTarget != NULL)
- free(pszTarget);
- pszTarget = NULL;
-
- if (pszCommunity != NULL)
- free(pszCommunity);
- pszCommunity = NULL;
-
- if (pszEnterpriseOID != NULL)
- free(pszEnterpriseOID);
- pszEnterpriseOID = NULL;
-
- if (pszSnmpTrapOID != NULL)
- free(pszSnmpTrapOID);
- pszSnmpTrapOID = NULL;
-
- if (pszSyslogMessageOID != NULL)
- free(pszSyslogMessageOID);
- pszSyslogMessageOID = NULL;
-
- iPort = 0;
- iSNMPVersion = 1;
- iSpecificType = 0;
- iTrapType = SNMP_TRAP_ENTERPRISESPECIFIC;
-
+ free(cs.pszTarget);
+ cs.pszTarget = NULL;
+ free(cs.pszCommunity);
+ cs.pszCommunity = NULL;
+ free(cs.pszEnterpriseOID);
+ cs.pszEnterpriseOID = NULL;
+ free(cs.pszSnmpTrapOID);
+ cs.pszSnmpTrapOID = NULL;
+ free(cs.pszSyslogMessageOID);
+ cs.pszSyslogMessageOID = NULL;
+ cs.iPort = 0;
+ cs.iSNMPVersion = 1;
+ cs.iSpecificType = 0;
+ cs.iTrapType = SNMP_TRAP_ENTERPRISESPECIFIC;
RETiRet;
}
BEGINmodExit
CODESTARTmodExit
- if (pszTarget != NULL)
- free(pszTarget);
- if (pszCommunity != NULL)
- free(pszCommunity);
- if (pszEnterpriseOID != NULL)
- free(pszEnterpriseOID);
- if (pszSnmpTrapOID != NULL)
- free(pszSnmpTrapOID);
- if (pszSyslogMessageOID != NULL)
- free(pszSyslogMessageOID);
+ free(cs.pszTarget);
+ free(cs.pszCommunity);
+ free(cs.pszEnterpriseOID);
+ free(cs.pszSnmpTrapOID);
+ free(cs.pszSyslogMessageOID);
/* release what we no longer need */
objRelease(errmsg, CORE_COMPONENT);
@@ -509,20 +511,21 @@ ENDqueryEtryPt
BEGINmodInit()
CODESTARTmodInit
+SCOPINGmodInit
*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
CODEmodInit_QueryRegCFSLineHdlr
CHKiRet(objUse(errmsg, CORE_COMPONENT));
- CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionsnmptransport", 0, eCmdHdlrGetWord, NULL, &pszTransport, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionsnmptarget", 0, eCmdHdlrGetWord, NULL, &pszTarget, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionsnmptargetport", 0, eCmdHdlrInt, NULL, &iPort, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionsnmpversion", 0, eCmdHdlrInt, NULL, &iSNMPVersion, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionsnmpcommunity", 0, eCmdHdlrGetWord, NULL, &pszCommunity, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionsnmpenterpriseoid", 0, eCmdHdlrGetWord, NULL, &pszEnterpriseOID, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionsnmptrapoid", 0, eCmdHdlrGetWord, NULL, &pszSnmpTrapOID, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionsnmpsyslogmessageoid", 0, eCmdHdlrGetWord, NULL, &pszSyslogMessageOID, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionsnmpspecifictype", 0, eCmdHdlrInt, NULL, &iSpecificType, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionsnmptraptype", 0, eCmdHdlrInt, NULL, &iTrapType, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionsnmptransport", 0, eCmdHdlrGetWord, NULL, &cs.pszTransport, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionsnmptarget", 0, eCmdHdlrGetWord, NULL, &cs.pszTarget, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionsnmptargetport", 0, eCmdHdlrInt, NULL, &cs.iPort, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionsnmpversion", 0, eCmdHdlrInt, NULL, &cs.iSNMPVersion, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionsnmpcommunity", 0, eCmdHdlrGetWord, NULL, &cs.pszCommunity, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionsnmpenterpriseoid", 0, eCmdHdlrGetWord, NULL, &cs.pszEnterpriseOID, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionsnmptrapoid", 0, eCmdHdlrGetWord, NULL, &cs.pszSnmpTrapOID, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionsnmpsyslogmessageoid", 0, eCmdHdlrGetWord, NULL, &cs.pszSyslogMessageOID, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionsnmpspecifictype", 0, eCmdHdlrInt, NULL, &cs.iSpecificType, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionsnmptraptype", 0, eCmdHdlrInt, NULL, &cs.iTrapType, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr( (uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
ENDmodInit
/*
diff --git a/plugins/omstdout/omstdout.c b/plugins/omstdout/omstdout.c
index cd689765..54dfdb04 100644
--- a/plugins/omstdout/omstdout.c
+++ b/plugins/omstdout/omstdout.c
@@ -45,13 +45,13 @@
MODULE_TYPE_OUTPUT
MODULE_TYPE_NOKEEP
+static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal);
+
/* internal structures
*/
DEF_OMOD_STATIC_DATA
/* config variables */
-static int bUseArrayInterface = 0; /* shall action use array instead of string template interface? */
-static int bEnsureLFEnding = 1; /* shall action use array instead of string template interface? */
typedef struct _instanceData {
@@ -59,6 +59,18 @@ typedef struct _instanceData {
int bEnsureLFEnding; /* ensure that a linefeed is written at the end of EACH record (test aid for nettester) */
} instanceData;
+typedef struct configSettings_s {
+ int bUseArrayInterface; /* shall action use array instead of string template interface? */
+ int bEnsureLFEnding; /* shall action use array instead of string template interface? */
+} configSettings_t;
+
+SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */
+
+BEGINinitConfVars /* (re)set config variables to default values */
+CODESTARTinitConfVars
+ resetConfigVariables(NULL, NULL);
+ENDinitConfVars
+
BEGINcreateInstance
CODESTARTcreateInstance
ENDcreateInstance
@@ -147,10 +159,10 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1)
/* check if a non-standard template is to be applied */
if(*(p-1) == ';')
--p;
- iTplOpts = (bUseArrayInterface == 0) ? 0 : OMSR_TPL_AS_ARRAY;
+ iTplOpts = (cs.bUseArrayInterface == 0) ? 0 : OMSR_TPL_AS_ARRAY;
CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, iTplOpts, (uchar*) "RSYSLOG_FileFormat"));
- pData->bUseArrayInterface = bUseArrayInterface;
- pData->bEnsureLFEnding = bEnsureLFEnding;
+ pData->bUseArrayInterface = cs.bUseArrayInterface;
+ pData->bEnsureLFEnding = cs.bEnsureLFEnding;
CODE_STD_FINALIZERparseSelectorAct
ENDparseSelectorAct
@@ -172,8 +184,8 @@ ENDqueryEtryPt
static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
{
DEFiRet;
- bUseArrayInterface = 0;
- bEnsureLFEnding = 1;
+ cs.bUseArrayInterface = 0;
+ cs.bEnsureLFEnding = 1;
RETiRet;
}
@@ -184,6 +196,7 @@ BEGINmodInit()
unsigned long opts;
int bArrayPassingSupported; /* does core support template passing as an array? */
CODESTARTmodInit
+SCOPINGmodInit
*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
CODEmodInit_QueryRegCFSLineHdlr
/* check if the rsyslog core supports parameter passing code */
@@ -202,10 +215,10 @@ CODEmodInit_QueryRegCFSLineHdlr
if(bArrayPassingSupported) {
/* enable config comand only if core supports it */
CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionomstdoutarrayinterface", 0, eCmdHdlrBinary, NULL,
- &bUseArrayInterface, STD_LOADABLE_MODULE_ID));
+ &cs.bUseArrayInterface, STD_LOADABLE_MODULE_ID));
}
CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionomstdoutensurelfending", 0, eCmdHdlrBinary, NULL,
- &bEnsureLFEnding, STD_LOADABLE_MODULE_ID));
+ &cs.bEnsureLFEnding, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler,
resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
ENDmodInit
diff --git a/plugins/omtemplate/omtemplate.c b/plugins/omtemplate/omtemplate.c
index 1472ebeb..2ed0518a 100644
--- a/plugins/omtemplate/omtemplate.c
+++ b/plugins/omtemplate/omtemplate.c
@@ -47,6 +47,8 @@
MODULE_TYPE_OUTPUT
MODULE_TYPE_NOKEEP
+static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal);
+
/* internal structures
*/
DEF_OMOD_STATIC_DATA
@@ -64,14 +66,23 @@ typedef struct _instanceData {
/* config variables
* For the configuration interface, we need to keep track of some settings. This
- * is done in global variables. It works as follows: when configuration statements
+ * is done in global variables, inside a struct. It works as follows: when configuration statements
* are entered, the config file handler (or custom function) sets the global
* variable here. When the action then actually is instantiated, this handler
* copies over to instanceData whatever configuration settings (from the global
* variables) apply. The global variables are NEVER used inside an action
* instance (at least this is how it is supposed to work ;)
*/
-static int iSrvPort = 0; /* sample: server port */
+typedef struct configSettings_s {
+ int iSrvPort; /* sample: server port */
+} configSettings_t;
+
+SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */
+
+BEGINinitConfVars /* (re)set config variables to default values */
+CODESTARTinitConfVars
+ resetConfigVariables(NULL, NULL);
+ENDinitConfVars
BEGINcreateInstance
@@ -177,7 +188,7 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1)
/* if we reach this point, all went well, and we can copy over to instanceData
* those configuration elements that we need.
*/
- pData->iSrvPort = (unsigned) iSrvPort; /* set configured port */
+ pData->iSrvPort = (unsigned) cs.iSrvPort; /* set configured port */
CODE_STD_FINALIZERparseSelectorAct
ENDparseSelectorAct
@@ -200,19 +211,20 @@ static rsRetVal
resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
{
DEFiRet;
- iSrvPort = 0; /* zero is the default port */
+ cs.iSrvPort = 0; /* zero is the default port */
RETiRet;
}
BEGINmodInit()
CODESTARTmodInit
+SCOPINGmodInit
*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
CODEmodInit_QueryRegCFSLineHdlr
CHKiRet(objUse(errmsg, CORE_COMPONENT));
/* register our config handlers */
/* confguration parameters MUST always be specified in lower case! */
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionomtemplteserverport", 0, eCmdHdlrInt, NULL, &iSrvPort, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionomtemplteserverport", 0, eCmdHdlrInt, NULL, &cs.iSrvPort, STD_LOADABLE_MODULE_ID));
/* "resetconfigvariables" should be provided. Notat that it is a chained directive */
CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
ENDmodInit
diff --git a/plugins/omtesting/omtesting.c b/plugins/omtesting/omtesting.c
index 909ff29a..139ac8f9 100644
--- a/plugins/omtesting/omtesting.c
+++ b/plugins/omtesting/omtesting.c
@@ -62,7 +62,6 @@ MODULE_TYPE_NOKEEP
*/
DEF_OMOD_STATIC_DATA
-static int bEchoStdout = 0; /* echo non-failed messages to stdout */
typedef struct _instanceData {
enum { MD_SLEEP, MD_FAIL, MD_RANDFAIL, MD_ALWAYS_SUSPEND }
@@ -76,6 +75,17 @@ typedef struct _instanceData {
int iCurrRetries;
} instanceData;
+typedef struct configSettings_s {
+ int bEchoStdout; /* echo non-failed messages to stdout */
+} configSettings_t;
+
+SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */
+
+BEGINinitConfVars /* (re)set config variables to default values */
+CODESTARTinitConfVars
+ cs.bEchoStdout = 0;
+ENDinitConfVars
+
BEGINcreateInstance
CODESTARTcreateInstance
pData->iWaitSeconds = 1;
@@ -287,7 +297,7 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1)
dbgprintf("invalid mode '%s', doing 'sleep 1 0' - fix your config\n", szBuf);
}
- pData->bEchoStdout = bEchoStdout;
+ pData->bEchoStdout = cs.bEchoStdout;
CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS,
(uchar*)"RSYSLOG_TraditionalForwardFormat"));
@@ -308,10 +318,11 @@ ENDqueryEtryPt
BEGINmodInit()
CODESTARTmodInit
+SCOPINGmodInit
*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
CODEmodInit_QueryRegCFSLineHdlr
CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionomtestingechostdout", 0, eCmdHdlrBinary, NULL,
- &bEchoStdout, STD_LOADABLE_MODULE_ID));
+ &cs.bEchoStdout, STD_LOADABLE_MODULE_ID));
/* we seed the random-number generator in any case... */
srand(time(NULL));
ENDmodInit
diff --git a/plugins/omudpspoof/omudpspoof.c b/plugins/omudpspoof/omudpspoof.c
index 48d7a68e..fd4551c9 100644
--- a/plugins/omudpspoof/omudpspoof.c
+++ b/plugins/omudpspoof/omudpspoof.c
@@ -105,14 +105,28 @@ typedef struct _instanceData {
#define DFLT_SOURCE_PORT_START 32000
#define DFLT_SOURCE_PORT_END 42000
-/* config data */
-static uchar *pszTplName = NULL; /* name of the default template to use */
-static uchar *pszSourceNameTemplate = NULL; /* name of the template containing the spoofing address */
-static uchar *pszTargetHost = NULL;
-static uchar *pszTargetPort = NULL;
-static int iCompressionLevel = 0; /* zlib compressionlevel, the usual values */
-static int iSourcePortStart = DFLT_SOURCE_PORT_START;
-static int iSourcePortEnd = DFLT_SOURCE_PORT_END;
+typedef struct configSettings_s {
+ uchar *pszTplName; /* name of the default template to use */
+ uchar *pszSourceNameTemplate; /* name of the template containing the spoofing address */
+ uchar *pszTargetHost;
+ uchar *pszTargetPort;
+ int iCompressionLevel; /* zlib compressionlevel, the usual values */
+ int iSourcePortStart;
+ int iSourcePortEnd;
+} configSettings_t;
+
+SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */
+
+BEGINinitConfVars /* (re)set config variables to default values */
+CODESTARTinitConfVars
+ cs.pszTplName = NULL;
+ cs.pszSourceNameTemplate = NULL;
+ cs.pszTargetHost = NULL;
+ cs.pszTargetPort = NULL;
+ cs.iCompressionLevel = 0;
+ cs.iSourcePortStart = DFLT_SOURCE_PORT_START;
+ cs.iSourcePortEnd = DFLT_SOURCE_PORT_END;
+ENDinitConfVars
/* add some variables needed for libnet */
@@ -394,28 +408,28 @@ CODE_STD_STRING_REQUESTparseSelectorAct(2)
p += sizeof(":omudpspoof:") - 1; /* eat indicator sequence (-1 because of '\0'!) */
CHKiRet(createInstance(&pData));
- sourceTpl = (pszSourceNameTemplate == NULL) ? UCHAR_CONSTANT("RSYSLOG_omudpspoofDfltSourceTpl")
- : pszSourceNameTemplate;
+ sourceTpl = (cs.pszSourceNameTemplate == NULL) ? UCHAR_CONSTANT("RSYSLOG_omudpspoofDfltSourceTpl")
+ : cs.pszSourceNameTemplate;
- if(pszTargetHost == NULL) {
+ if(cs.pszTargetHost == NULL) {
errmsg.LogError(0, NO_ERRCODE, "No $ActionOMUDPSpoofTargetHost given, can not continue with this action.");
ABORT_FINALIZE(RS_RET_HOST_NOT_SPECIFIED);
}
/* fill instance properties */
- CHKmalloc(pData->host = ustrdup(pszTargetHost));
- if(pszTargetPort == NULL)
+ CHKmalloc(pData->host = ustrdup(cs.pszTargetHost));
+ if(cs.pszTargetPort == NULL)
pData->port = NULL;
else
- CHKmalloc(pData->port = ustrdup(pszTargetPort));
- CHKiRet(OMSRsetEntry(*ppOMSR, 1, ustrdup(sourceTpl), OMSR_NO_RQD_TPL_OPTS));
- pData->compressionLevel = iCompressionLevel;
- pData->sourcePort = pData->sourcePortStart = iSourcePortStart;
- pData->sourcePortEnd = iSourcePortEnd;
+ CHKmalloc(pData->port = ustrdup(cs.pszTargetPort));
+ CHKiRet(OMSRsetEntry(*ppOMSR, 1, ustrdup(cs.pszSourceNameTemplate), OMSR_NO_RQD_TPL_OPTS));
+ pData->compressionLevel = cs.iCompressionLevel;
+ pData->sourcePort = pData->sourcePortStart = cs.iSourcePortStart;
+ pData->sourcePortEnd = cs.iSourcePortEnd;
/* process template */
CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS,
- (pszTplName == NULL) ? (uchar*)"RSYSLOG_TraditionalForwardFormat" : pszTplName));
+ (cs.pszTplName == NULL) ? (uchar*)"RSYSLOG_TraditionalForwardFormat" : cs.pszTplName));
CODE_STD_FINALIZERparseSelectorAct
ENDparseSelectorAct
@@ -427,12 +441,12 @@ ENDparseSelectorAct
static void
freeConfigVars(void)
{
- free(pszTplName);
- pszTplName = NULL;
- free(pszTargetHost);
- pszTargetHost = NULL;
- free(pszTargetPort);
- pszTargetPort = NULL;
+ free(cs.pszTplName);
+ cs.pszTplName = NULL;
+ free(cs.pszTargetHost);
+ cs.pszTargetHost = NULL;
+ free(cs.pszTargetPort);
+ cs.pszTargetPort = NULL;
}
@@ -461,15 +475,16 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a
{
freeConfigVars();
/* we now must reset all non-string values */
- iCompressionLevel = 0;
- iSourcePortStart = DFLT_SOURCE_PORT_START;
- iSourcePortEnd = DFLT_SOURCE_PORT_END;
+ cs.iCompressionLevel = 0;
+ cs.iSourcePortStart = DFLT_SOURCE_PORT_START;
+ cs.iSourcePortEnd = DFLT_SOURCE_PORT_END;
return RS_RET_OK;
}
BEGINmodInit()
CODESTARTmodInit
+SCOPINGmodInit
*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
CODEmodInit_QueryRegCFSLineHdlr
CHKiRet(objUse(glbl, CORE_COMPONENT));
@@ -489,13 +504,13 @@ CODEmodInit_QueryRegCFSLineHdlr
ABORT_FINALIZE(RS_RET_ERR_LIBNET_INIT);
}
- CHKiRet(regCfSysLineHdlr((uchar *)"actionomudpspoofdefaulttemplate", 0, eCmdHdlrGetWord, NULL, &pszTplName, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionomudpspoofsourcenametemplate", 0, eCmdHdlrGetWord, NULL, &pszSourceNameTemplate, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionomudpspooftargethost", 0, eCmdHdlrGetWord, NULL, &pszTargetHost, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionomudpspooftargetport", 0, eCmdHdlrGetWord, NULL, &pszTargetPort, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionomudpspoofsourceportstart", 0, eCmdHdlrInt, NULL, &iSourcePortStart, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionomudpspoofsourceportend", 0, eCmdHdlrInt, NULL, &iSourcePortEnd, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionomudpcompressionlevel", 0, eCmdHdlrInt, NULL, &iCompressionLevel, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionomudpspoofdefaulttemplate", 0, eCmdHdlrGetWord, NULL, &cs.pszTplName, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionomudpspoofsourcenametemplate", 0, eCmdHdlrGetWord, NULL, &cs.pszSourceNameTemplate, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionomudpspooftargethost", 0, eCmdHdlrGetWord, NULL, &cs.pszTargetHost, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionomudpspooftargetport", 0, eCmdHdlrGetWord, NULL, &cs.pszTargetPort, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionomudpspoofsourceportstart", 0, eCmdHdlrInt, NULL, &cs.iSourcePortStart, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionomudpspoofsourceportend", 0, eCmdHdlrInt, NULL, &cs.iSourcePortEnd, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionomudpcompressionlevel", 0, eCmdHdlrInt, NULL, &cs.iCompressionLevel, NULL));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
ENDmodInit
diff --git a/plugins/omuxsock/omuxsock.c b/plugins/omuxsock/omuxsock.c
index b29276f9..05b0532d 100644
--- a/plugins/omuxsock/omuxsock.c
+++ b/plugins/omuxsock/omuxsock.c
@@ -64,8 +64,19 @@ typedef struct _instanceData {
} instanceData;
/* config data */
-static uchar *tplName = NULL; /* name of the default template to use */
-static uchar *sockName = NULL; /* name of the default template to use */
+typedef struct configSettings_s {
+ uchar *tplName; /* name of the default template to use */
+ uchar *sockName; /* name of the default template to use */
+} configSettings_t;
+
+SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */
+
+BEGINinitConfVars /* (re)set config variables to default values */
+CODESTARTinitConfVars
+ cs.tplName = NULL;
+ cs.sockName = NULL;
+ENDinitConfVars
+
static rsRetVal doTryResume(instanceData *pData);
@@ -239,16 +250,16 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1)
/* check if a non-standard template is to be applied */
if(*(p-1) == ';')
--p;
- CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, 0, tplName == NULL ? UCHAR_CONSTANT("RSYSLOG_TraditionalForwardFormat")
- : tplName ));
+ CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, 0, cs.tplName == NULL ? UCHAR_CONSTANT("RSYSLOG_TraditionalForwardFormat")
+ : cs.tplName ));
- if(sockName == NULL) {
+ if(cs.sockName == NULL) {
errmsg.LogError(0, RS_RET_NO_SOCK_CONFIGURED, "No output socket configured for omuxsock\n");
ABORT_FINALIZE(RS_RET_NO_SOCK_CONFIGURED);
}
- pData->sockName = sockName;
- sockName = NULL; /* pData is now owner and will fee it */
+ pData->sockName = cs.sockName;
+ cs.sockName = NULL; /* pData is now owner and will fee it */
CODE_STD_FINALIZERparseSelectorAct
ENDparseSelectorAct
@@ -260,10 +271,10 @@ ENDparseSelectorAct
static inline void
freeConfigVars(void)
{
- free(tplName);
- tplName = NULL;
- free(sockName);
- sockName = NULL;
+ free(cs.tplName);
+ cs.tplName = NULL;
+ free(cs.sockName);
+ cs.sockName = NULL;
}
@@ -300,8 +311,8 @@ CODEmodInit_QueryRegCFSLineHdlr
CHKiRet(objUse(glbl, CORE_COMPONENT));
CHKiRet(objUse(errmsg, CORE_COMPONENT));
- CHKiRet(regCfSysLineHdlr((uchar *)"omuxsockdefaulttemplate", 0, eCmdHdlrGetWord, NULL, &tplName, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"omuxsocksocket", 0, eCmdHdlrGetWord, NULL, &sockName, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"omuxsockdefaulttemplate", 0, eCmdHdlrGetWord, NULL, &cs.tplName, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"omuxsocksocket", 0, eCmdHdlrGetWord, NULL, &cs.sockName, NULL));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
ENDmodInit
diff --git a/rsyslog.service.in b/rsyslog.service.in
index aa9e5db1..a5d53ad2 100644
--- a/rsyslog.service.in
+++ b/rsyslog.service.in
@@ -3,7 +3,7 @@ Description=System Logging Service
[Service]
ExecStartPre=/bin/systemctl stop systemd-kmsg-syslogd.service
-ExecStart=@sbindir@/rsyslogd -n -c5
+ExecStart=@sbindir@/rsyslogd -n -c6
Sockets=syslog.socket
StandardOutput=null
diff --git a/runtime/Makefile.am b/runtime/Makefile.am
index 09cb6b41..c8e8ce2a 100644
--- a/runtime/Makefile.am
+++ b/runtime/Makefile.am
@@ -110,12 +110,12 @@ librsyslog_la_SOURCES = \
# runtime or will no longer be needed. -- rgerhards, 2008-06-13
if WITH_MODDIRS
-librsyslog_la_CPPFLAGS = -DSD_EXPORT_SYMBOLS -D_PATH_MODDIR=\"$(pkglibdir)/:$(moddirs)\" $(PTHREADS_CFLAGS)
+librsyslog_la_CPPFLAGS = -DSD_EXPORT_SYMBOLS -D_PATH_MODDIR=\"$(pkglibdir)/:$(moddirs)\" $(PTHREADS_CFLAGS) $(LIBEE_CFLAGS)
else
-librsyslog_la_CPPFLAGS = -DSD_EXPORT_SYMBOLS -D_PATH_MODDIR=\"$(pkglibdir)/\" -I$(top_srcdir) $(PTHREADS_CFLAGS)
+librsyslog_la_CPPFLAGS = -DSD_EXPORT_SYMBOLS -D_PATH_MODDIR=\"$(pkglibdir)/\" -I$(top_srcdir) $(PTHREADS_CFLAGS) $(LIBEE_CFLAGS)
endif
#librsyslog_la_LDFLAGS = -module -avoid-version
-librsyslog_la_LIBADD = $(DL_LIBS) $(RT_LIBS)
+librsyslog_la_LIBADD = $(DL_LIBS) $(RT_LIBS) $(LIBEE_LIBS)
#
# regular expression support
diff --git a/runtime/cfsysline.c b/runtime/cfsysline.c
index 4997e0fb..b9516435 100644
--- a/runtime/cfsysline.c
+++ b/runtime/cfsysline.c
@@ -37,6 +37,7 @@
#include "cfsysline.h"
#include "obj.h"
+#include "conf.h"
#include "errmsg.h"
#include "srUtils.h"
#include "unicode-helper.h"
@@ -804,8 +805,7 @@ finalize_it:
* caller does not need to take care of that. The caller must, however,
* free pCmdName if he allocated it dynamically! -- rgerhards, 2007-08-09
*/
-rsRetVal regCfSysLineHdlr(uchar *pCmdName, int bChainingPermitted, ecslCmdHdrlType eType, rsRetVal (*pHdlr)(), void *pData,
- void *pOwnerCookie)
+rsRetVal regCfSysLineHdlr(uchar *pCmdName, int bChainingPermitted, ecslCmdHdrlType eType, rsRetVal (*pHdlr)(), void *pData, void *pOwnerCookie)
{
DEFiRet;
cslCmd_t *pThis;
@@ -910,6 +910,7 @@ rsRetVal processCfSysLineCommand(uchar *pCmdName, uchar **p)
uchar *pHdlrP; /* the handler's private p (else we could only call one handler) */
int bWasOnceOK; /* was the result of an handler at least once RS_RET_OK? */
uchar *pOKp = NULL; /* returned conf line pointer when it was OK */
+ int bHadScopingErr = 0; /* set if a scoping error occured */
iRet = llFind(&llCmdList, (void *) pCmdName, (void*) &pCmd);
@@ -923,17 +924,25 @@ rsRetVal processCfSysLineCommand(uchar *pCmdName, uchar **p)
llCookieCmdHdlr = NULL;
bWasOnceOK = 0;
while((iRetLL = llGetNextElt(&pCmd->llCmdHdlrs, &llCookieCmdHdlr, (void*)&pCmdHdlr)) == RS_RET_OK) {
- /* for the time being, we ignore errors during handlers. The
- * reason is that handlers are independent. An error in one
- * handler does not necessarily mean that another one will
- * fail, too. Later, we might add a config variable to control
- * this behaviour (but I am not sure if that is rally
- * necessary). -- rgerhards, 2007-07-31
- */
- pHdlrP = *p;
- if((iRet = cslchCallHdlr(pCmdHdlr, &pHdlrP)) == RS_RET_OK) {
- bWasOnceOK = 1;
- pOKp = pHdlrP;
+ /* check if handler is valid in current scope */
+ if(pCmdHdlr->eConfObjType == eConfObjAlways ||
+ (bConfStrictScoping == 0 && currConfObj == eConfObjGlobal) ||
+ pCmdHdlr->eConfObjType == currConfObj) {
+ /* for the time being, we ignore errors during handlers. The
+ * reason is that handlers are independent. An error in one
+ * handler does not necessarily mean that another one will
+ * fail, too. Later, we might add a config variable to control
+ * this behaviour (but I am not sure if that is really
+ * necessary). -- rgerhards, 2007-07-31
+ */
+ pHdlrP = *p;
+ if((iRet = cslchCallHdlr(pCmdHdlr, &pHdlrP)) == RS_RET_OK) {
+ bWasOnceOK = 1;
+ pOKp = pHdlrP;
+ }
+ } else {
+ errmsg.LogError(0, RS_RET_CONF_INVLD_SCOPE, "config command invalid for current scope");
+ bHadScopingErr = 1;
}
}
@@ -945,6 +954,10 @@ rsRetVal processCfSysLineCommand(uchar *pCmdName, uchar **p)
if(iRetLL != RS_RET_END_OF_LINKEDLIST)
iRet = iRetLL;
+ if(bHadScopingErr) {
+ iRet = RS_RET_CONF_INVLD_SCOPE;
+ }
+
finalize_it:
RETiRet;
}
diff --git a/runtime/cfsysline.h b/runtime/cfsysline.h
index 53f35f6a..2768243f 100644
--- a/runtime/cfsysline.h
+++ b/runtime/cfsysline.h
@@ -24,28 +24,12 @@
#include "linkedlist.h"
-/* types of configuration handlers
- */
-typedef enum cslCmdHdlrType {
- eCmdHdlrInvalid = 0, /* invalid handler type - indicates a coding error */
- eCmdHdlrCustomHandler, /* custom handler, just call handler function */
- eCmdHdlrUID,
- eCmdHdlrGID,
- eCmdHdlrBinary,
- eCmdHdlrFileCreateMode,
- eCmdHdlrInt,
- eCmdHdlrSize,
- eCmdHdlrGetChar,
- eCmdHdlrFacility,
- eCmdHdlrSeverity,
- eCmdHdlrGetWord
-} ecslCmdHdrlType;
-
/* this is a single entry for a parse routine. It describes exactly
* one entry point/handler.
* The short name is cslch (Configfile SysLine CommandHandler)
*/
struct cslCmdHdlr_s { /* config file sysline parse entry */
+ ecslConfObjType __attribute__((deprecated)) eConfObjType; /* which config object is this for? */
ecslCmdHdrlType eType; /* which type of handler is this? */
rsRetVal (*cslCmdHdlr)(); /* function pointer to use with handler (params depending on eType) */
void *pData; /* user-supplied data pointer */
diff --git a/runtime/conf.c b/runtime/conf.c
index 4bd18bf5..6b812573 100644
--- a/runtime/conf.c
+++ b/runtime/conf.c
@@ -48,7 +48,6 @@
#endif
#include "rsyslog.h"
-#include "../tools/syslogd.h" /* TODO: this must be removed! */
#include "dirty.h"
#include "parse.h"
#include "action.h"
@@ -89,6 +88,10 @@ DEFobjCurrIf(net)
DEFobjCurrIf(rule)
DEFobjCurrIf(ruleset)
+ecslConfObjType currConfObj = eConfObjGlobal; /* to support scoping - which config object is currently active? */
+int bConfStrictScoping = 0; /* force strict scoping during config processing? */
+
+
static int iNbrActions = 0; /* number of currently defined actions */
/* The following module-global variables are used for building
@@ -870,6 +873,14 @@ static rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f)
rsParsDestruct(pPars);
return(iRet);
}
+ if(f->f_filterData.prop.propID == PROP_CEE) {
+ /* in CEE case, we need to preserve the actual property name */
+ if((f->f_filterData.prop.propName =
+ es_newStrFromBuf((char*)cstrGetSzStrNoNULL(pCSPropName)+2, cstrLen(pCSPropName)-2)) == NULL) {
+ cstrDestruct(&pCSPropName);
+ return(RS_RET_ERR);
+ }
+ }
cstrDestruct(&pCSPropName);
/* read operation */
@@ -898,10 +909,13 @@ static rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f)
iOffset = 0;
}
+dbgprintf("XXX: offset is %d, string '%s'\n", iOffset, rsCStrGetSzStrNoNULL(pCSCompOp));
if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "contains", 8)) {
f->f_filterData.prop.operation = FIOP_CONTAINS;
} else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "isequal", 7)) {
f->f_filterData.prop.operation = FIOP_ISEQUAL;
+ } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "isempty", 7)) {
+ f->f_filterData.prop.operation = FIOP_ISEMPTY;
} else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "startswith", 10)) {
f->f_filterData.prop.operation = FIOP_STARTSWITH;
} else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (unsigned char*) "regex", 5)) {
@@ -914,12 +928,15 @@ static rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f)
}
rsCStrDestruct(&pCSCompOp); /* no longer needed */
- /* read compare value */
- iRet = parsQuotedCStr(pPars, &f->f_filterData.prop.pCSCompValue);
- if(iRet != RS_RET_OK) {
- errmsg.LogError(0, iRet, "error %d compare value property - ignoring selector", iRet);
- rsParsDestruct(pPars);
- return(iRet);
+dbgprintf("XXX: fiop is %u\n", (unsigned) f->f_filterData.prop.operation);
+ if(f->f_filterData.prop.operation != FIOP_ISEMPTY) {
+ /* read compare value */
+ iRet = parsQuotedCStr(pPars, &f->f_filterData.prop.pCSCompValue);
+ if(iRet != RS_RET_OK) {
+ errmsg.LogError(0, iRet, "error %d compare value property - ignoring selector", iRet);
+ rsParsDestruct(pPars);
+ return(iRet);
+ }
}
/* skip to action part */
@@ -1061,7 +1078,6 @@ static rsRetVal cflineDoFilter(uchar **pp, rule_t *f)
* and, if so, we copy them over. rgerhards, 2005-10-18
*/
if(pDfltProgNameCmp != NULL) {
-RUNLOG_STR("dflt ProgNameCmp != NULL, setting opCSProgNameComp");
CHKiRet(rsCStrConstructFromCStr(&(f->pCSProgNameComp), pDfltProgNameCmp));
}
@@ -1101,6 +1117,11 @@ static rsRetVal cflineDoAction(uchar **p, action_t **ppAction)
iRet = pMod->mod.om.parseSelectorAct(p, &pModData, &pOMSR);
dbgprintf("tried selector action for %s: %d\n", module.GetName(pMod), iRet);
if(iRet == RS_RET_OK || iRet == RS_RET_SUSPENDED) {
+ /* advance our config parser state: we now only accept an $End as valid,
+ * no more action statments.
+ */
+ if(currConfObj == eConfObjAction)
+ currConfObj = eConfObjActionWaitEnd;
if((iRet = addAction(&pAction, pMod, pModData, pOMSR, (iRet == RS_RET_SUSPENDED)? 1 : 0)) == RS_RET_OK) {
/* now check if the module is compatible with select features */
if(pMod->isCompatibleWithFeature(sFEATURERepeatedMsgReduction) == RS_RET_OK)
@@ -1250,6 +1271,134 @@ finalize_it:
ENDobjQueryInterface(conf)
+/* switch to a new action scope. This means that we switch the current
+ * mode to action, but it also means we need to clear all scope variables,
+ * so that we have a new environment.
+ * rgerhards, 2010-07-23
+ */
+static inline rsRetVal
+setActionScope(void)
+{
+ DEFiRet;
+ modInfo_t *pMod;
+
+ currConfObj = eConfObjAction;
+ DBGPRINTF("entering action scope\n");
+ CHKiRet(actionNewScope());
+
+ /* now tell each action to start the scope */
+ pMod = NULL;
+ while((pMod = module.GetNxtType(pMod, eMOD_OUT)) != NULL) {
+ DBGPRINTF("NO LONGER SUPPORTED beginning scope on module %s\n", pMod->pszName);
+ }
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* switch back from action scope.
+ * rgerhards, 2010-07-27
+ */
+static inline rsRetVal
+unsetActionScope(void)
+{
+ DEFiRet;
+ modInfo_t *pMod;
+
+ currConfObj = eConfObjAction;
+ DBGPRINTF("exiting action scope\n");
+ CHKiRet(actionRestoreScope());
+
+ /* now tell each action to restore the scope */
+ pMod = NULL;
+ while((pMod = module.GetNxtType(pMod, eMOD_OUT)) != NULL) {
+ DBGPRINTF("NO LONGER SUPPORTED exiting scope on module %s\n", pMod->pszName);
+ }
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* This method is called by our own handlers to begin a new config
+ * object ($Begin statement). This also implies a new scope.
+ * rgerhards, 2010-07-23
+ */
+static rsRetVal
+beginConfObj(void __attribute__((unused)) *pVal, uchar *pszName)
+{
+ DEFiRet;
+
+ if(currConfObj != eConfObjGlobal) {
+ errmsg.LogError(0, RS_RET_CONF_NOT_GLBL, "not in global scope - can not nest $Begin");
+ ABORT_FINALIZE(RS_RET_CONF_NOT_GLBL);
+ }
+
+ if(!strcasecmp((char*)pszName, "action")) {
+ setActionScope();
+ } else {
+ errmsg.LogError(0, RS_RET_INVLD_CONF_OBJ, "invalid config object \"%s\" in $Begin", pszName);
+ ABORT_FINALIZE(RS_RET_INVLD_CONF_OBJ);
+ }
+
+finalize_it:
+ free(pszName); /* no longer needed */
+ RETiRet;
+}
+
+
+/* This method is called to end a config scope and switch
+ * back to global scope.
+ * rgerhards, 2010-07-23
+ */
+static rsRetVal
+endConfObj(void __attribute__((unused)) *pVal, uchar *pszName)
+{
+ DEFiRet;
+
+ if(currConfObj == eConfObjGlobal) {
+ errmsg.LogError(0, RS_RET_CONF_NOT_GLBL, "already in global scope - dangling $End");
+ ABORT_FINALIZE(RS_RET_CONF_IN_GLBL);
+ }
+
+ if(!strcasecmp((char*)pszName, "action")) {
+ if(currConfObj == eConfObjAction) {
+ errmsg.LogError(0, RS_RET_CONF_END_NO_ACT, "$End action but not action specified");
+ /* this is a warning, we continue processing in that case (unscope) */
+ } else if(currConfObj != eConfObjActionWaitEnd) {
+ errmsg.LogError(0, RS_RET_CONF_INVLD_END, "$End not for active config object - "
+ "nesting error?");
+ ABORT_FINALIZE(RS_RET_CONF_INVLD_END);
+ }
+ currConfObj = eConfObjGlobal;
+ CHKiRet(unsetActionScope());
+ } else {
+ errmsg.LogError(0, RS_RET_INVLD_CONF_OBJ, "invalid config object \"%s\" in $End", pszName);
+ ABORT_FINALIZE(RS_RET_INVLD_CONF_OBJ);
+ }
+
+finalize_it:
+ free(pszName); /* no longer needed */
+ RETiRet;
+}
+
+
+/* Reset config variables to default values. Note that
+ * when we are inside an scope, we simply reset this to global.
+ * However, $ResetConfigVariables is a global directive, and as such
+ * will not be honored inside a scope!
+ * rgerhards, 2010-07-23
+ */
+static rsRetVal
+resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
+{
+ currConfObj = eConfObjGlobal;
+ bConfStrictScoping = 0;
+ return RS_RET_OK;
+}
+
+
/* exit our class
* rgerhards, 2008-03-11
*/
@@ -1290,6 +1439,11 @@ BEGINAbstractObjClassInit(conf, 1, OBJ_IS_CORE_MODULE) /* class, version - CHANG
CHKiRet(objUse(net, LM_NET_FILENAME)); /* TODO: make this dependcy go away! */
CHKiRet(objUse(rule, CORE_COMPONENT));
CHKiRet(objUse(ruleset, CORE_COMPONENT));
+
+ /* These commands will NOT be supported -- the new v6.3 config system provides
+ * far better methods. We will remove the related code soon. -- rgerhards, 2012-01-09
+ */
+ CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, NULL));
ENDObjClassInit(conf)
/* vi:set ai:
diff --git a/runtime/conf.h b/runtime/conf.h
index 93683975..8c6174cb 100644
--- a/runtime/conf.h
+++ b/runtime/conf.h
@@ -27,6 +27,8 @@
* somewhat strange (at least its name). -- rgerhards, 2007-08-01
*/
enum eDirective { DIR_TEMPLATE = 0, DIR_OUTCHANNEL = 1, DIR_ALLOWEDSENDER = 2};
+extern ecslConfObjType currConfObj;
+extern int bConfStrictScoping; /* force strict scoping during config processing? */
/* interfaces */
BEGINinterface(conf) /* name must also be changed in ENDinterface macro! */
@@ -37,8 +39,14 @@ BEGINinterface(conf) /* name must also be changed in ENDinterface macro! */
rsRetVal (*cfline)(uchar *line, rule_t **pfCurr);
rsRetVal (*processConfFile)(uchar *pConfFile);
rsRetVal (*GetNbrActActions)(int *);
+ /* version 4 -- 2010-07-23 rgerhards */
+ /* "just" added global variables
+ * FYI: we reconsider repacking as a non-object, as only the core currently
+ * accesses this module. The current object structure complicates things without
+ * any real benefit.
+ */
ENDinterface(conf)
-#define confCURR_IF_VERSION 3 /* increment whenever you change the interface structure! */
+#define confCURR_IF_VERSION 4 /* increment whenever you change the interface structure! */
/* in Version 3, entry point "ReInitConf()" was removed, as we do not longer need
* to support restart-type HUP -- rgerhards, 2009-07-15
*/
diff --git a/runtime/ctok.c b/runtime/ctok.c
index 1da4f4d6..16d59425 100644
--- a/runtime/ctok.c
+++ b/runtime/ctok.c
@@ -275,6 +275,9 @@ ctokGetVar(ctok_t *pThis, ctok_token_t *pToken)
if(c == '$') { /* second dollar, we have a system variable */
pToken->tok = ctok_SYSVAR;
CHKiRet(ctokGetCharFromStream(pThis, &c)); /* "eat" it... */
+ } else if(c == '!') { /* cee variable indicator */
+ pToken->tok = ctok_CEEVAR;
+ CHKiRet(ctokGetCharFromStream(pThis, &c)); /* "eat" it... */
} else {
pToken->tok = ctok_MSGVAR;
}
diff --git a/runtime/ctok_token.h b/runtime/ctok_token.h
index 578fcaa6..1f476b4c 100644
--- a/runtime/ctok_token.h
+++ b/runtime/ctok_token.h
@@ -52,6 +52,7 @@ typedef struct {
ctok_FUNCTION = 17,
ctok_THEN = 18,
ctok_STRADD = 19,
+ ctok_CEEVAR = 20,
ctok_CMP_EQ = 100, /* all compare operations must be in a row */
ctok_CMP_NEQ = 101,
ctok_CMP_LT = 102,
diff --git a/runtime/debug.c b/runtime/debug.c
index d02bd516..955076e2 100644
--- a/runtime/debug.c
+++ b/runtime/debug.c
@@ -841,12 +841,15 @@ do_dbgprint(uchar *pszObjName, char *pszMsg, size_t lenMsg)
static int bWasNL = 0;
char pszThrdName[64]; /* 64 is to be on the safe side, anything over 20 is bad... */
char pszWriteBuf[32*1024];
+ size_t lenCopy;
+ size_t offsWriteBuf = 0;
size_t lenWriteBuf;
struct timespec t;
# if _POSIX_TIMERS <= 0
struct timeval tv;
# endif
+#if 1
/* The bWasNL handler does not really work. It works if no thread
* switching occurs during non-NL messages. Else, things are messed
* up. Anyhow, it works well enough to provide useful help during
@@ -857,8 +860,8 @@ do_dbgprint(uchar *pszObjName, char *pszMsg, size_t lenMsg)
*/
if(ptLastThrdID != pthread_self()) {
if(!bWasNL) {
- if(stddbg != -1) write(stddbg, "\n", 1);
- if(altdbg != -1) write(altdbg, "\n", 1);
+ pszWriteBuf[0] = '\n';
+ offsWriteBuf = 1;
bWasNL = 1;
}
ptLastThrdID = pthread_self();
@@ -879,25 +882,28 @@ do_dbgprint(uchar *pszObjName, char *pszMsg, size_t lenMsg)
t.tv_sec = tv.tv_sec;
t.tv_nsec = tv.tv_usec * 1000;
# endif
- lenWriteBuf = snprintf(pszWriteBuf, sizeof(pszWriteBuf),
+ lenWriteBuf = snprintf(pszWriteBuf+offsWriteBuf, sizeof(pszWriteBuf) - offsWriteBuf,
"%4.4ld.%9.9ld:", (long) (t.tv_sec % 10000), t.tv_nsec);
- if(stddbg != -1) write(stddbg, pszWriteBuf, lenWriteBuf);
- if(altdbg != -1) write(altdbg, pszWriteBuf, lenWriteBuf);
+ offsWriteBuf += lenWriteBuf;
}
- lenWriteBuf = snprintf(pszWriteBuf, sizeof(pszWriteBuf), "%s: ", pszThrdName);
- // use for testing: lenWriteBuf = snprintf(pszWriteBuf, sizeof(pszWriteBuf), "{%ld}%s: ", (long) syscall(SYS_gettid), pszThrdName);
- if(stddbg != -1) write(stddbg, pszWriteBuf, lenWriteBuf);
- if(altdbg != -1) write(altdbg, pszWriteBuf, lenWriteBuf);
+ lenWriteBuf = snprintf(pszWriteBuf + offsWriteBuf, sizeof(pszWriteBuf) - offsWriteBuf, "%s: ", pszThrdName);
+ offsWriteBuf += lenWriteBuf;
/* print object name header if we have an object */
if(pszObjName != NULL) {
- lenWriteBuf = snprintf(pszWriteBuf, sizeof(pszWriteBuf), "%s: ", pszObjName);
- if(stddbg != -1) write(stddbg, pszWriteBuf, lenWriteBuf);
- if(altdbg != -1) write(altdbg, pszWriteBuf, lenWriteBuf);
+ lenWriteBuf = snprintf(pszWriteBuf + offsWriteBuf, sizeof(pszWriteBuf) - offsWriteBuf, "%s: ", pszObjName);
+ offsWriteBuf += lenWriteBuf;
}
}
- if(stddbg != -1) write(stddbg, pszMsg, lenMsg);
- if(altdbg != -1) write(altdbg, pszMsg, lenMsg);
+#endif
+ if(lenMsg > sizeof(pszWriteBuf) - offsWriteBuf)
+ lenCopy = sizeof(pszWriteBuf) - offsWriteBuf;
+ else
+ lenCopy = lenMsg;
+ memcpy(pszWriteBuf + offsWriteBuf, pszMsg, lenCopy);
+ offsWriteBuf += lenCopy;
+ if(stddbg != -1) write(stddbg, pszWriteBuf, offsWriteBuf);
+ if(altdbg != -1) write(altdbg, pszWriteBuf, offsWriteBuf);
bWasNL = (pszMsg[lenMsg - 1] == '\n') ? 1 : 0;
}
@@ -921,12 +927,12 @@ dbgprint(obj_t *pObj, char *pszMsg, size_t lenMsg)
pszObjName = obj.GetName(pObj);
}
- pthread_mutex_lock(&mutdbgprint);
- pthread_cleanup_push(dbgMutexCancelCleanupHdlr, &mutdbgprint);
+// pthread_mutex_lock(&mutdbgprint);
+// pthread_cleanup_push(dbgMutexCancelCleanupHdlr, &mutdbgprint);
do_dbgprint(pszObjName, pszMsg, lenMsg);
- pthread_cleanup_pop(1);
+// pthread_cleanup_pop(1);
}
#pragma GCC diagnostic warning "-Wempty-body"
diff --git a/runtime/expr.c b/runtime/expr.c
index 6d376ad3..4538e14e 100644
--- a/runtime/expr.c
+++ b/runtime/expr.c
@@ -149,6 +149,11 @@ terminal(expr_t *pThis, ctok_t *tok)
CHKiRet(ctok_token.UnlinkVar(pToken, &pVar));
CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_PUSHMSGVAR, pVar)); /* add to program */
break;
+ case ctok_CEEVAR:
+ dbgoprint((obj_t*) pThis, "SYSVAR\n");
+ CHKiRet(ctok_token.UnlinkVar(pToken, &pVar));
+ CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_PUSHCEEVAR, pVar)); /* add to program */
+ break;
case ctok_SYSVAR:
dbgoprint((obj_t*) pThis, "SYSVAR\n");
CHKiRet(ctok_token.UnlinkVar(pToken, &pVar));
diff --git a/runtime/glbl.h b/runtime/glbl.h
index 4b4bdf83..82bd1a7a 100644
--- a/runtime/glbl.h
+++ b/runtime/glbl.h
@@ -76,7 +76,7 @@ BEGINinterface(glbl) /* name must also be changed in ENDinterface macro! */
*/
SIMP_PROP(FdSetSize, int)
/* v7: was neeeded to mean v5+v6 - do NOT add anything else for that version! */
- /* next change is v8! */
+ /* next is v8! */
#undef SIMP_PROP
ENDinterface(glbl)
#define glblCURR_IF_VERSION 7 /* increment whenever you change the interface structure! */
diff --git a/runtime/module-template.h b/runtime/module-template.h
index e21d6157..d7a869d4 100644
--- a/runtime/module-template.h
+++ b/runtime/module-template.h
@@ -35,7 +35,7 @@
/* macro to define standard output-module static data members
*/
#define DEF_MOD_STATIC_DATA \
- static __attribute__((unused)) rsRetVal (*omsdRegCFSLineHdlr)();
+ static __attribute__((unused)) rsRetVal (*omsdRegCFSLineHdlr)(uchar *pCmdName, int bChainingPermitted, ecslCmdHdrlType eType, rsRetVal (*pHdlr)(), void *pData, void *pOwnerCookie);
#define DEF_OMOD_STATIC_DATA \
DEF_MOD_STATIC_DATA \
@@ -316,6 +316,50 @@ static rsRetVal tryResume(instanceData __attribute__((unused)) *pData)\
}
+/* Config scoping system.
+ * save current config scope and start a new one. Note that we do NOT implement a
+ * stack. Exactly one scope can be saved.
+ * We assume standard naming conventions (local confgSettings_t holds all
+ * config settings and MUST have been defined before this macro is being used!).
+ * Note that initConfVars() must be defined locally as well.
+ */
+#define SCOPING_SUPPORT \
+static rsRetVal initConfVars(void);\
+static configSettings_t cs; /* our current config settings */ \
+static configSettings_t cs_save; /* our saved (scope!) config settings */ \
+static rsRetVal __attribute__((unused)) newScope(void) \
+{ \
+ DEFiRet; \
+ memcpy(&cs_save, &cs, sizeof(cs)); \
+ iRet = initConfVars(); \
+ RETiRet; \
+} \
+static rsRetVal __attribute__((unused)) restoreScope(void) \
+{ \
+ DEFiRet; \
+ memcpy(&cs, &cs_save, sizeof(cs)); \
+ RETiRet; \
+}
+/* initConfVars()
+ * This entry point is called to check if a module can resume operations. This
+ * happens when a module requested that it be suspended. In suspended state,
+ * the engine periodically tries to resume the module. If that succeeds, normal
+ * processing continues. If not, the module will not be called unless a
+ * tryResume() call succeeds.
+ * Returns RS_RET_OK, if resumption succeeded, RS_RET_SUSPENDED otherwise
+ * rgerhard, 2007-08-02
+ */
+#define BEGINinitConfVars \
+static rsRetVal initConfVars(void)\
+{\
+ DEFiRet;
+
+#define CODESTARTinitConfVars
+
+#define ENDinitConfVars \
+ RETiRet;\
+}
+
/* queryEtryPt()
*/
@@ -485,6 +529,10 @@ rsRetVal modInit##uniqName(int iIFVersRequested __attribute__((unused)), int *ip
/* now get the obj interface so that we can access other objects */ \
CHKiRet(pObjGetObjInterface(&obj));
+/* do those initializations necessary for scoping */
+#define SCOPINGmodInit \
+ initConfVars();
+
#define ENDmodInit \
finalize_it:\
*pQueryEtryPt = queryEtryPt;\
diff --git a/runtime/modules.c b/runtime/modules.c
index 4541bddf..23b5c94e 100644
--- a/runtime/modules.c
+++ b/runtime/modules.c
@@ -355,8 +355,7 @@ static modInfo_t *GetNxt(modInfo_t *pThis)
/* this function is like GetNxt(), but it returns pointers to
- * modules of specific type only. As we currently deal just with output modules,
- * it is a dummy, to be filled with real code later.
+ * modules of specific type only.
* rgerhards, 2007-07-24
*/
static modInfo_t *GetNxtType(modInfo_t *pThis, eModType_t rqtdType)
diff --git a/runtime/modules.h b/runtime/modules.h
index 4daaf1f9..75e993f1 100644
--- a/runtime/modules.h
+++ b/runtime/modules.h
@@ -47,8 +47,10 @@
* version 5 changes the way parsing works for input modules. This is
* an important change, parseAndSubmitMessage() goes away. Other
* module types are not affected. -- rgerhards, 2008-10-09
+ * version 6 introduces scoping support (starting with the output
+ * modules) -- rgerhards, 2010-07-27
*/
-#define CURR_MOD_IF_VERSION 5
+#define CURR_MOD_IF_VERSION 6
typedef enum eModType_ {
eMOD_IN = 0, /* input module */
diff --git a/runtime/msg.c b/runtime/msg.c
index 7b94228c..01808ac0 100644
--- a/runtime/msg.c
+++ b/runtime/msg.c
@@ -36,7 +36,9 @@
#include <assert.h>
#include <ctype.h>
#include <sys/socket.h>
+#include <sys/sysinfo.h>
#include <netdb.h>
+#include <libee/libee.h>
#if HAVE_MALLOC_H
# include <malloc.h>
#endif
@@ -561,8 +563,14 @@ rsRetVal propNameToID(cstr_t *pCSPropName, propid_t *pPropID)
*pPropID = PROP_SYS_MINUTE;
} else if(!strcmp((char*) pName, "$myhostname")) {
*pPropID = PROP_SYS_MYHOSTNAME;
+ } else if(!strcmp((char*) pName, "$!all-json")) {
+ *pPropID = PROP_CEE_ALL_JSON;
+ } else if(!strncmp((char*) pName, "$!", 2)) {
+ *pPropID = PROP_CEE;
} else if(!strcmp((char*) pName, "$bom")) {
*pPropID = PROP_SYS_BOM;
+ } else if(!strcmp((char*) pName, "$uptime")) {
+ *pPropID = PROP_SYS_UPTIME;
} else {
*pPropID = PROP_INVALID;
iRet = RS_RET_VAR_NOT_FOUND;
@@ -644,6 +652,10 @@ uchar *propIDToName(propid_t propID)
return UCHAR_CONSTANT("$MINUTE");
case PROP_SYS_MYHOSTNAME:
return UCHAR_CONSTANT("$MYHOSTNAME");
+ case PROP_CEE:
+ return UCHAR_CONSTANT("*CEE-based property*");
+ case PROP_CEE_ALL_JSON:
+ return UCHAR_CONSTANT("$!all-json");
case PROP_SYS_BOM:
return UCHAR_CONSTANT("$BOM");
default:
@@ -714,6 +726,7 @@ static inline rsRetVal msgBaseConstruct(msg_t **ppThis)
pM->pRcvFromIP = NULL;
pM->rcvFrom.pRcvFrom = NULL;
pM->pRuleset = NULL;
+ pM->event = NULL;
memset(&pM->tRcvdAt, 0, sizeof(pM->tRcvdAt));
memset(&pM->tTIMESTAMP, 0, sizeof(pM->tTIMESTAMP));
pM->TAG.pszTAG = NULL;
@@ -849,6 +862,8 @@ CODESTARTobjDestruct(msg)
rsCStrDestruct(&pThis->pCSPROCID);
if(pThis->pCSMSGID != NULL)
rsCStrDestruct(&pThis->pCSMSGID);
+ if(pThis->event != NULL)
+ ee_deleteEvent(pThis->event);
# ifndef HAVE_ATOMIC_BUILTINS
MsgUnlock(pThis);
# endif
@@ -1221,7 +1236,7 @@ char *getProtocolVersionString(msg_t *pM)
}
-static inline void
+void
getRawMsg(msg_t *pM, uchar **pBuf, int *piLen)
{
if(pM == NULL) {
@@ -2243,8 +2258,8 @@ char *textpri(char *pRes, size_t pResLen, int pri)
assert(pRes != NULL);
assert(pResLen > 0);
- snprintf(pRes, pResLen, "%s.%s<%d>", syslog_fac_names[LOG_FAC(pri)],
- syslog_severity_names[LOG_PRI(pri)], pri);
+ snprintf(pRes, pResLen, "%s.%s", syslog_fac_names[LOG_FAC(pri)],
+ syslog_severity_names[LOG_PRI(pri)]);
return pRes;
}
@@ -2301,6 +2316,41 @@ static uchar *getNOW(eNOWType eNow)
#undef tmpBUFSIZE /* clean up */
+/* Get a CEE-Property from libee. This function probably should be
+ * placed somewhere else, but this smells like a big restructuring
+ * useful in any case. So for the time being, I'll simply leave the
+ * function here, as the context seems good enough. -- rgerhards, 2010-12-01
+ */
+static inline void
+getCEEPropVal(msg_t *pMsg, es_str_t *propName, uchar **pRes, int *buflen, unsigned short *pbMustBeFreed)
+{
+ es_str_t *str = NULL;
+ int r;
+
+ if(*pbMustBeFreed)
+ free(*pRes);
+ *pRes = NULL;
+
+ if(pMsg->event == NULL) goto finalize_it;
+ r = ee_getEventFieldAsString(pMsg->event, propName, &str);
+
+ if(r != EE_OK) {
+ DBGPRINTF("msgGtCEEVar: libee error %d during ee_getEventFieldAsString\n", r);
+ FINALIZE;
+ }
+ *pRes = (unsigned char*) es_str2cstr(str, "#000");
+ es_deleteStr(str);
+ *buflen = (int) ustrlen(*pRes);
+ *pbMustBeFreed = 1;
+
+finalize_it:
+ if(*pRes == NULL) {
+ /* could not find any value, so set it to empty */
+ *pRes = (unsigned char*)"";
+ *pbMustBeFreed = 0;
+ }
+}
+
/* This function returns a string-representation of the
* requested message property. This is a generic function used
* to abstract properties so that these can be easier
@@ -2343,7 +2393,7 @@ static uchar *getNOW(eNOWType eNow)
*pPropLen = sizeof("**OUT OF MEMORY**") - 1; \
return(UCHAR_CONSTANT("**OUT OF MEMORY**"));}
uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
- propid_t propID, size_t *pPropLen,
+ propid_t propid, es_str_t *propName, size_t *pPropLen,
unsigned short *pbMustBeFreed)
{
uchar *pRes; /* result pointer */
@@ -2352,6 +2402,7 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
uchar *pBuf;
int iLen;
short iOffs;
+ es_str_t *str; /* for CEE handling, temp. string */
BEGINfunc
assert(pMsg != NULL);
@@ -2365,7 +2416,7 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
*pbMustBeFreed = 0;
- switch(propID) {
+ switch(propid) {
case PROP_MSG:
pRes = getMSG(pMsg);
bufLen = getMSGLen(pMsg);
@@ -2498,17 +2549,43 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
case PROP_SYS_MYHOSTNAME:
pRes = glbl.GetLocalHostName();
break;
+ case PROP_CEE_ALL_JSON:
+ ee_fmtEventToJSON(pMsg->event, &str);
+ pRes = (uchar*) es_str2cstr(str, "#000");
+ es_deleteStr(str);
+ *pbMustBeFreed = 1; /* all of these functions allocate dyn. memory */
+ break;
+ case PROP_CEE:
+ getCEEPropVal(pMsg, propName, &pRes, &bufLen, pbMustBeFreed);
+ break;
case PROP_SYS_BOM:
if(*pbMustBeFreed == 1)
free(pRes);
pRes = (uchar*) "\xEF\xBB\xBF";
*pbMustBeFreed = 0;
break;
+ case PROP_SYS_UPTIME:
+ {
+ struct sysinfo s_info;
+
+ if((pRes = (uchar*) MALLOC(sizeof(uchar) * 32)) == NULL) {
+ RET_OUT_OF_MEMORY;
+ }
+ *pbMustBeFreed = 1;
+
+ if(sysinfo(&s_info) < 0) {
+ *pPropLen = sizeof("**SYSCALL FAILED**") - 1;
+ return(UCHAR_CONSTANT("**SYSCALL FAILED**"));
+ }
+
+ snprintf((char*) pRes, sizeof(uchar) * 32, "%ld", s_info.uptime);
+ }
+ break;
default:
/* there is no point in continuing, we may even otherwise render the
* error message unreadable. rgerhards, 2007-07-10
*/
- dbgprintf("invalid property id: '%d'\n", propID);
+ dbgprintf("invalid property id: '%d'\n", propid);
*pbMustBeFreed = 0;
*pPropLen = sizeof("**INVALID PROPERTY NAME**") - 1;
return UCHAR_CONSTANT("**INVALID PROPERTY NAME**");
@@ -2516,6 +2593,7 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
/* If we did not receive a template pointer, we are already done... */
if(pTpe == NULL) {
+ *pPropLen = (bufLen == -1) ? ustrlen(pRes) : bufLen;
return pRes;
}
@@ -3104,6 +3182,57 @@ dbgprintf("end prop repl, pRes='%s', len %d\n", pRes, bufLen);
}
+/* The function returns a cee variable suitable for use with RainerScript. Most importantly, this means
+ * that the value is returned in a var_t object. The var_t is constructed inside this function and
+ * MUST be freed by the caller.
+ * Note that we need to do a lot of conversions between es_str_t and cstr -- this will go away once
+ * we have moved larger parts of rsyslog to es_str_t. Acceptable for the moment, especially as we intend
+ * to rewrite the script engine as well!
+ * rgerhards, 2010-12-03
+ */
+rsRetVal
+msgGetCEEVar(msg_t *pMsg, cstr_t *propName, var_t **ppVar)
+{
+ DEFiRet;
+ var_t *pVar;
+ cstr_t *pstrProp;
+ es_str_t *str = NULL;
+ es_str_t *epropName = NULL;
+ int r;
+
+ ISOBJ_TYPE_assert(pMsg, msg);
+ ASSERT(propName != NULL);
+ ASSERT(ppVar != NULL);
+
+ /* make sure we have a var_t instance */
+ CHKiRet(var.Construct(&pVar));
+ CHKiRet(var.ConstructFinalize(pVar));
+
+ epropName = es_newStrFromBuf((char*)propName->pBuf, propName->iStrLen);
+ r = ee_getEventFieldAsString(pMsg->event, epropName, &str);
+
+ if(r != EE_OK) {
+ DBGPRINTF("msgGtCEEVar: libee error %d during ee_getEventFieldAsString\n", r);
+ CHKiRet(cstrConstruct(&pstrProp));
+ CHKiRet(cstrFinalize(pstrProp));
+ } else {
+ CHKiRet(cstrConstructFromESStr(&pstrProp, str));
+ }
+
+ /* now create a string object out of it and hand that over to the var */
+ CHKiRet(var.SetString(pVar, pstrProp));
+ es_deleteStr(str);
+
+ /* finally store var */
+ *ppVar = pVar;
+
+finalize_it:
+ if(epropName != NULL)
+ es_deleteStr(epropName);
+ RETiRet;
+}
+
+
/* The returns a message variable suitable for use with RainerScript. Most importantly, this means
* that the value is returned in a var_t object. The var_t is constructed inside this function and
* MUST be freed by the caller.
@@ -3131,7 +3260,7 @@ msgGetMsgVar(msg_t *pThis, cstr_t *pstrPropName, var_t **ppVar)
/* always call MsgGetProp() without a template specifier */
/* TODO: optimize propNameToID() call -- rgerhards, 2009-06-26 */
propNameToID(pstrPropName, &propid);
- pszProp = (uchar*) MsgGetProp(pThis, NULL, propid, &propLen, &bMustBeFreed);
+ pszProp = (uchar*) MsgGetProp(pThis, NULL, propid, NULL, &propLen, &bMustBeFreed);
/* now create a string object out of it and hand that over to the var */
CHKiRet(rsCStrConstructFromszStr(&pstrProp, pszProp));
@@ -3146,6 +3275,8 @@ finalize_it:
RETiRet;
}
+
+
/* This function can be used as a generic way to set properties.
* We have to handle a lot of legacy, so our return value is not always
* 100% correct (called functions do not always provide one, should
diff --git a/runtime/msg.h b/runtime/msg.h
index 26a07aca..01a1e059 100644
--- a/runtime/msg.h
+++ b/runtime/msg.h
@@ -29,10 +29,12 @@
#define MSG_H_INCLUDED 1
#include <pthread.h>
+#include <libestr.h>
#include "obj.h"
#include "syslogd-types.h"
#include "template.h"
#include "atomic.h"
+#include "libee/libee.h"
/* rgerhards 2004-11-08: The following structure represents a
@@ -106,6 +108,7 @@ struct msg {
it obviously is solved in way or another...). */
struct syslogTime tRcvdAt;/* time the message entered this program */
struct syslogTime tTIMESTAMP;/* (parsed) value of the timestamp */
+ struct ee_event *event; /**< libee event */
/* some fixed-size buffers to save malloc()/free() for frequently used fields (from the default templates) */
uchar szRawMsg[CONF_RAWMSG_BUFSIZE]; /* most messages are small, and these are stored here (without malloc/free!) */
uchar szHOSTNAME[CONF_HOSTNAME_BUFSIZE];
@@ -163,7 +166,8 @@ void MsgSetRawMsgWOSize(msg_t *pMsg, char* pszRawMsg);
void MsgSetRawMsg(msg_t *pMsg, char* pszRawMsg, size_t lenMsg);
rsRetVal MsgReplaceMSG(msg_t *pThis, uchar* pszMSG, int lenMSG);
uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
- propid_t propID, size_t *pPropLen, unsigned short *pbMustBeFreed);
+ propid_t propid, es_str_t *propName,
+ size_t *pPropLen, unsigned short *pbMustBeFreed);
char *textpri(char *pRes, size_t pResLen, int pri);
rsRetVal msgGetMsgVar(msg_t *pThis, cstr_t *pstrPropName, var_t **ppVar);
rsRetVal MsgEnableThreadSafety(void);
@@ -171,6 +175,8 @@ uchar *getRcvFrom(msg_t *pM);
void getTAG(msg_t *pM, uchar **ppBuf, int *piLen);
char *getTimeReported(msg_t *pM, enum tplFormatTypes eFmt);
char *getPRI(msg_t *pMsg);
+void getRawMsg(msg_t *pM, uchar **pBuf, int *piLen);
+rsRetVal msgGetCEEVar(msg_t *pThis, cstr_t *propName, var_t **ppVar);
/* TODO: remove these five (so far used in action.c) */
diff --git a/runtime/netstrm.c b/runtime/netstrm.c
index 3658006f..a6f840a5 100644
--- a/runtime/netstrm.c
+++ b/runtime/netstrm.c
@@ -64,6 +64,7 @@ ENDobjConstruct(netstrm)
/* destructor for the netstrm object */
BEGINobjDestruct(netstrm) /* be sure to specify the object type also in END and CODESTART macros! */
CODESTARTobjDestruct(netstrm)
+//printf("destruct driver data %p\n", pThis->pDrvrData);
if(pThis->pDrvrData != NULL)
iRet = pThis->Drvr.Destruct(&pThis->pDrvrData);
ENDobjDestruct(netstrm)
@@ -169,6 +170,7 @@ Rcv(netstrm_t *pThis, uchar *pBuf, ssize_t *pLenBuf)
{
DEFiRet;
ISOBJ_TYPE_assert(pThis, netstrm);
+//printf("Rcv %p\n", pThis);
iRet = pThis->Drvr.Rcv(pThis->pDrvrData, pBuf, pLenBuf);
RETiRet;
}
diff --git a/runtime/netstrms.c b/runtime/netstrms.c
index ea2dd9f3..0122064d 100644
--- a/runtime/netstrms.c
+++ b/runtime/netstrms.c
@@ -32,7 +32,6 @@
#include "rsyslog.h"
#include "module-template.h"
#include "obj.h"
-//#include "errmsg.h"
#include "nsd.h"
#include "netstrm.h"
#include "nssel.h"
diff --git a/runtime/nsd.h b/runtime/nsd.h
index d1f164ec..ab64c443 100644
--- a/runtime/nsd.h
+++ b/runtime/nsd.h
@@ -27,6 +27,16 @@
#include <sys/socket.h>
+/**
+ * The following structure is a set of descriptors that need to be processed.
+ * This set will be the result of the epoll call and be used
+ * in the actual request processing stage. -- rgerhards, 2011-01-24
+ */
+struct nsd_epworkset_s {
+ int id;
+ void *pUsr;
+};
+
enum nsdsel_waitOp_e {
NSDSEL_RD = 1,
NSDSEL_WR = 2,
@@ -90,7 +100,7 @@ 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);
+ rsRetVal (*Wait)(nsdpoll_t *pNsdpoll, int timeout, int *numReady, nsd_epworkset_t workset[]);
ENDinterface(nsdpoll)
#define nsdpollCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */
diff --git a/runtime/nsd_gtls.c b/runtime/nsd_gtls.c
index 036e8290..0b1ab4b8 100644
--- a/runtime/nsd_gtls.c
+++ b/runtime/nsd_gtls.c
@@ -50,7 +50,6 @@
#include "nsd_gtls.h"
/* things to move to some better place/functionality - TODO */
-#define DH_BITS 1024
#define CRLFILE "crl.pem"
@@ -82,7 +81,6 @@ static pthread_mutex_t mutGtlsStrerror; /**< a mutex protecting the potentially
/* ------------------------------ GnuTLS specifics ------------------------------ */
static gnutls_certificate_credentials xcred;
-static gnutls_dh_params dh_params;
#ifdef DEBUG
#if 0 /* uncomment, if needed some time again -- DEV Debug only */
@@ -614,7 +612,6 @@ gtlsInitSession(nsd_gtls_t *pThis)
/* request client certificate if any. */
gnutls_certificate_server_set_request( session, GNUTLS_CERT_REQUEST);
- gnutls_dh_set_prime_bits(session, DH_BITS);
pThis->sess = session;
@@ -623,23 +620,6 @@ finalize_it:
}
-static rsRetVal
-generate_dh_params(void)
-{
- int gnuRet;
- DEFiRet;
- /* Generate Diffie Hellman parameters - for use with DHE
- * kx algorithms. These should be discarded and regenerated
- * once a day, once a week or once a month. Depending on the
- * security requirements.
- */
- CHKgnutls(gnutls_dh_params_init( &dh_params));
- CHKgnutls(gnutls_dh_params_generate2( dh_params, DH_BITS));
-finalize_it:
- RETiRet;
-}
-
-
/* set up all global things that are needed for server operations
* rgerhards, 2008-04-30
*/
@@ -653,8 +633,6 @@ gtlsGlblInitLstn(void)
* considered legacy. -- rgerhards, 2008-05-05
*/
/*CHKgnutls(gnutls_certificate_set_x509_crl_file(xcred, CRLFILE, GNUTLS_X509_FMT_PEM));*/
- CHKiRet(generate_dh_params());
- gnutls_certificate_set_dh_params(xcred, dh_params); /* this is void */
bGlblSrvrInitDone = 1; /* we are all set now */
/* now we need to add our certificate */
@@ -1426,6 +1404,10 @@ AcceptConnReq(nsd_t *pNsd, nsd_t **ppNew)
/* we got a handshake, now check authorization */
CHKiRet(gtlsChkPeerAuth(pNew));
} else {
+ uchar *pGnuErr = gtlsStrerror(gnuRet);
+ errmsg.LogError(0, RS_RET_TLS_HANDSHAKE_ERR,
+ "gnutls returned error on handshake: %s\n", pGnuErr);
+ free(pGnuErr);
ABORT_FINALIZE(RS_RET_TLS_HANDSHAKE_ERR);
}
diff --git a/runtime/nsdpoll_ptcp.c b/runtime/nsdpoll_ptcp.c
index ef9c37a3..8c90d7fd 100644
--- a/runtime/nsdpoll_ptcp.c
+++ b/runtime/nsdpoll_ptcp.c
@@ -71,13 +71,16 @@ addEvent(nsdpoll_ptcp_t *pThis, int id, void *pUsr, int mode, nsd_ptcp_t *pSock,
pNew->pUsr = pUsr;
pNew->pSock = pSock;
pNew->event.events = 0; /* TODO: at some time we should be able to use EPOLLET */
+ //pNew->event.events = EPOLLET;
if(mode & NSDPOLL_IN)
pNew->event.events |= EPOLLIN;
if(mode & NSDPOLL_OUT)
pNew->event.events |= EPOLLOUT;
pNew->event.data.u64 = (uint64) pNew;
+ pthread_mutex_lock(&pThis->mutEvtLst);
pNew->pNext = pThis->pRoot;
pThis->pRoot = pNew;
+ pthread_mutex_unlock(&pThis->mutEvtLst);
*pEvtLst = pNew;
finalize_it:
@@ -94,6 +97,7 @@ unlinkEvent(nsdpoll_ptcp_t *pThis, int id, void *pUsr, nsdpoll_epollevt_lst_t **
nsdpoll_epollevt_lst_t *pPrev = NULL;
DEFiRet;
+ pthread_mutex_lock(&pThis->mutEvtLst);
pEvtLst = pThis->pRoot;
while(pEvtLst != NULL && !(pEvtLst->id == id && pEvtLst->pUsr == pUsr)) {
pPrev = pEvtLst;
@@ -111,6 +115,7 @@ unlinkEvent(nsdpoll_ptcp_t *pThis, int id, void *pUsr, nsdpoll_epollevt_lst_t **
pPrev->pNext = pEvtLst->pNext;
finalize_it:
+ pthread_mutex_unlock(&pThis->mutEvtLst);
RETiRet;
}
@@ -147,13 +152,27 @@ BEGINobjConstruct(nsdpoll_ptcp) /* be sure to specify the object type also in EN
DBGPRINTF("epoll_create1() could not create fd\n");
ABORT_FINALIZE(RS_RET_IO_ERROR);
}
+ pthread_mutex_init(&pThis->mutEvtLst, NULL);
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! */
+ nsdpoll_epollevt_lst_t *node;
+ nsdpoll_epollevt_lst_t *nextnode;
CODESTARTobjDestruct(nsdpoll_ptcp)
+ /* we check if the epoll list still holds entries. This may happen, but
+ * is a bit unusual.
+ */
+ if(pThis->pRoot != NULL) {
+ for(node = pThis->pRoot ; node != NULL ; node = nextnode) {
+ nextnode = node->pNext;
+ dbgprintf("nsdpoll_ptcp destruct, need to destruct node %p\n", node);
+ delEvent(&node);
+ }
+ }
+ pthread_mutex_destroy(&pThis->mutEvtLst);
ENDobjDestruct(nsdpoll_ptcp)
@@ -202,23 +221,25 @@ finalize_it:
/* 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.
+ * numEntries contains the maximum number of entries on entry and the actual
+ * number of entries actually read on exit.
* rgerhards, 2009-11-18
*/
static rsRetVal
-Wait(nsdpoll_t *pNsdpoll, int timeout, int *idRdy, void **ppUsr) {
+Wait(nsdpoll_t *pNsdpoll, int timeout, int *numEntries, nsd_epworkset_t workset[]) {
nsdpoll_ptcp_t *pThis = (nsdpoll_ptcp_t*) pNsdpoll;
nsdpoll_epollevt_lst_t *pOurEvt;
- struct epoll_event event;
+ struct epoll_event event[128];
int nfds;
+ int i;
DEFiRet;
- assert(idRdy != NULL);
- assert(ppUsr != NULL);
+ assert(workset != NULL);
- nfds = epoll_wait(pThis->efd, &event, 1, timeout);
+ if(*numEntries > 128)
+ *numEntries = 128;
+ DBGPRINTF("doing epoll_wait for max %d events\n", *numEntries);
+ nfds = epoll_wait(pThis->efd, event, *numEntries, timeout);
if(nfds == -1) {
if(errno == EINTR) {
ABORT_FINALIZE(RS_RET_EINTR);
@@ -230,10 +251,15 @@ Wait(nsdpoll_t *pNsdpoll, int timeout, int *idRdy, void **ppUsr) {
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;
+ /* we got valid events, so tell the caller... */
+dbgprintf("epoll returned %d entries\n", nfds);
+ for(i = 0 ; i < nfds ; ++i) {
+ pOurEvt = (nsdpoll_epollevt_lst_t*) event[i].data.u64;
+ workset[i].id = pOurEvt->id;
+ workset[i].pUsr = pOurEvt->pUsr;
+dbgprintf("epoll push ppusr[%d]: %p\n", i, pOurEvt->pUsr);
+ }
+ *numEntries = nfds;
finalize_it:
RETiRet;
diff --git a/runtime/nsdpoll_ptcp.h b/runtime/nsdpoll_ptcp.h
index cea2823d..dfefad1b 100644
--- a/runtime/nsdpoll_ptcp.h
+++ b/runtime/nsdpoll_ptcp.h
@@ -49,6 +49,7 @@ 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 */
+ pthread_mutex_t mutEvtLst;
};
/* interface is defined in nsd.h, we just implement it! */
diff --git a/runtime/nspoll.c b/runtime/nspoll.c
index 64927280..a936b255 100644
--- a/runtime/nspoll.c
+++ b/runtime/nspoll.c
@@ -129,11 +129,11 @@ finalize_it:
/* Carries out the actual wait (all done in lower layers)
*/
static rsRetVal
-Wait(nspoll_t *pThis, int timeout, int *idRdy, void **ppUsr) {
+Wait(nspoll_t *pThis, int timeout, int *numEntries, nsd_epworkset_t workset[]) {
DEFiRet;
ISOBJ_TYPE_assert(pThis, nspoll);
- assert(idRdy != NULL);
- iRet = pThis->Drvr.Wait(pThis->pDrvrData, timeout, idRdy, ppUsr);
+ assert(workset != NULL);
+ iRet = pThis->Drvr.Wait(pThis->pDrvrData, timeout, numEntries, workset);
RETiRet;
}
diff --git a/runtime/nspoll.h b/runtime/nspoll.h
index a77759c0..037f6c38 100644
--- a/runtime/nspoll.h
+++ b/runtime/nspoll.h
@@ -50,11 +50,12 @@ 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 (*Wait)(nspoll_t *pNsdpoll, int timeout, int *numEntries, nsd_epworkset_t workset[]);
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! */
+#define nspollCURR_IF_VERSION 2 /* increment whenever you change the interface structure! */
+/* interface change in v2 is that wait supports multiple return objects */
/* prototypes */
PROTOTYPEObj(nspoll);
diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h
index 55df4d11..baadf322 100644
--- a/runtime/rsyslog.h
+++ b/runtime/rsyslog.h
@@ -137,7 +137,10 @@ typedef uintTiny propid_t;
#define PROP_SYS_QHOUR 156
#define PROP_SYS_MINUTE 157
#define PROP_SYS_MYHOSTNAME 158
+#define PROP_CEE 200
+#define PROP_CEE_ALL_JSON 201
#define PROP_SYS_BOM 159
+#define PROP_SYS_UPTIME 160
/* The error codes below are orginally "borrowed" from
@@ -332,6 +335,11 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth
RS_RET_TIMEOUT = -2164, /**< timeout occured during operation */
RS_RET_RCV_ERR = -2165, /**< error occured during socket rcv operation */
RS_RET_NO_SOCK_CONFIGURED = -2166, /**< no socket (name) was configured where one is required */
+ RS_RET_CONF_NOT_GLBL = -2167, /**< $Begin not in global scope */
+ RS_RET_CONF_IN_GLBL = -2168, /**< $End when in global scope */
+ RS_RET_CONF_INVLD_END = -2169, /**< $End for wrong conf object (probably nesting error) */
+ RS_RET_CONF_INVLD_SCOPE = -2170,/**< config statement not valid in current scope (e.g. global stmt in action block) */
+ RS_RET_CONF_END_NO_ACT = -2171, /**< end of action block, but no actual action specified */
RS_RET_NO_LSTN_DEFINED = -2172, /**< no listener defined (e.g. inside an input module) */
RS_RET_EPOLL_CR_FAILED = -2173, /**< epoll_create() failed */
RS_RET_EPOLL_CTL_FAILED = -2174, /**< epoll_ctl() failed */
@@ -346,6 +354,10 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth
RS_RET_OUTDATED_STMT = -2184, /**< some outdated statement/functionality is being used in conf file */
RS_RET_MISSING_WHITESPACE = -2185, /**< whitespace is missing in some config construct */
+ RS_RET_INVLD_CONF_OBJ= -2200, /**< invalid config object (e.g. $Begin conf statement) */
+ RS_RET_ERR_LIBEE_INIT = -2201, /**< cannot obtain libee ctx */
+ RS_RET_ERR_LIBLOGNORM_INIT = -2202,/**< cannot obtain liblognorm ctx */
+ RS_RET_ERR_LIBLOGNORM_SAMPDB_LOAD = -2203,/**< liblognorm sampledb load failed */
RS_RET_CONF_RQRD_PARAM_MISSING = -2208,/**< required parameter in config object is missing */
/* RainerScript error messages (range 1000.. 1999) */
RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */
@@ -471,6 +483,13 @@ rsRetVal rsrtExit(void);
int rsrtIsInit(void);
rsRetVal rsrtSetErrLogger(rsRetVal (*errLogger)(int, uchar*));
+/* this define below is (later) intended to be used to implement empty
+ * structs. TODO: check if compilers supports this and, if not, define
+ * a dummy variable. This requires review of where in code empty structs
+ * are already defined. -- rgerhards, 2010-07-26
+ */
+#define EMPTY_STRUCT
+
#endif /* multi-include protection */
/* vim:set ai:
*/
diff --git a/runtime/rule.c b/runtime/rule.c
index b27ddb5f..6f25233e 100644
--- a/runtime/rule.c
+++ b/runtime/rule.c
@@ -68,6 +68,12 @@ getFIOPName(unsigned iFIOP)
case FIOP_REGEX:
pRet = "regex";
break;
+ case FIOP_EREREGEX:
+ pRet = "ereregex";
+ break;
+ case FIOP_ISEMPTY:
+ pRet = "isempty";
+ break;
default:
pRet = "NOP";
break;
@@ -188,7 +194,8 @@ shouldProcessThisMessage(rule_t *pRule, msg_t *pMsg, sbool *bProcessMsg)
bRet = (pResult->val.num) ? 1 : 0;
} else {
assert(pRule->f_filter_type == FILTER_PROP); /* assert() just in case... */
- pszPropVal = MsgGetProp(pMsg, NULL, pRule->f_filterData.prop.propID, &propLen, &pbMustBeFreed);
+ pszPropVal = MsgGetProp(pMsg, NULL, pRule->f_filterData.prop.propID,
+ pRule->f_filterData.prop.propName, &propLen, &pbMustBeFreed);
/* Now do the compares (short list currently ;)) */
switch(pRule->f_filterData.prop.operation ) {
@@ -196,6 +203,10 @@ shouldProcessThisMessage(rule_t *pRule, msg_t *pMsg, sbool *bProcessMsg)
if(rsCStrLocateInSzStr(pRule->f_filterData.prop.pCSCompValue, (uchar*) pszPropVal) != -1)
bRet = 1;
break;
+ case FIOP_ISEMPTY:
+ if(propLen == 0)
+ bRet = 1; /* process message! */
+ break;
case FIOP_ISEQUAL:
if(rsCStrSzStrCmp(pRule->f_filterData.prop.pCSCompValue,
pszPropVal, ustrlen(pszPropVal)) == 0)
@@ -228,14 +239,28 @@ shouldProcessThisMessage(rule_t *pRule, msg_t *pMsg, sbool *bProcessMsg)
bRet = (bRet == 1) ? 0 : 1;
if(Debug) {
- dbgprintf("Filter: check for property '%s' (value '%s') ",
- propIDToName(pRule->f_filterData.prop.propID), pszPropVal);
+ char *cstr;
+ if(pRule->f_filterData.prop.propID == PROP_CEE) {
+ cstr = es_str2cstr(pRule->f_filterData.prop.propName, NULL);
+ dbgprintf("Filter: check for CEE property '%s' (value '%s') ",
+ cstr, pszPropVal);
+ free(cstr);
+ } else {
+ dbgprintf("Filter: check for property '%s' (value '%s') ",
+ propIDToName(pRule->f_filterData.prop.propID), pszPropVal);
+ }
if(pRule->f_filterData.prop.isNegated)
dbgprintf("NOT ");
- dbgprintf("%s '%s': %s\n",
- getFIOPName(pRule->f_filterData.prop.operation),
- rsCStrGetSzStrNoNULL(pRule->f_filterData.prop.pCSCompValue),
- bRet ? "TRUE" : "FALSE");
+ if(pRule->f_filterData.prop.operation == FIOP_ISEMPTY) {
+ dbgprintf("%s : %s\n",
+ getFIOPName(pRule->f_filterData.prop.operation),
+ bRet ? "TRUE" : "FALSE");
+ } else {
+ dbgprintf("%s '%s': %s\n",
+ getFIOPName(pRule->f_filterData.prop.operation),
+ rsCStrGetSzStrNoNULL(pRule->f_filterData.prop.pCSCompValue),
+ bRet ? "TRUE" : "FALSE");
+ }
}
/* cleanup */
@@ -327,6 +352,8 @@ CODESTARTobjDestruct(rule)
rsCStrDestruct(&pThis->f_filterData.prop.pCSCompValue);
if(pThis->f_filterData.prop.regex_cache != NULL)
rsCStrRegexDestruct(&pThis->f_filterData.prop.regex_cache);
+ if(pThis->f_filterData.prop.propName != NULL)
+ es_deleteStr(pThis->f_filterData.prop.propName);
} else if(pThis->f_filter_type == FILTER_EXPR) {
if(pThis->f_filterData.f_expr != NULL)
expr.Destruct(&pThis->f_filterData.f_expr);
@@ -371,6 +398,7 @@ DEFFUNC_llExecFunc(dbgPrintInitInfoAction)
/* debugprint for the rule object */
BEGINobjDebugPrint(rule) /* be sure to specify the object type also in END and CODESTART macros! */
int i;
+ char *cstr;
CODESTARTobjDebugPrint(rule)
dbgoprint((obj_t*) pThis, "rsyslog rule:\n");
if(pThis->pCSProgNameComp != NULL)
@@ -391,12 +419,19 @@ CODESTARTobjDebugPrint(rule)
} else {
dbgprintf("PROPERTY-BASED Filter:\n");
dbgprintf("\tProperty.: '%s'\n", propIDToName(pThis->f_filterData.prop.propID));
+ if(pThis->f_filterData.prop.propName != NULL) {
+ cstr = es_str2cstr(pThis->f_filterData.prop.propName, NULL);
+ dbgprintf("\tCEE-Prop.: '%s'\n", cstr);
+ free(cstr);
+ }
dbgprintf("\tOperation: ");
if(pThis->f_filterData.prop.isNegated)
dbgprintf("NOT ");
dbgprintf("'%s'\n", getFIOPName(pThis->f_filterData.prop.operation));
- dbgprintf("\tValue....: '%s'\n",
- rsCStrGetSzStrNoNULL(pThis->f_filterData.prop.pCSCompValue));
+ if(pThis->f_filterData.prop.pCSCompValue != NULL) {
+ dbgprintf("\tValue....: '%s'\n",
+ rsCStrGetSzStrNoNULL(pThis->f_filterData.prop.pCSCompValue));
+ }
dbgprintf("\tAction...: ");
}
diff --git a/runtime/rule.h b/runtime/rule.h
index 2b585879..55b039ef 100644
--- a/runtime/rule.h
+++ b/runtime/rule.h
@@ -23,6 +23,7 @@
#ifndef INCLUDED_RULE_H
#define INCLUDED_RULE_H
+#include "libestr.h"
#include "linkedlist.h"
#include "regexp.h"
#include "expr.h"
@@ -47,6 +48,7 @@ struct rule_s {
cstr_t *pCSCompValue; /* value to "compare" against */
sbool isNegated;
propid_t propID; /* ID of the requested property */
+ es_str_t *propName; /* name of property for CEE-based filters */
} prop;
expr_t *f_expr; /* expression object */
} f_filterData;
diff --git a/runtime/stringbuf.c b/runtime/stringbuf.c
index e11d0e3b..e7fd72c2 100644
--- a/runtime/stringbuf.c
+++ b/runtime/stringbuf.c
@@ -33,6 +33,7 @@
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
+#include <libestr.h>
#include "rsyslog.h"
#include "stringbuf.h"
#include "srUtils.h"
@@ -102,6 +103,34 @@ finalize_it:
RETiRet;
}
+
+/* construct from es_str_t string
+ * rgerhards 2010-12-03
+ */
+rsRetVal cstrConstructFromESStr(cstr_t **ppThis, es_str_t *str)
+{
+ DEFiRet;
+ cstr_t *pThis;
+
+ assert(ppThis != NULL);
+
+ CHKiRet(rsCStrConstruct(&pThis));
+
+ pThis->iBufSize = pThis->iStrLen = es_strlen(str);
+ if((pThis->pBuf = (uchar*) MALLOC(sizeof(uchar) * pThis->iStrLen)) == NULL) {
+ RSFREEOBJ(pThis);
+ ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
+ }
+
+ /* we do NOT need to copy the \0! */
+ memcpy(pThis->pBuf, es_getBufAddr(str), pThis->iStrLen);
+
+ *ppThis = pThis;
+
+finalize_it:
+ RETiRet;
+}
+
/* construct from CStr object. only the counted string is
* copied, not the szString.
* rgerhards 2005-10-18
diff --git a/runtime/stringbuf.h b/runtime/stringbuf.h
index b6e22977..bba004a0 100644
--- a/runtime/stringbuf.h
+++ b/runtime/stringbuf.h
@@ -33,6 +33,7 @@
#define _STRINGBUF_H_INCLUDED__ 1
#include <assert.h>
+#include <libestr.h>
/**
* The dynamic string buffer object.
@@ -54,6 +55,7 @@ typedef struct cstr_s
*/
rsRetVal cstrConstruct(cstr_t **ppThis);
#define rsCStrConstruct(x) cstrConstruct((x))
+rsRetVal cstrConstructFromESStr(cstr_t **ppThis, es_str_t *str);
rsRetVal rsCStrConstructFromszStr(cstr_t **ppThis, uchar *sz);
rsRetVal rsCStrConstructFromCStr(cstr_t **ppThis, cstr_t *pFrom);
diff --git a/runtime/typedefs.h b/runtime/typedefs.h
index d3da7699..b6cfbd57 100644
--- a/runtime/typedefs.h
+++ b/runtime/typedefs.h
@@ -79,6 +79,7 @@ typedef struct parserList_s parserList_t;
typedef struct strgen_s strgen_t;
typedef struct strgenList_s strgenList_t;
typedef struct statsobj_s statsobj_t;
+typedef struct nsd_epworkset_s nsd_epworkset_t;
typedef rsRetVal (*prsf_t)(struct vmstk_s*, int); /* pointer to a RainerScript function */
typedef uint64 qDeqID; /* queue Dequeue order ID. 32 bits is considered dangerously few */
@@ -127,9 +128,41 @@ typedef enum {
FIOP_ISEQUAL = 2, /* is (exactly) equal? */
FIOP_STARTSWITH = 3, /* starts with a string? */
FIOP_REGEX = 4, /* matches a (BRE) regular expression? */
- FIOP_EREREGEX = 5 /* matches a ERE regular expression? */
+ FIOP_EREREGEX = 5, /* matches a ERE regular expression? */
+ FIOP_ISEMPTY = 6 /* string empty <=> strlen(s) == 0 ?*/
} fiop_t;
+/* types of configuration handlers
+ */
+typedef enum cslCmdHdlrType {
+ eCmdHdlrInvalid = 0, /* invalid handler type - indicates a coding error */
+ eCmdHdlrCustomHandler, /* custom handler, just call handler function */
+ eCmdHdlrUID,
+ eCmdHdlrGID,
+ eCmdHdlrBinary,
+ eCmdHdlrFileCreateMode,
+ eCmdHdlrInt,
+ eCmdHdlrSize,
+ eCmdHdlrGetChar,
+ eCmdHdlrFacility,
+ eCmdHdlrSeverity,
+ eCmdHdlrGetWord
+} ecslCmdHdrlType;
+
+
+/* the next type describes $Begin .. $End block object types
+ */
+typedef enum cslConfObjType {
+ eConfObjGlobal = 0, /* global directives */
+ eConfObjAction, /* action-specific directives */
+ /* now come states that indicate that we wait for a block-end. These are
+ * states that permit us to do some safety checks and they hopefully ease
+ * migration to a "real" parser/grammar.
+ */
+ eConfObjActionWaitEnd,
+ eConfObjAlways /* always valid, very special case (guess $End only!) */
+} ecslConfObjType;
+
/* multi-submit support.
* This is done via a simple data structure, which holds the number of elements
diff --git a/runtime/var.h b/runtime/var.h
index 384463e0..64571bad 100644
--- a/runtime/var.h
+++ b/runtime/var.h
@@ -38,6 +38,7 @@ typedef struct var_s {
varType_t varType;
union {
number_t num;
+ es_str_t *str;
cstr_t *pStr;
syslogTime_t vSyslogTime;
diff --git a/runtime/vm.c b/runtime/vm.c
index 84ba4bcf..bbc8d346 100644
--- a/runtime/vm.c
+++ b/runtime/vm.c
@@ -448,6 +448,7 @@ BEGINop(PUSHMSGVAR) /* remember to set the instruction also in the ENDop macro!
var_t *pVal; /* the value to push */
cstr_t *pstrVal;
CODESTARTop(PUSHMSGVAR)
+dbgprintf("XXX: pushMSGVAR, var '%s'\n", rsCStrGetSzStr(pOp->operand.pVar->val.pStr));
if(pThis->pMsg == NULL) {
/* TODO: flag an error message! As a work-around, we permit
* execution to continue here with an empty string
@@ -468,6 +469,31 @@ finalize_it:
ENDop(PUSHMSGVAR)
+BEGINop(PUSHCEEVAR) /* remember to set the instruction also in the ENDop macro! */
+ var_t *pVal; /* the value to push */
+ cstr_t *pstrVal;
+CODESTARTop(PUSHCEEVAR)
+dbgprintf("XXX: pushCEEVAR, var '%s'\n", rsCStrGetSzStr(pOp->operand.pVar->val.pStr));
+ if(pThis->pMsg == NULL) {
+ /* TODO: flag an error message! As a work-around, we permit
+ * execution to continue here with an empty string
+ */
+ CHKiRet(var.Construct(&pVal));
+ CHKiRet(var.ConstructFinalize(pVal));
+ CHKiRet(rsCStrConstructFromszStr(&pstrVal, (uchar*)""));
+ CHKiRet(var.SetString(pVal, pstrVal));
+ } else {
+ /* we have a message, so pull value from there */
+ CHKiRet(msgGetCEEVar(pThis->pMsg, pOp->operand.pVar->val.pStr, &pVal));
+ }
+
+ /* if we reach this point, we have a valid pVal and can push it */
+ vmstk.Push(pThis->pStk, pVal);
+dbgprintf("XXX: pushCEEVAR, result '%s'\n", rsCStrGetSzStr(pVal->val.pStr));
+finalize_it:
+ENDop(PUSHCEEVAR)
+
+
BEGINop(PUSHSYSVAR) /* remember to set the instruction also in the ENDop macro! */
var_t *pVal; /* the value to push */
CODESTARTop(PUSHSYSVAR)
@@ -696,6 +722,7 @@ execProg(vm_t *pThis, vmprg_t *pProg)
doOP(NOT);
doOP(PUSHCONSTANT);
doOP(PUSHMSGVAR);
+ doOP(PUSHCEEVAR);
doOP(PUSHSYSVAR);
doOP(STRADD);
doOP(PLUS);
diff --git a/runtime/vmop.h b/runtime/vmop.h
index 68b173ab..591ae29d 100644
--- a/runtime/vmop.h
+++ b/runtime/vmop.h
@@ -57,6 +57,7 @@ typedef enum { /* do NOT start at 0 to detect uninitialized types after calloc(
opcode_PUSHSYSVAR = 1001, /* requires var operand */
opcode_PUSHMSGVAR = 1002, /* requires var operand */
opcode_PUSHCONSTANT = 1003, /* requires var operand */
+ opcode_PUSHCEEVAR = 1004, /* requires var operand */
opcode_UNARY_MINUS = 1010,
opcode_FUNC_CALL = 1012,
opcode_END_PROG = 2000
diff --git a/tcpclt.c b/tcpclt.c
index 5a2eea33..af3dcf23 100644
--- a/tcpclt.c
+++ b/tcpclt.c
@@ -307,7 +307,7 @@ Send(tcpclt_t *pThis, void *pData, char *msg, size_t len)
CHKiRet(pThis->initFunc(pData));
iRet = pThis->sendFunc(pData, msg, len);
- if(iRet == RS_RET_OK) {
+ if(iRet == RS_RET_OK || iRet == RS_RET_DEFER_COMMIT || iRet == RS_RET_PREVIOUS_COMMITTED) {
/* we are done, we also use this as indication that the previous
* message was succesfully received (it's not always the case, but its at
* least our best shot at it -- rgerhards, 2008-03-12
diff --git a/tcps_sess.c b/tcps_sess.c
index 15423cc8..92026079 100644
--- a/tcps_sess.c
+++ b/tcps_sess.c
@@ -95,6 +95,7 @@ finalize_it:
/* destructor for the tcps_sess object */
BEGINobjDestruct(tcps_sess) /* be sure to specify the object type also in END and CODESTART macros! */
CODESTARTobjDestruct(tcps_sess)
+//printf("sess %p destruct, pStrm %p\n", pThis, pThis->pStrm);
if(pThis->pStrm != NULL)
netstrm.Destruct(&pThis->pStrm);
@@ -253,7 +254,8 @@ defaultDoSubmitMessage(tcps_sess_t *pThis, struct syslogTime *stTime, time_t ttG
CHKiRet(msgConstructWithTime(&pMsg, stTime, ttGenTime));
MsgSetRawMsg(pMsg, (char*)pThis->pMsg, pThis->iMsg);
MsgSetInputName(pMsg, pThis->pLstnInfo->pInputName);
- MsgSetFlowControlType(pMsg, eFLOWCTL_LIGHT_DELAY);
+ MsgSetFlowControlType(pMsg, pThis->pSrv->bUseFlowControl
+ ? eFLOWCTL_LIGHT_DELAY : eFLOWCTL_NO_DELAY);
pMsg->msgFlags = NEEDS_PARSING | PARSE_HOSTNAME;
MsgSetRcvFrom(pMsg, pThis->fromHost);
CHKiRet(MsgSetRcvFromIP(pMsg, pThis->fromHostIP));
@@ -337,6 +339,7 @@ Close(tcps_sess_t *pThis)
{
DEFiRet;
+//printf("sess %p close\n", pThis);
ISOBJ_TYPE_assert(pThis, tcps_sess);
netstrm.Destruct(&pThis->pStrm);
if(pThis->fromHost != NULL) {
@@ -466,6 +469,7 @@ DataRcvd(tcps_sess_t *pThis, char *pData, size_t iLen)
char *pEnd;
DEFiRet;
+//printf("DataRcvd: %p\n", pThis);
ISOBJ_TYPE_assert(pThis, tcps_sess);
assert(pData != NULL);
assert(iLen > 0);
diff --git a/tcpsrv.c b/tcpsrv.c
index 95c45780..5d68dc3c 100644
--- a/tcpsrv.c
+++ b/tcpsrv.c
@@ -50,6 +50,7 @@
#include <ctype.h>
#include <netinet/in.h>
#include <netdb.h>
+#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#if HAVE_FCNTL_H
@@ -73,6 +74,7 @@
#include "ruleset.h"
#include "unicode-helper.h"
+
MODULE_TYPE_LIB
MODULE_TYPE_NOKEEP
@@ -95,6 +97,23 @@ DEFobjCurrIf(nspoll)
DEFobjCurrIf(prop)
+/* The following structure controls the worker threads. Global data is
+ * needed for their access.
+ */
+static struct wrkrInfo_s {
+ pthread_t tid; /* the worker's thread ID */
+ pthread_cond_t run;
+ int idx;
+ tcpsrv_t *pSrv; /* pSrv == NULL -> idle */
+ nspoll_t *pPoll;
+ void *pUsr;
+ long long unsigned numCalled; /* how often was this called */
+} wrkrInfo[4];
+static pthread_mutex_t wrkrMut;
+static pthread_cond_t wrkrIdle;
+static int wrkrMax = 4;
+static int wrkrRunning;
+
/* add new listener port to listener port list
* rgerhards, 2009-05-21
*/
@@ -514,7 +533,9 @@ doReceive(tcpsrv_t *pThis, tcps_sess_t **ppSess, nspoll_t *pPoll)
errmsg.LogError(0, RS_RET_PEER_CLOSED_CONN, "Netstream session %p closed by remote peer %s.\n",
(*ppSess)->pStrm, pszPeer);
}
+ //pthread_mutex_lock(&mut);
CHKiRet(closeSess(pThis, ppSess, pPoll));
+ //pthread_mutex_unlock(&mut);
break;
case RS_RET_RETRY:
/* we simply ignore retry - this is not an error, but we also have not received anything */
@@ -543,6 +564,133 @@ finalize_it:
RETiRet;
}
+/* process a single workset item
+ */
+static inline rsRetVal
+processWorksetItem(tcpsrv_t *pThis, nspoll_t *pPoll, int idx, void *pUsr)
+{
+ tcps_sess_t *pNewSess;
+ DEFiRet;
+
+ dbgprintf("tcpsrv: processing item %d, pUsr %p\n", idx, pUsr);
+ if(pUsr == pThis->ppLstn) {
+ DBGPRINTF("New connect on NSD %p.\n", pThis->ppLstn[idx]);
+ iRet = SessAccept(pThis, pThis->ppLstnPort[idx], &pNewSess, pThis->ppLstn[idx]);
+ if(iRet == RS_RET_OK) {
+ if(pPoll != NULL)
+ CHKiRet(nspoll.Ctl(pPoll, pNewSess->pStrm, 0, pNewSess, NSDPOLL_IN, NSDPOLL_ADD));
+ DBGPRINTF("New session created with NSD %p.\n", pNewSess);
+ } else {
+ DBGPRINTF("tcpsrv: error %d during accept\n", iRet);
+ }
+ } else {
+ pNewSess = (tcps_sess_t*) pUsr;
+ doReceive(pThis, &pNewSess, pPoll);
+ if(pPoll == NULL && pNewSess == NULL) {
+ pThis->pSessions[idx] = NULL;
+ }
+ }
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* worker to process incoming requests
+ */
+static void *
+wrkr(void *myself)
+{
+ struct wrkrInfo_s *me = (struct wrkrInfo_s*) myself;
+
+ pthread_mutex_lock(&wrkrMut);
+ while(1) {
+ while(me->pSrv == NULL && glbl.GetGlobalInputTermState() == 0) {
+ pthread_cond_wait(&me->run, &wrkrMut);
+ }
+ if(glbl.GetGlobalInputTermState() == 1)
+ break;
+ pthread_mutex_unlock(&wrkrMut);
+
+ ++me->numCalled;
+ processWorksetItem(me->pSrv, me->pPoll, me->idx, me->pUsr);
+
+ pthread_mutex_lock(&wrkrMut);
+ me->pSrv = NULL; /* indicate we are free again */
+ --wrkrRunning;
+ pthread_cond_signal(&wrkrIdle);
+ }
+ pthread_mutex_unlock(&wrkrMut);
+
+ return NULL;
+}
+
+
+/* Process a workset, that is handle io. We become activated
+ * from either select or epoll handler. We split the workload
+ * out to a pool of threads, but try to avoid context switches
+ * as much as possible.
+ */
+static rsRetVal
+processWorkset(tcpsrv_t *pThis, nspoll_t *pPoll, int numEntries, nsd_epworkset_t workset[])
+{
+ int i;
+ int origEntries = numEntries;
+ DEFiRet;
+
+ dbgprintf("tcpsrv: ready to process %d event entries\n", numEntries);
+
+ while(numEntries > 0) {
+ if(glbl.GetGlobalInputTermState() == 1)
+ ABORT_FINALIZE(RS_RET_FORCE_TERM);
+ if(numEntries == 1) {
+ /* process self, save context switch */
+ processWorksetItem(pThis, pPoll, workset[numEntries-1].id, workset[numEntries-1].pUsr);
+ } else {
+ pthread_mutex_lock(&wrkrMut);
+ /* check if there is a free worker */
+ for(i = 0 ; (i < wrkrMax) && (wrkrInfo[i].pSrv != NULL) ; ++i)
+ /*do search*/;
+ if(i < wrkrMax) {
+ /* worker free -> use it! */
+ wrkrInfo[i].pSrv = pThis;
+ wrkrInfo[i].pPoll = pPoll;
+ wrkrInfo[i].idx = workset[numEntries -1].id;
+ wrkrInfo[i].pUsr = workset[numEntries -1].pUsr;
+ /* Note: we must increment wrkrRunning HERE and not inside the worker's
+ * code. This is because a worker may actually never start, and thus
+ * increment wrkrRunning, before we finish and check the running worker
+ * count. We can only avoid this by incrementing it here.
+ */
+ ++wrkrRunning;
+ pthread_cond_signal(&wrkrInfo[i].run);
+ pthread_mutex_unlock(&wrkrMut);
+ } else {
+ pthread_mutex_unlock(&wrkrMut);
+ /* no free worker, so we process this one ourselfs */
+ processWorksetItem(pThis, pPoll, workset[numEntries-1].id,
+ workset[numEntries-1].pUsr);
+ }
+ }
+ --numEntries;
+ }
+
+ if(origEntries > 1) {
+ /* we now need to wait until all workers finish. This is because the
+ * rest of this module can not handle the concurrency introduced
+ * by workers running during the epoll call.
+ */
+ pthread_mutex_lock(&wrkrMut);
+ while(wrkrRunning > 0) {
+ pthread_cond_wait(&wrkrIdle, &wrkrMut);
+ }
+ pthread_mutex_unlock(&wrkrMut);
+ }
+
+finalize_it:
+ RETiRet;
+}
+
/* This function is called to gather input.
* This variant here is only used if we need to work with a netstream driver
@@ -550,14 +698,14 @@ finalize_it:
*/
#pragma GCC diagnostic ignored "-Wempty-body"
static inline rsRetVal
-RunSelect(tcpsrv_t *pThis)
+RunSelect(tcpsrv_t *pThis, nsd_epworkset_t workset[], size_t sizeWorkset)
{
DEFiRet;
int nfds;
int i;
+ int iWorkset;
int iTCPSess;
int bIsReady;
- tcps_sess_t *pNewSess;
nssel_t *pSel = NULL;
rsRetVal localRet;
@@ -592,13 +740,21 @@ RunSelect(tcpsrv_t *pThis)
if(glbl.GetGlobalInputTermState() == 1)
break; /* terminate input! */
+ iWorkset = 0;
for(i = 0 ; i < pThis->iLstnCurr ; ++i) {
if(glbl.GetGlobalInputTermState() == 1)
ABORT_FINALIZE(RS_RET_FORCE_TERM);
CHKiRet(nssel.IsReady(pSel, pThis->ppLstn[i], NSDSEL_RD, &bIsReady, &nfds));
if(bIsReady) {
- DBGPRINTF("New connect on NSD %p.\n", pThis->ppLstn[i]);
- SessAccept(pThis, pThis->ppLstnPort[i], &pNewSess, pThis->ppLstn[i]);
+ workset[iWorkset].id = i;
+ workset[iWorkset].pUsr = (void*) pThis->ppLstn; /* this is a flag to indicate listen sock */
+ ++iWorkset;
+ if(iWorkset >= (int) sizeWorkset) {
+ processWorkset(pThis, NULL, iWorkset, workset);
+ iWorkset = 0;
+ }
+ //DBGPRINTF("New connect on NSD %p.\n", pThis->ppLstn[i]);
+ //SessAccept(pThis, pThis->ppLstnPort[i], &pNewSess, pThis->ppLstn[i]);
--nfds; /* indicate we have processed one */
}
}
@@ -610,11 +766,22 @@ RunSelect(tcpsrv_t *pThis)
ABORT_FINALIZE(RS_RET_FORCE_TERM);
localRet = nssel.IsReady(pSel, pThis->pSessions[iTCPSess]->pStrm, NSDSEL_RD, &bIsReady, &nfds);
if(bIsReady || localRet != RS_RET_OK) {
- doReceive(pThis, &pThis->pSessions[iTCPSess], NULL);
+ workset[iWorkset].id = iTCPSess;
+ workset[iWorkset].pUsr = (void*) pThis->pSessions[iTCPSess];
+ ++iWorkset;
+ if(iWorkset >= (int) sizeWorkset) {
+ processWorkset(pThis, NULL, iWorkset, workset);
+ iWorkset = 0;
+ }
--nfds; /* indicate we have processed one */
}
iTCPSess = TCPSessGetNxtSess(pThis, iTCPSess);
}
+
+ if(iWorkset > 0)
+ processWorkset(pThis, NULL, iWorkset, workset);
+
+ /* we need to copy back close descriptors */
CHKiRet(nssel.Destruct(&pSel));
finalize_it: /* this is a very special case - this time only we do not exit the function,
* because that would not help us either. So we simply retry it. Let's see
@@ -645,9 +812,9 @@ Run(tcpsrv_t *pThis)
{
DEFiRet;
int i;
- tcps_sess_t *pNewSess;
+ nsd_epworkset_t workset[128]; /* 128 is currently fixed num of concurrent requests */
+ int numEntries;
nspoll_t *pPoll = NULL;
- void *pUsr;
rsRetVal localRet;
ISOBJ_TYPE_assert(pThis, tcpsrv);
@@ -663,11 +830,11 @@ Run(tcpsrv_t *pThis)
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);
+ iRet = RunSelect(pThis, workset, sizeof(workset)/sizeof(nsd_epworkset_t));
FINALIZE;
}
- dbgprintf("tcpsrv uses epoll() interface, nsdpol driver found\n");
+ dbgprintf("tcpsrv uses epoll() interface, nsdpoll driver found\n");
/* flag that we are in epoll mode */
pThis->bUsingEPoll = TRUE;
@@ -680,7 +847,8 @@ Run(tcpsrv_t *pThis)
}
while(1) {
- localRet = nspoll.Wait(pPoll, -1, &i, &pUsr);
+ numEntries = sizeof(workset)/sizeof(nsd_epworkset_t);
+ localRet = nspoll.Wait(pPoll, -1, &numEntries, workset);
if(glbl.GetGlobalInputTermState() == 1)
break; /* terminate input! */
@@ -691,17 +859,7 @@ Run(tcpsrv_t *pThis)
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);
- }
+ processWorkset(pThis, pPoll, numEntries, workset);
}
/* remove the tcp listen sockets from the epoll set */
@@ -723,6 +881,7 @@ BEGINobjConstruct(tcpsrv) /* be sure to specify the object type also in END macr
pThis->addtlFrameDelim = TCPSRV_NO_ADDTL_DELIMITER;
pThis->bDisableLFDelim = 0;
pThis->OnMsgReceive = NULL;
+ pThis->bUseFlowControl = 1;
ENDobjConstruct(tcpsrv)
@@ -998,6 +1157,18 @@ SetLstnMax(tcpsrv_t *pThis, int iMax)
}
+/* set if flow control shall be supported
+ */
+static rsRetVal
+SetUseFlowControl(tcpsrv_t *pThis, int bUseFlowControl)
+{
+ DEFiRet;
+ ISOBJ_TYPE_assert(pThis, tcpsrv);
+ pThis->bUseFlowControl = bUseFlowControl;
+ RETiRet;
+}
+
+
/* set max number of sessions
* this must be called before ConstructFinalize, or it will have no effect!
* rgerhards, 2009-04-09
@@ -1040,6 +1211,7 @@ CODESTARTobjQueryInterface(tcpsrv)
pIf->SetAddtlFrameDelim = SetAddtlFrameDelim;
pIf->SetbDisableLFDelim = SetbDisableLFDelim;
pIf->SetSessMax = SetSessMax;
+ pIf->SetUseFlowControl = SetUseFlowControl;
pIf->SetLstnMax = SetLstnMax;
pIf->SetDrvrMode = SetDrvrMode;
pIf->SetDrvrAuthMode = SetDrvrAuthMode;
@@ -1105,11 +1277,50 @@ BEGINObjClassInit(tcpsrv, 1, OBJ_IS_LOADABLE_MODULE) /* class, version - CHANGE
ENDObjClassInit(tcpsrv)
-/* --------------- here now comes the plumbing that makes as a library module --------------- */
+/* destroy worker pool structures and wait for workers to terminate
+ */
+static inline void
+startWorkerPool(void)
+{
+ int i;
+ wrkrRunning = 0;
+ pthread_mutex_init(&wrkrMut, NULL);
+ pthread_cond_init(&wrkrIdle, NULL);
+ for(i = 0 ; i < wrkrMax ; ++i) {
+ /* init worker info structure! */
+ pthread_cond_init(&wrkrInfo[i].run, NULL);
+ wrkrInfo[i].pSrv = NULL;
+ wrkrInfo[i].numCalled = 0;
+ pthread_create(&wrkrInfo[i].tid, NULL, wrkr, &(wrkrInfo[i]));
+ }
+}
+
+/* destroy worker pool structures and wait for workers to terminate
+ */
+static inline void
+stopWorkerPool(void)
+{
+ int i;
+ for(i = 0 ; i < wrkrMax ; ++i) {
+ pthread_cond_signal(&wrkrInfo[i].run); /* awake wrkr if not running */
+ pthread_join(wrkrInfo[i].tid, NULL);
+ DBGPRINTF("tcpsrv: info: worker %d was called %llu times\n", i, wrkrInfo[i].numCalled);
+ pthread_cond_destroy(&wrkrInfo[i].run);
+ }
+ pthread_cond_destroy(&wrkrIdle);
+ pthread_mutex_destroy(&wrkrMut);
+
+}
+
+
+/* --------------- here now comes the plumbing that makes as a library module --------------- */
BEGINmodExit
CODESTARTmodExit
+dbgprintf("tcpsrv: modExit\n");
+ stopWorkerPool();
+
/* de-init in reverse order! */
tcpsrvClassExit();
tcps_sessClassExit();
@@ -1129,6 +1340,9 @@ CODESTARTmodInit
/* Initialize all classes that are in our module - this includes ourselfs */
CHKiRet(tcps_sessClassInit(pModInfo));
CHKiRet(tcpsrvClassInit(pModInfo)); /* must be done after tcps_sess, as we use it */
+
+ startWorkerPool();
+
ENDmodInit
/* vim:set ai:
diff --git a/tcpsrv.h b/tcpsrv.h
index 269863c2..2a1bd843 100644
--- a/tcpsrv.h
+++ b/tcpsrv.h
@@ -55,6 +55,7 @@ struct tcpsrv_s {
permittedPeers_t *pPermPeers;/**< driver's permitted peers */
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!) */
+ sbool bUseFlowControl; /**< use flow control (make light delayable) */
int iLstnCurr; /**< max nbr of listeners currently supported */
netstrm_t **ppLstn; /**< our netstream listners */
tcpLstnPortList_t **ppLstnPort; /**< pointer to relevant listen port description */
@@ -82,6 +83,18 @@ struct tcpsrv_s {
};
+/**
+ * The following structure is a set of descriptors that need to be processed.
+ * This set will be the result of the epoll or select call and be used
+ * in the actual request processing stage. It serves as a basis
+ * to run multiple request by concurrent threads. -- rgerhards, 2011-01-24
+ */
+struct tcpsrv_workset_s {
+ int idx; /**< index into session table (or -1 if listener) */
+ void *pUsr;
+};
+
+
/* interfaces */
BEGINinterface(tcpsrv) /* name must also be changed in ENDinterface macro! */
INTERFACEObjDebugPrint(tcpsrv);
@@ -120,8 +133,10 @@ BEGINinterface(tcpsrv) /* name must also be changed in ENDinterface macro! */
rsRetVal (*SetNotificationOnRemoteClose)(tcpsrv_t *pThis, int bNewVal); /* 2009-10-01 */
/* added v9 -- rgerhards, 2010-03-01 */
rsRetVal (*SetbDisableLFDelim)(tcpsrv_t*, int);
+ /* added v10 -- rgerhards, 2011-04-01 */
+ rsRetVal (*SetUseFlowControl)(tcpsrv_t*, int);
ENDinterface(tcpsrv)
-#define tcpsrvCURR_IF_VERSION 9 /* increment whenever you change the interface structure! */
+#define tcpsrvCURR_IF_VERSION 10 /* 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 2038c6c1..38b86719 100644
--- a/template.c
+++ b/template.c
@@ -116,7 +116,8 @@ rsRetVal tplToString(struct template *pTpl, msg_t *pMsg, uchar **ppBuf, size_t *
iLenVal = pTpe->data.constant.iLenConstant;
bMustBeFreed = 0;
} else if(pTpe->eEntryType == FIELD) {
- pVal = (uchar*) MsgGetProp(pMsg, pTpe, pTpe->data.field.propid, &iLenVal, &bMustBeFreed);
+ pVal = (uchar*) MsgGetProp(pMsg, pTpe, pTpe->data.field.propid,
+ pTpe->data.field.propName, &iLenVal, &bMustBeFreed);
/* we now need to check if we should use SQL option. In this case,
* we must go over the generated string and escape '\'' characters.
* rgerhards, 2005-09-22: the option values below look somewhat misplaced,
@@ -195,7 +196,8 @@ rsRetVal tplToArray(struct template *pTpl, msg_t *pMsg, uchar*** ppArr)
if(pTpe->eEntryType == CONSTANT) {
CHKmalloc(pArr[iArr] = (uchar*)strdup((char*) pTpe->data.constant.pConstant));
} else if(pTpe->eEntryType == FIELD) {
- pVal = (uchar*) MsgGetProp(pMsg, pTpe, pTpe->data.field.propid, &propLen, &bMustBeFreed);
+ pVal = (uchar*) MsgGetProp(pMsg, pTpe, pTpe->data.field.propid,
+ pTpe->data.field.propName, &propLen, &bMustBeFreed);
if(bMustBeFreed) { /* if it must be freed, it is our own private copy... */
pArr[iArr] = pVal; /* ... so we can use it! */
} else {
@@ -588,7 +590,14 @@ static int do_Parameter(unsigned char **pp, struct template *pTpl)
cstrDestruct(&pStrB);
return 1;
}
- cstrDestruct(&pStrB); /* no longer needed, now use ID */
+ if(pTpe->data.field.propid == PROP_CEE) {
+ /* in CEE case, we need to preserve the actual property name */
+ if((pTpe->data.field.propName = es_newStrFromCStr((char*)cstrGetSzStrNoNULL(pStrB)+2, cstrLen(pStrB)-2)) == NULL) {
+ cstrDestruct(&pStrB);
+ return 1;
+ }
+ }
+ cstrDestruct(&pStrB);
/* Check frompos, if it has an R, then topos should be a regex */
if(*p == ':') {
@@ -1092,6 +1101,8 @@ void tplDeleteAll(void)
regexp.regfree(&(pTpeDel->data.field.re));
}
}
+ if(pTpeDel->data.field.propName != NULL)
+ es_deleteStr(pTpeDel->data.field.propName);
#endif
break;
}
@@ -1148,6 +1159,8 @@ void tplDeleteNew(void)
regexp.regfree(&(pTpeDel->data.field.re));
}
}
+ if(pTpeDel->data.field.propName != NULL)
+ es_deleteStr(pTpeDel->data.field.propName);
#endif
break;
}
@@ -1198,6 +1211,11 @@ void tplPrintList(void)
break;
case FIELD:
dbgprintf("(FIELD), value: '%d' ", pTpe->data.field.propid);
+ if(pTpe->data.field.propid == PROP_CEE) {
+ char *cstr = es_str2cstr(pTpe->data.field.propName, NULL);
+ dbgprintf("[EE-Property: '%s'] ", cstr);
+ free(cstr);
+ }
switch(pTpe->data.field.eDateFormat) {
case tplFmtDefault:
break;
diff --git a/template.h b/template.h
index f7ac2e08..2fb8e1ae 100644
--- a/template.h
+++ b/template.h
@@ -25,6 +25,7 @@
#ifndef TEMPLATE_H_INCLUDED
#define TEMPLATE_H_INCLUDED 1
+#include <libestr.h>
#include "regexp.h"
#include "stringbuf.h"
@@ -88,6 +89,8 @@ struct templateEntry {
unsigned char field_delim; /* support for field-counting: field delemiter char */
int field_expand; /* use multiple instances of the field delimiter as a single one? */
+ es_str_t *propName; /**< property name (currently being used for CEE only) */
+
enum tplFormatTypes eDateFormat;
enum tplFormatCaseConvTypes eCaseConv;
struct { /* bit fields! */
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 77381d2f..38d10da6 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -50,6 +50,9 @@ TESTS += \
imuxsock_logger_root.sh \
imuxsock_traillf_root.sh \
imuxsock_ccmiddle_root.sh \
+ udp-msgreduc-vg.sh \
+ udp-msgreduc-orgmsg-vg.sh \
+ queue-persist.sh
discard-rptdmsg.sh \
discard-allmark.sh \
discard.sh \
@@ -100,6 +103,11 @@ TESTS += \
endif
if ENABLE_GNUTLS
+# TODO: re-enable in newer version
+#TESTS += \
+ #sndrcv_tls_anon.sh \
+ #sndrcv_tls_anon_rebind.sh \
+ #imtcp-tls-basic.sh
if HAVE_VALGRIND
# This test does not work on v5 as we keep DH params
#TESTS += manytcp-too-few-tls.sh
@@ -155,6 +163,12 @@ test_files = testbench.h runtime-dummy.c
EXTRA_DIST= 1.rstest 2.rstest 3.rstest err1.rstest \
validation-run.sh \
+ testsuites/x.509/ca.pem \
+ testsuites/x.509/ca-key.pem \
+ testsuites/x.509/client-cert.pem \
+ testsuites/x.509/client-key.pem \
+ testsuites/x.509/machine-cert.pem \
+ testsuites/x.509/machine-key.pem \
testsuites/invalid.conf \
testsuites/valid.conf \
cfg.sh \
@@ -251,8 +265,14 @@ EXTRA_DIST= 1.rstest 2.rstest 3.rstest err1.rstest \
testsuites/da-mainmsg-q.conf \
diskqueue-fsync.sh \
testsuites/diskqueue-fsync.conf \
+ imtcp-tls-basic.sh \
+ testsuites/imtcp-tls-basic.conf \
imtcp-multiport.sh \
testsuites/imtcp-multiport.conf \
+ udp-msgreduc-orgmsg-vg.sh \
+ testsuites/udp-msgreduc-orgmsg-vg.conf \
+ udp-msgreduc-vg.sh \
+ testsuites/udp-msgreduc-vg.conf \
manytcp.sh \
testsuites/manytcp.conf \
manyptcp.sh \
@@ -436,6 +456,15 @@ EXTRA_DIST= 1.rstest 2.rstest 3.rstest err1.rstest \
testsuites/mysql-asyn.conf \
cfg.sh
+# TODO: re-enable
+#sndrcv_tls_anon_rebind.sh \
+#testsuites/sndrcv_tls_anon_rebind_sender.conf \
+#testsuites/sndrcv_tls_anon_rebind_rcvr.conf \
+#sndrcv_tls_anon.sh \
+#testsuites/sndrcv_tls_anon_sender.conf \
+#testsuites/sndrcv_tls_anon_rcvr.conf \
+#
+
ourtail_SOURCES = ourtail.c
msleep_SOURCES = msleep.c
chkseq_SOURCES = chkseq.c
@@ -444,8 +473,11 @@ uxsockrcvr_SOURCES = uxsockrcvr.c
uxsockrcvr_LDADD = $(SOL_LIBS)
tcpflood_SOURCES = tcpflood.c
-tcpflood_CPPFLAGS = $(PTHREADS_CFLAGS)
-tcpflood_LDADD = $(SOL_LIBS) $(PTHREADS_LIBS)
+tcpflood_CPPFLAGS = $(PTHREADS_CFLAGS) $(GNUTLS_CFLAGS)
+tcpflood_LDADD = $(SOL_LIBS) $(PTHREADS_LIBS) $(GNUTLS_LIBS)
+if ENABLE_GNUTLS
+tcpflood_LDADD += -lgcrypt
+endif
syslog_caller_SOURCES = syslog_caller.c
syslog_caller_LDADD = $(SOL_LIBS)
diff --git a/tests/diag.sh b/tests/diag.sh
index 3e0263c1..9fd878a4 100755
--- a/tests/diag.sh
+++ b/tests/diag.sh
@@ -31,7 +31,7 @@ case $1 in
rm -f work rsyslog.out.log rsyslog2.out.log rsyslog.out.log.save # common work files
rm -rf test-spool test-logdir stat-file1
rm -f rsyslog.out.*.log rsyslog.random.data work-presort rsyslog.pipe
- rm -f rsyslog.input stat-file1 #rsyslog.empty
+ rm -f rsyslog.input rsyslog.conf.tlscert stat-file1 rsyslog.empty
echo -------------------------------------------------------------------------------
;;
'startup') # start rsyslogd with default params. $2 is the config file name to use
@@ -41,7 +41,7 @@ case $1 in
;;
'startup-vg') # start rsyslogd with default params under valgrind control. $2 is the config file name to use
# returns only after successful startup, $3 is the instance (blank or 2!)
- valgrind --error-exitcode=10 --malloc-fill=ff --free-fill=fe --leak-check=full ../tools/rsyslogd -c6 -u2 -n -irsyslog$3.pid -M../runtime/.libs:../.libs -f$srcdir/testsuites/$2 &
+ valgrind --log-fd=1 --error-exitcode=10 --malloc-fill=ff --free-fill=fe --leak-check=full ../tools/rsyslogd -c6 -u2 -n -irsyslog$3.pid -M../runtime/.libs:../.libs -f$srcdir/testsuites/$2 &
$srcdir/diag.sh wait-startup $3
;;
'wait-startup') # wait for rsyslogd startup ($2 is the instance)
diff --git a/tests/filewriter.c b/tests/filewriter.c
new file mode 100644
index 00000000..07991b1d
--- /dev/null
+++ b/tests/filewriter.c
@@ -0,0 +1,158 @@
+/* This program expands the input file several times. This
+ * is done in order to obtain large (and maybe huge) files for
+ * testing. Note that the input file is stored in memory. It's
+ * last line must properly be terminated.
+ * Max input line size is 10K.
+ *
+ * command line options:
+ * -i file to be used for input (else stdin)
+ * -o file to be used for output (else stdout)
+ * -c number of times the file is to be copied
+ * -n add line numbers (default: off)
+ * -w wait nbr of microsecs between batches
+ * -W number of file lines to generate in a batch
+ * This is useful only if -w is specified as well,
+ * default is 1000.
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+
+/* input file is stored in a single-linked list */
+struct line {
+ struct line *next;
+ char *ln;
+} *root, *tail;
+
+static FILE *fpIn;
+static FILE *fpOut;
+static long long nCopies = 1;
+static int linenbrs = 0;
+static int waitusecs = 0;
+static int batchsize = 1000;
+
+
+/* read the input file and create in-memory representation
+ */
+static inline void
+readFile()
+{
+ char *r;
+ char lnBuf[10240];
+ struct line *node;
+
+ root = tail = NULL;
+ r = fgets(lnBuf, sizeof(lnBuf), fpIn);
+ while(r != NULL) {
+ node = malloc(sizeof(struct line));
+ if(node == NULL) {
+ perror("malloc node");
+ exit(1);
+ }
+ node->next = NULL;
+ node->ln = strdup(lnBuf);
+ if(node->ln == NULL) {
+ perror("malloc node");
+ exit(1);
+ }
+ if(tail == NULL) {
+ tail = root = node;
+ } else {
+ tail->next = node;
+ tail = node;
+ }
+ r = fgets(lnBuf, sizeof(lnBuf), fpIn);
+ }
+ if(!feof(fpIn)) {
+ perror("fgets");
+ fprintf(stderr, "end of read loop, but not end of file!");
+ exit(1);
+ }
+}
+
+
+static void
+genCopies()
+{
+ long long i;
+ long long unsigned lnnbr;
+ struct line *node;
+
+ lnnbr = 1;
+ for(i = 0 ; i < nCopies ; ++i) {
+ if(i % 10000 == 0)
+ fprintf(stderr, "copyrun %d\n", i);
+ if(waitusecs && (i % batchsize == 0)) {
+ usleep(waitusecs);
+ }
+ for(node = root ; node != NULL ; node = node->next) {
+ if(linenbrs)
+ fprintf(fpOut, "%12.12llu:%s", lnnbr, node->ln);
+ else
+ fprintf(fpOut, "%s", node->ln);
+ ++lnnbr;
+ }
+ }
+}
+
+void main(int argc, char *argv[])
+{
+ int opt;
+ fpIn = stdin;
+ fpOut = stdout;
+
+ while((opt = getopt(argc, argv, "i:o:c:nw:W:")) != -1) {
+ switch (opt) {
+ case 'i': /* input file */
+ if((fpIn = fopen(optarg, "r")) == NULL) {
+ perror(optarg);
+ exit(1);
+ }
+ break;
+ case 'o': /* output file */
+ if((fpOut = fopen(optarg, "w")) == NULL) {
+ perror(optarg);
+ exit(1);
+ }
+ break;
+ case 'c':
+ nCopies = atoll(optarg);
+ break;
+ case 'n':
+ linenbrs = 1;
+ break;
+ case 'w':
+ waitusecs = atoi(optarg);
+ break;
+ case 'W':
+ batchsize = atoi(optarg);
+ break;
+ default: printf("invalid option '%c' or value missing - terminating...\n", opt);
+ exit (1);
+ break;
+ }
+ }
+
+ readFile();
+ genCopies();
+}
diff --git a/tests/imtcp-tls-basic.sh b/tests/imtcp-tls-basic.sh
new file mode 100755
index 00000000..bfe24880
--- /dev/null
+++ b/tests/imtcp-tls-basic.sh
@@ -0,0 +1,14 @@
+# added 2011-02-28 by Rgerhards
+# This file is part of the rsyslog project, released under GPLv3
+echo ===============================================================================
+echo \[imtcp-tls-basic.sh\]: testing imtcp in TLS mode - basic test
+source $srcdir/diag.sh init
+echo \$DefaultNetstreamDriverCAFile $srcdir/tls-certs/ca.pem >rsyslog.conf.tlscert
+echo \$DefaultNetstreamDriverCertFile $srcdir/tls-certs/cert.pem >>rsyslog.conf.tlscert
+echo \$DefaultNetstreamDriverKeyFile $srcdir/tls-certs/key.pem >>rsyslog.conf.tlscert
+source $srcdir/diag.sh startup imtcp-tls-basic.conf
+source $srcdir/diag.sh tcpflood -p13514 -m50000 -Ttls -Z$srcdir/tls-certs/cert.pem -z$srcdir/tls-certs/key.pem
+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 49999
+source $srcdir/diag.sh exit
diff --git a/tests/sndrcv_drvr.sh b/tests/sndrcv_drvr.sh
index f9092647..1f3b9113 100755
--- a/tests/sndrcv_drvr.sh
+++ b/tests/sndrcv_drvr.sh
@@ -1,2 +1 @@
source $srcdir/sndrcv_drvr_noexit.sh $1 $2
-source $srcdir/diag.sh exit
diff --git a/tests/sndrcv_tls_anon_rebind.sh b/tests/sndrcv_tls_anon_rebind.sh
new file mode 100755
index 00000000..55b96d04
--- /dev/null
+++ b/tests/sndrcv_tls_anon_rebind.sh
@@ -0,0 +1,5 @@
+# rgerhards, 2011-04-04
+# This file is part of the rsyslog project, released under GPLv3
+echo ===============================================================================
+echo \[sndrcv_tls_anon_rebind.sh\]: testing sending and receiving via TLS with anon auth and rebind
+source $srcdir/sndrcv_drvr.sh sndrcv_tls_anon_rebind 25000
diff --git a/tests/testsuites/imtcp-tls-basic.conf b/tests/testsuites/imtcp-tls-basic.conf
new file mode 100644
index 00000000..a94a00ef
--- /dev/null
+++ b/tests/testsuites/imtcp-tls-basic.conf
@@ -0,0 +1,21 @@
+# Test for queue disk mode (see .sh file for details)
+# rgerhards, 2009-05-22
+$IncludeConfig diag-common.conf
+
+$ModLoad ../plugins/imtcp/.libs/imtcp
+$MainMsgQueueTimeoutShutdown 10000
+
+$DefaultNetstreamDriver gtls
+
+# certificate files - just CA for a client
+$IncludeConfig rsyslog.conf.tlscert
+$InputTCPServerStreamDriverMode 1
+$InputTCPServerStreamDriverAuthMode anon
+$InputTCPServerRun 13514
+
+$template outfmt,"%msg:F,58:2%\n"
+$OMFileFlushOnTXEnd off
+$OMFileFlushInterval 2
+$OMFileAsyncWriting on
+$OMFileIOBufferSize 16k
+:msg, contains, "msgnum:" ./rsyslog.out.log;outfmt
diff --git a/tests/testsuites/sndrcv_tls_anon_rebind_rcvr.conf b/tests/testsuites/sndrcv_tls_anon_rebind_rcvr.conf
new file mode 100644
index 00000000..01143b22
--- /dev/null
+++ b/tests/testsuites/sndrcv_tls_anon_rebind_rcvr.conf
@@ -0,0 +1,22 @@
+# see equally-named shell file for details
+# this is the config fil for the TLS server
+# rgerhards, 2009-11-11
+$IncludeConfig diag-common.conf
+
+$ModLoad ../plugins/imtcp/.libs/imtcp
+
+# certificates
+$DefaultNetstreamDriverCAFile testsuites/x.509/ca.pem
+$DefaultNetstreamDriverCertFile testsuites/x.509/client-cert.pem
+$DefaultNetstreamDriverKeyFile testsuites/x.509/client-key.pem
+
+$DefaultNetstreamDriver gtls # use gtls netstream driver
+
+# then SENDER sends to this port (not tcpflood!)
+$InputTCPServerStreamDriverMode 1
+$InputTCPServerStreamDriverAuthMode anon
+$InputTCPServerRun 13515
+
+$template outfmt,"%msg:F,58:2%\n"
+$template dynfile,"rsyslog.out.log" # trick to use relative path names!
+:msg, contains, "msgnum:" ?dynfile;outfmt
diff --git a/tests/testsuites/sndrcv_tls_anon_rebind_sender.conf b/tests/testsuites/sndrcv_tls_anon_rebind_sender.conf
new file mode 100644
index 00000000..47633349
--- /dev/null
+++ b/tests/testsuites/sndrcv_tls_anon_rebind_sender.conf
@@ -0,0 +1,20 @@
+# see tcpsndrcv.sh for details
+# this is the TLS client
+# rgerhards, 2009-11-11
+$IncludeConfig diag-common2.conf
+
+# certificates
+$DefaultNetstreamDriverCAFile testsuites/x.509/ca.pem
+$DefaultNetstreamDriverCertFile testsuites/x.509/client-cert.pem
+$DefaultNetstreamDriverKeyFile testsuites/x.509/client-key.pem
+
+# Note: no TLS for the listener, this is for tcpflood!
+$ModLoad ../plugins/imtcp/.libs/imtcp
+$InputTCPServerRun 13514
+
+# set up the action
+$DefaultNetstreamDriver gtls # use gtls netstream driver
+$ActionSendStreamDriverMode 1 # require TLS for the connection
+$ActionSendStreamDriverAuthMode anon
+$ActionSendTCPRebindInterval 50
+*.* @@127.0.0.1:13515
diff --git a/tests/testsuites/udp-msgreduc-orgmsg-vg.conf b/tests/testsuites/udp-msgreduc-orgmsg-vg.conf
new file mode 100644
index 00000000..5e80e49b
--- /dev/null
+++ b/tests/testsuites/udp-msgreduc-orgmsg-vg.conf
@@ -0,0 +1,11 @@
+# Test for queue disk mode (see .sh file for details)
+# rgerhards, 2009-05-22
+$IncludeConfig diag-common.conf
+
+$ModLoad ../plugins/imudp/.libs/imudp
+$UDPServerRun 13514
+$RepeatedMsgReduction on
+$RepeatedMsgContainsOriginalMsg on
+
+$template outfmt,"%msg:F,58:2%\n"
+*.* ./rsyslog.out.log;outfmt
diff --git a/tests/testsuites/udp-msgreduc-vg.conf b/tests/testsuites/udp-msgreduc-vg.conf
new file mode 100644
index 00000000..150bef2e
--- /dev/null
+++ b/tests/testsuites/udp-msgreduc-vg.conf
@@ -0,0 +1,11 @@
+# Test for queue disk mode (see .sh file for details)
+# rgerhards, 2009-05-22
+$IncludeConfig diag-common.conf
+
+$ModLoad ../plugins/imudp/.libs/imudp
+$UDPServerRun 13514
+$RepeatedMsgReduction on
+
+$template outfmt,"%msg:F,58:2%\n"
+*.* ./rsyslog.out.log;outfmt
+#:msg, contains, "msgnum:" ./rsyslog.out.log;outfmt
diff --git a/tests/udp-msgreduc-orgmsg-vg.sh b/tests/udp-msgreduc-orgmsg-vg.sh
new file mode 100755
index 00000000..1594c89a
--- /dev/null
+++ b/tests/udp-msgreduc-orgmsg-vg.sh
@@ -0,0 +1,18 @@
+# check if valgrind violations occur. Correct output is not checked.
+# added 2011-03-01 by Rgerhards
+# This file is part of the rsyslog project, released under GPLv3
+echo ===============================================================================
+echo \[udp-msgreduc-orgmsg-vg.sh\]: testing msg reduction via udp, with org message
+source $srcdir/diag.sh init
+source $srcdir/diag.sh startup-vg udp-msgreduc-orgmsg-vg.conf
+source $srcdir/diag.sh wait-startup
+./tcpflood -t 127.0.0.1 -m 4 -r -Tudp -M "<133>2011-03-01T11:22:12Z host tag msgh ..."
+./tcpflood -t 127.0.0.1 -m 1 -r -Tudp -M "<133>2011-03-01T11:22:12Z host tag msgh ...x"
+source $srcdir/diag.sh shutdown-when-empty # shut down rsyslogd when done processing messages
+source $srcdir/diag.sh wait-shutdown-vg
+if [ "$RSYSLOGD_EXIT" -eq "10" ]
+then
+ echo "udp-msgreduc-orgmsg-vg.sh FAILED"
+ exit 1
+fi
+source $srcdir/diag.sh exit
diff --git a/tests/udp-msgreduc-vg.sh b/tests/udp-msgreduc-vg.sh
new file mode 100755
index 00000000..e19ffd86
--- /dev/null
+++ b/tests/udp-msgreduc-vg.sh
@@ -0,0 +1,18 @@
+# check if valgrind violations occur. Correct output is not checked.
+# added 2011-03-01 by Rgerhards
+# This file is part of the rsyslog project, released under GPLv3
+echo ===============================================================================
+echo \[udp-msgreduc-vg.sh\]: testing imtcp multiple listeners
+source $srcdir/diag.sh init
+source $srcdir/diag.sh startup-vg udp-msgreduc-vg.conf
+source $srcdir/diag.sh wait-startup
+./tcpflood -t 127.0.0.1 -m 4 -r -Tudp -M "<133>2011-03-01T11:22:12Z host tag msgh ..."
+./tcpflood -t 127.0.0.1 -m 1 -r -Tudp -M "<133>2011-03-01T11:22:12Z host tag msgh ...x"
+source $srcdir/diag.sh shutdown-when-empty # shut down rsyslogd when done processing messages
+source $srcdir/diag.sh wait-shutdown-vg
+if [ "$RSYSLOGD_EXIT" -eq "10" ]
+then
+ echo "udp-msgreduc-vg.sh FAILED"
+ exit 1
+fi
+source $srcdir/diag.sh exit
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 962ae507..fef88af1 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -36,7 +36,7 @@ rsyslogd_SOURCES = \
\
../dirty.h
rsyslogd_CPPFLAGS = $(PTHREADS_CFLAGS) $(RSRT_CFLAGS)
-rsyslogd_LDADD = $(ZLIB_LIBS) $(PTHREADS_LIBS) $(RSRT_LIBS) $(SOL_LIBS)
+rsyslogd_LDADD = $(ZLIB_LIBS) $(PTHREADS_LIBS) $(RSRT_LIBS) $(SOL_LIBS) $(LIBEE_LIBS) $(LIBLOGNORM_LIBS)
rsyslogd_LDFLAGS = -export-dynamic
if ENABLE_DIAGTOOLS
diff --git a/tools/omdiscard.c b/tools/omdiscard.c
index 02896d45..5b64d3ff 100644
--- a/tools/omdiscard.c
+++ b/tools/omdiscard.c
@@ -44,9 +44,19 @@ MODULE_TYPE_NOKEEP
DEF_OMOD_STATIC_DATA
typedef struct _instanceData {
- char dummy;
+ EMPTY_STRUCT
} instanceData;
+typedef struct configSettings_s {
+ EMPTY_STRUCT
+} configSettings_t;
+
+SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */
+
+BEGINinitConfVars /* (re)set config variables to default values */
+CODESTARTinitConfVars
+ENDinitConfVars
+
/* we do not need a createInstance()!
BEGINcreateInstance
CODESTARTcreateInstance
@@ -114,6 +124,7 @@ ENDqueryEtryPt
BEGINmodInit(Discard)
CODESTARTmodInit
+SCOPINGmodInit
*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
CODEmodInit_QueryRegCFSLineHdlr
ENDmodInit
diff --git a/tools/omfile.c b/tools/omfile.c
index fbd263c7..e13efa74 100644
--- a/tools/omfile.c
+++ b/tools/omfile.c
@@ -72,6 +72,9 @@
MODULE_TYPE_OUTPUT
MODULE_TYPE_NOKEEP
+/* forward definitions */
+static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal);
+
/* internal structures
*/
DEF_OMOD_STATIC_DATA
@@ -123,26 +126,6 @@ typedef struct s_dynaFileCacheEntry dynaFileCacheEntry;
#define FLUSHONTX_DFLT 1 /* default for flush on TX end */
#define DFLT_bForceChown 0
-/* globals for default values */
-static int iDynaFileCacheSize = 10; /* max cache for dynamic files */
-static int fCreateMode = 0644; /* mode to use when creating files */
-static int fDirCreateMode = 0700; /* mode to use when creating files */
-static int bFailOnChown; /* fail if chown fails? */
-static int bForceChown = DFLT_bForceChown; /* Force chown() on existing files? */
-static uid_t fileUID; /* UID to be used for newly created files */
-static uid_t fileGID; /* GID to be used for newly created files */
-static uid_t dirUID; /* UID to be used for newly created directories */
-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 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? */
-uchar *pszFileDfltTplName = NULL; /* name of the default template to use */
-/* end globals for default values */
-
typedef struct _instanceData {
uchar f_fname[MAXFNAME];/* file or template name (display only) */
@@ -177,6 +160,35 @@ typedef struct _instanceData {
} instanceData;
+typedef struct configSettings_s {
+ int iDynaFileCacheSize; /* max cache for dynamic files */
+ int fCreateMode; /* mode to use when creating files */
+ int fDirCreateMode; /* mode to use when creating files */
+ int bFailOnChown; /* fail if chown fails? */
+ int bForceChown; /* Force chown() on existing files? */
+ uid_t fileUID; /* UID to be used for newly created files */
+ uid_t fileGID; /* GID to be used for newly created files */
+ uid_t dirUID; /* UID to be used for newly created directories */
+ uid_t dirGID; /* GID to be used for newly created directories */
+ int bCreateDirs;/* auto-create directories for dynaFiles: 0 - no, 1 - yes */
+ int bEnableSync;/* enable syncing of files (no dash in front of pathname in conf): 0 - no, 1 - yes */
+ int iZipLevel; /* zip compression mode (0..9 as usual) */
+ sbool bFlushOnTXEnd;/* flush write buffers when transaction has ended? */
+ int64 iIOBufSize; /* size of an io buffer */
+ int iFlushInterval; /* how often flush the output buffer on inactivity? */
+ int bUseAsyncWriter; /* should we enable asynchronous writing? */
+ EMPTY_STRUCT
+} configSettings_t;
+uchar *pszFileDfltTplName; /* name of the default template to use */
+
+SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */
+
+BEGINinitConfVars /* (re)set config variables to default values */
+CODESTARTinitConfVars
+ pszFileDfltTplName = NULL; /* make sure this can be free'ed! */
+ iRet = resetConfigVariables(NULL, NULL); /* params are dummies */
+ENDinitConfVars
+
BEGINisCompatibleWithFeature
CODESTARTisCompatibleWithFeature
if(eFeat == sFEATURERepeatedMsgReduction)
@@ -232,7 +244,7 @@ rsRetVal setDynaFileCacheSize(void __attribute__((unused)) *pVal, int iNewVal)
iNewVal = 1000;
}
- iDynaFileCacheSize = iNewVal;
+ cs.iDynaFileCacheSize = iNewVal;
DBGPRINTF("DynaFileCacheSize changed to %d.\n", iNewVal);
RETiRet;
@@ -459,7 +471,7 @@ prepareFile(instanceData *pData, uchar *newFileName)
CHKiRet(strm.SetiZipLevel(pData->pStrm, pData->iZipLevel));
CHKiRet(strm.SetsIOBufSize(pData->pStrm, (size_t) pData->iIOBufSize));
CHKiRet(strm.SettOperationsMode(pData->pStrm, STREAMMODE_WRITE_APPEND));
- CHKiRet(strm.SettOpenMode(pData->pStrm, fCreateMode));
+ CHKiRet(strm.SettOpenMode(pData->pStrm, cs.fCreateMode));
CHKiRet(strm.SetbSync(pData->pStrm, pData->bSyncFile));
CHKiRet(strm.SetsType(pData->pStrm, pData->strmType));
CHKiRet(strm.SetiSizeLimit(pData->pStrm, pData->iSizeLimit));
@@ -743,7 +755,7 @@ CODESTARTparseSelectorAct
pData->bSyncFile = 0;
p++;
} else {
- pData->bSyncFile = bEnableSync;
+ pData->bSyncFile = cs.bEnableSync;
}
pData->iSizeLimit = 0; /* default value, use outchannels to configure! */
@@ -777,7 +789,7 @@ CODESTARTparseSelectorAct
pData->iCurrElt = -1; /* no current element */
/* we now allocate the cache table */
CHKmalloc(pData->dynCache = (dynaFileCacheEntry**)
- calloc(iDynaFileCacheSize, sizeof(dynaFileCacheEntry*)));
+ calloc(cs.iDynaFileCacheSize, sizeof(dynaFileCacheEntry*)));
break;
/* case '|': while pipe support has been removed, I leave the code in in case we
@@ -806,21 +818,21 @@ CODESTARTparseSelectorAct
}
/* freeze current paremeters for this action */
- pData->iDynaFileCacheSize = iDynaFileCacheSize;
- pData->fCreateMode = fCreateMode;
- pData->fDirCreateMode = fDirCreateMode;
- pData->bCreateDirs = bCreateDirs;
- pData->bFailOnChown = bFailOnChown;
- pData->bForceChown = bForceChown;
- pData->fileUID = fileUID;
- pData->fileGID = fileGID;
- pData->dirUID = dirUID;
- pData->dirGID = dirGID;
- pData->iZipLevel = iZipLevel;
- pData->bFlushOnTXEnd = bFlushOnTXEnd;
- pData->iIOBufSize = (int) iIOBufSize;
- pData->iFlushInterval = iFlushInterval;
- pData->bUseAsyncWriter = bUseAsyncWriter;
+ pData->iDynaFileCacheSize = cs.iDynaFileCacheSize;
+ pData->fCreateMode = cs.fCreateMode;
+ pData->fDirCreateMode = cs.fDirCreateMode;
+ pData->bCreateDirs = cs.bCreateDirs;
+ pData->bFailOnChown = cs.bFailOnChown;
+ pData->bForceChown = cs.bForceChown;
+ pData->fileUID = cs.fileUID;
+ pData->fileGID = cs.fileGID;
+ pData->dirUID = cs.dirUID;
+ pData->dirGID = cs.dirGID;
+ pData->iZipLevel = cs.iZipLevel;
+ pData->bFlushOnTXEnd = cs.bFlushOnTXEnd;
+ pData->iIOBufSize = (int) cs.iIOBufSize;
+ pData->iFlushInterval = cs.iFlushInterval;
+ pData->bUseAsyncWriter = cs.bUseAsyncWriter;
if(pData->bDynamicName == 0) {
/* try open and emit error message if not possible. At this stage, we ignore the
@@ -842,26 +854,24 @@ ENDparseSelectorAct
*/
static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
{
- fileUID = -1;
- fileGID = -1;
- dirUID = -1;
- dirGID = -1;
- bFailOnChown = 1;
- bForceChown = DFLT_bForceChown;
- iDynaFileCacheSize = 10;
- fCreateMode = 0644;
- fDirCreateMode = 0700;
- bCreateDirs = 1;
- bEnableSync = 0;
- iZipLevel = 0;
- bFlushOnTXEnd = FLUSHONTX_DFLT;
- iIOBufSize = IOBUF_DFLT_SIZE;
- iFlushInterval = FLUSH_INTRVL_DFLT;
- bUseAsyncWriter = USE_ASYNCWRITER_DFLT;
- if(pszFileDfltTplName != NULL) {
- free(pszFileDfltTplName);
- pszFileDfltTplName = NULL;
- }
+ cs.fileUID = -1;
+ cs.fileGID = -1;
+ cs.dirUID = -1;
+ cs.dirGID = -1;
+ cs.bFailOnChown = 1;
+ cs.bForceChown = DFLT_bForceChown;
+ cs.iDynaFileCacheSize = 10;
+ cs.fCreateMode = 0644;
+ cs.fDirCreateMode = 0700;
+ cs.bCreateDirs = 1;
+ cs.bEnableSync = 0;
+ cs.iZipLevel = 0;
+ cs.bFlushOnTXEnd = FLUSHONTX_DFLT;
+ cs.iIOBufSize = IOBUF_DFLT_SIZE;
+ cs.iFlushInterval = FLUSH_INTRVL_DFLT;
+ cs.bUseAsyncWriter = USE_ASYNCWRITER_DFLT;
+ free(pszFileDfltTplName);
+ pszFileDfltTplName = NULL;
return RS_RET_OK;
}
@@ -901,6 +911,7 @@ BEGINmodInit(File)
CODESTARTmodInit
*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
CODEmodInit_QueryRegCFSLineHdlr
+SCOPINGmodInit
CHKiRet(objUse(errmsg, CORE_COMPONENT));
CHKiRet(objUse(strm, CORE_COMPONENT));
@@ -909,21 +920,21 @@ CODEmodInit_QueryRegCFSLineHdlr
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));
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"omfileziplevel", 0, eCmdHdlrInt, NULL, &iZipLevel, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"omfileflushinterval", 0, eCmdHdlrInt, NULL, &iFlushInterval, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"omfileasyncwriting", 0, eCmdHdlrBinary, NULL, &bUseAsyncWriter, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"omfileflushontxend", 0, eCmdHdlrBinary, NULL, &bFlushOnTXEnd, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"omfileiobuffersize", 0, eCmdHdlrSize, NULL, &iIOBufSize, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"dirowner", 0, eCmdHdlrUID, NULL, &dirUID, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"dirgroup", 0, eCmdHdlrGID, NULL, &dirGID, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"fileowner", 0, eCmdHdlrUID, NULL, &fileUID, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"filegroup", 0, eCmdHdlrGID, NULL, &fileGID, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"dircreatemode", 0, eCmdHdlrFileCreateMode, NULL, &fDirCreateMode, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"filecreatemode", 0, eCmdHdlrFileCreateMode, NULL, &fCreateMode, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"createdirs", 0, eCmdHdlrBinary, NULL, &bCreateDirs, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"failonchownfailure", 0, eCmdHdlrBinary, NULL, &bFailOnChown, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"omfileForceChown", 0, eCmdHdlrBinary, NULL, &bForceChown, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionfileenablesync", 0, eCmdHdlrBinary, NULL, &bEnableSync, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"omfileziplevel", 0, eCmdHdlrInt, NULL, &cs.iZipLevel, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"omfileflushinterval", 0, eCmdHdlrInt, NULL, &cs.iFlushInterval, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"omfileasyncwriting", 0, eCmdHdlrBinary, NULL, &cs.bUseAsyncWriter, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"omfileflushontxend", 0, eCmdHdlrBinary, NULL, &cs.bFlushOnTXEnd, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"omfileiobuffersize", 0, eCmdHdlrSize, NULL, &cs.iIOBufSize, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"dirowner", 0, eCmdHdlrUID, NULL, &cs.dirUID, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"dirgroup", 0, eCmdHdlrGID, NULL, &cs.dirGID, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"fileowner", 0, eCmdHdlrUID, NULL, &cs.fileUID, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"filegroup", 0, eCmdHdlrGID, NULL, &cs.fileGID, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"dircreatemode", 0, eCmdHdlrFileCreateMode, NULL, &cs.fDirCreateMode, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"filecreatemode", 0, eCmdHdlrFileCreateMode, NULL, &cs.fCreateMode, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"createdirs", 0, eCmdHdlrBinary, NULL, &cs.bCreateDirs, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"failonchownfailure", 0, eCmdHdlrBinary, NULL, &cs.bFailOnChown, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"omfileForceChown", 0, eCmdHdlrBinary, NULL, &cs.bForceChown, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionfileenablesync", 0, eCmdHdlrBinary, NULL, &cs.bEnableSync, STD_LOADABLE_MODULE_ID));
CHKiRet(regCfSysLineHdlr((uchar *)"actionfiledefaulttemplate", 0, eCmdHdlrGetWord, NULL, &pszFileDfltTplName, NULL));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
ENDmodInit
diff --git a/tools/omfwd.c b/tools/omfwd.c
index 10cce0e2..d5f113e7 100644
--- a/tools/omfwd.c
+++ b/tools/omfwd.c
@@ -97,18 +97,36 @@ typedef struct _instanceData {
# define FORW_TCP 1
/* following fields for TCP-based delivery */
tcpclt_t *pTCPClt; /* our tcpclt object */
+ uchar sndBuf[16*1024]; /* this is intensionally fixed -- see no good reason to make configurable */
+ unsigned offsSndBuf; /* next free spot in send buffer */
} instanceData;
/* config data */
-static uchar *pszTplName = NULL; /* name of the default template to use */
-static uchar *pszStrmDrvr = NULL; /* name of the stream driver to use */
-static int iStrmDrvrMode = 0; /* mode for stream driver, driver-dependent (0 mostly means plain tcp) */
-static int bResendLastOnRecon = 0; /* should the last message be re-sent on a successful reconnect? */
-static uchar *pszStrmDrvrAuthMode = NULL; /* authentication mode to use */
-static int iUDPRebindInterval = 0; /* support for automatic re-binding (load balancers!). 0 - no rebind */
-static int iTCPRebindInterval = 0; /* support for automatic re-binding (load balancers!). 0 - no rebind */
+typedef struct configSettings_s {
+ uchar *pszTplName; /* name of the default template to use */
+ uchar *pszStrmDrvr; /* name of the stream driver to use */
+ int iStrmDrvrMode; /* mode for stream driver, driver-dependent (0 mostly means plain tcp) */
+ int bResendLastOnRecon; /* should the last message be re-sent on a successful reconnect? */
+ uchar *pszStrmDrvrAuthMode; /* authentication mode to use */
+ int iUDPRebindInterval; /* support for automatic re-binding (load balancers!). 0 - no rebind */
+ int iTCPRebindInterval; /* support for automatic re-binding (load balancers!). 0 - no rebind */
+ permittedPeers_t *pPermPeers;
+} configSettings_t;
+
+SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */
+
+BEGINinitConfVars /* (re)set config variables to default values */
+CODESTARTinitConfVars
+ cs.pszTplName = NULL; /* name of the default template to use */
+ cs.pszStrmDrvr = NULL; /* name of the stream driver to use */
+ cs.iStrmDrvrMode = 0; /* mode for stream driver, driver-dependent (0 mostly means plain tcp) */
+ cs.bResendLastOnRecon = 0; /* should the last message be re-sent on a successful reconnect? */
+ cs.pszStrmDrvrAuthMode = NULL; /* authentication mode to use */
+ cs.iUDPRebindInterval = 0; /* support for automatic re-binding (load balancers!). 0 - no rebind */
+ cs.iTCPRebindInterval = 0; /* support for automatic re-binding (load balancers!). 0 - no rebind */
+ cs.pPermPeers = NULL;
+ENDinitConfVars
-static permittedPeers_t *pPermPeers = NULL;
static rsRetVal doTryResume(instanceData *pData);
@@ -151,6 +169,10 @@ static char *getFwdPt(instanceData *pData)
* This, for example, is needed after something went wrong.
* This function is void because it "can not" fail.
* rgerhards, 2008-06-04
+ * Note that we DO NOT discard the current buffer contents
+ * (if any). This permits us to save data between sessions. In
+ * the wort case, some duplication occurs, but we do not
+ * loose data.
*/
static inline void
DestructTCPInstanceData(instanceData *pData)
@@ -164,6 +186,7 @@ DestructTCPInstanceData(instanceData *pData)
BEGINcreateInstance
CODESTARTcreateInstance
+ pData->offsSndBuf = 0;
ENDcreateInstance
@@ -262,7 +285,7 @@ static rsRetVal
setPermittedPeer(void __attribute__((unused)) *pVal, uchar *pszID)
{
DEFiRet;
- CHKiRet(net.AddPermittedPeer(&pPermPeers, pszID));
+ CHKiRet(net.AddPermittedPeer(&cs.pPermPeers, pszID));
free(pszID); /* no longer needed, but we must free it as of interface def */
finalize_it:
RETiRet;
@@ -273,30 +296,60 @@ finalize_it:
/* CODE FOR SENDING TCP MESSAGES */
-/* Send a frame via plain TCP protocol
- * rgerhards, 2007-12-28
+/* Send a buffer via TCP. Usually, this is used to send the current
+ * send buffer, but if a message is larger than the buffer, we need to
+ * have the capability to send the message buffer directly.
+ * rgerhards, 2011-04-04
*/
-static rsRetVal TCPSendFrame(void *pvData, char *msg, size_t len)
+static rsRetVal
+TCPSendBuf(instanceData *pData, uchar *buf, unsigned len)
{
DEFiRet;
+ unsigned alreadySent;
ssize_t lenSend;
- instanceData *pData = (instanceData *) pvData;
- lenSend = len;
+ alreadySent = 0;
+dbgprintf("omfwd: XXXX: pData %p, pNetStrm %p\n", pData, pData->pNetstrm);
netstrm.CheckConnection(pData->pNetstrm); /* hack for plain tcp syslog - see ptcp driver for details */
- CHKiRet(netstrm.Send(pData->pNetstrm, (uchar*)msg, &lenSend));
- dbgprintf("TCP sent %ld bytes, requested %ld\n", (long) lenSend, (long) len);
+ while(alreadySent != len) {
+ lenSend = len - alreadySent;
+ CHKiRet(netstrm.Send(pData->pNetstrm, buf+alreadySent, &lenSend));
+ DBGPRINTF("omfwd: TCP sent %ld bytes, requested %u\n", (long) lenSend, len - alreadySent);
+ alreadySent += lenSend;
+ }
- if(lenSend != (ssize_t) len) {
- /* no real error, could "just" not send everything...
- * For the time being, we ignore this...
- * rgerhards, 2005-10-25
- */
- dbgprintf("message not completely (tcp)send, ignoring %ld\n", (long) lenSend);
- usleep(1000); /* experimental - might be benefitial in this situation */
- /* TODO: we need to revisit this code -- rgerhards, 2007-12-28 */
+finalize_it:
+ RETiRet;
+}
+
+
+/* Add frame to send buffer (or send, if requried)
+ */
+static rsRetVal TCPSendFrame(void *pvData, char *msg, size_t len)
+{
+ DEFiRet;
+ instanceData *pData = (instanceData *) pvData;
+
+ DBGPRINTF("omfwd: add %u bytes to send buffer (curr offs %u)\n",
+ (unsigned) len, pData->offsSndBuf);
+ if(pData->offsSndBuf != 0 && pData->offsSndBuf + len >= sizeof(pData->sndBuf)) {
+ /* no buffer space left, need to commit previous records */
+ CHKiRet(TCPSendBuf(pData, pData->sndBuf, pData->offsSndBuf));
+ pData->offsSndBuf = 0;
+ iRet = RS_RET_PREVIOUS_COMMITTED;
}
+ /* check if the message is too large to fit into buffer */
+ if(len > sizeof(pData->sndBuf)) {
+ CHKiRet(TCPSendBuf(pData, (uchar*)msg, len));
+ ABORT_FINALIZE(RS_RET_OK); /* committed everything so far */
+ }
+
+ /* we now know the buffer has enough free space */
+ memcpy(pData->sndBuf + pData->offsSndBuf, msg, len);
+ pData->offsSndBuf += len;
+ iRet = RS_RET_DEFER_COMMIT;
+
finalize_it:
RETiRet;
}
@@ -329,7 +382,7 @@ static rsRetVal TCPSendInit(void *pvData)
if(pData->pNetstrm == NULL) {
CHKiRet(netstrms.Construct(&pData->pNS));
/* the stream driver must be set before the object is finalized! */
- CHKiRet(netstrms.SetDrvrName(pData->pNS, pszStrmDrvr));
+ CHKiRet(netstrms.SetDrvrName(pData->pNS, cs.pszStrmDrvr));
CHKiRet(netstrms.ConstructFinalize(pData->pNS));
/* now create the actual stream and connect to the server */
@@ -411,6 +464,13 @@ CODESTARTtryResume
iRet = doTryResume(pData);
ENDtryResume
+
+BEGINbeginTransaction
+CODESTARTbeginTransaction
+dbgprintf("omfwd: beginTransaction\n");
+ENDbeginTransaction
+
+
BEGINdoAction
char *psz = NULL; /* temporary buffering */
register unsigned l;
@@ -477,9 +537,8 @@ CODESTARTdoAction
CHKiRet(UDPSend(pData, psz, l));
} else {
/* forward via TCP */
- rsRetVal ret;
- ret = tcpclt.Send(pData->pTCPClt, pData, psz, l);
- if(ret != RS_RET_OK) {
+ iRet = tcpclt.Send(pData->pTCPClt, pData, psz, l);
+ if(iRet != RS_RET_OK && iRet != RS_RET_DEFER_COMMIT && iRet != RS_RET_PREVIOUS_COMMITTED) {
/* error! */
dbgprintf("error forwarding via tcp, suspending\n");
DestructTCPInstanceData(pData);
@@ -496,6 +555,17 @@ finalize_it:
ENDdoAction
+BEGINendTransaction
+CODESTARTendTransaction
+dbgprintf("omfwd: endTransaction, offsSndBuf %u\n", pData->offsSndBuf);
+ if(pData->offsSndBuf != 0) {
+ iRet = TCPSendBuf(pData, pData->sndBuf, pData->offsSndBuf);
+ pData->offsSndBuf = 0;
+ }
+ENDendTransaction
+
+
+
/* This function loads TCP support, if not already loaded. It will be called
* during config processing. To server ressources, TCP support will only
* be loaded if it actually is used. -- rgerhard, 2008-04-17
@@ -512,7 +582,6 @@ finalize_it:
RETiRet;
}
-
BEGINparseSelectorAct
uchar *q;
int i;
@@ -652,32 +721,32 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1)
}
/* copy over config data as needed */
- pData->iUDPRebindInterval = iUDPRebindInterval;
- pData->iTCPRebindInterval = iTCPRebindInterval;
+ pData->iUDPRebindInterval = cs.iUDPRebindInterval;
+ pData->iTCPRebindInterval = cs.iTCPRebindInterval;
/* process template */
CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS,
- (pszTplName == NULL) ? (uchar*)"RSYSLOG_TraditionalForwardFormat" : pszTplName));
+ (cs.pszTplName == NULL) ? (uchar*)"RSYSLOG_TraditionalForwardFormat" : cs.pszTplName));
if(pData->protocol == FORW_TCP) {
/* create our tcpclt */
CHKiRet(tcpclt.Construct(&pData->pTCPClt));
- CHKiRet(tcpclt.SetResendLastOnRecon(pData->pTCPClt, bResendLastOnRecon));
+ CHKiRet(tcpclt.SetResendLastOnRecon(pData->pTCPClt, cs.bResendLastOnRecon));
/* and set callbacks */
CHKiRet(tcpclt.SetSendInit(pData->pTCPClt, TCPSendInit));
CHKiRet(tcpclt.SetSendFrame(pData->pTCPClt, TCPSendFrame));
CHKiRet(tcpclt.SetSendPrepRetry(pData->pTCPClt, TCPSendPrepRetry));
CHKiRet(tcpclt.SetFraming(pData->pTCPClt, tcp_framing));
CHKiRet(tcpclt.SetRebindInterval(pData->pTCPClt, pData->iTCPRebindInterval));
- pData->iStrmDrvrMode = iStrmDrvrMode;
- if(pszStrmDrvr != NULL)
- CHKmalloc(pData->pszStrmDrvr = (uchar*)strdup((char*)pszStrmDrvr));
- if(pszStrmDrvrAuthMode != NULL)
+ pData->iStrmDrvrMode = cs.iStrmDrvrMode;
+ if(cs.pszStrmDrvr != NULL)
+ CHKmalloc(pData->pszStrmDrvr = (uchar*)strdup((char*)cs.pszStrmDrvr));
+ if(cs.pszStrmDrvrAuthMode != NULL)
CHKmalloc(pData->pszStrmDrvrAuthMode =
- (uchar*)strdup((char*)pszStrmDrvrAuthMode));
- if(pPermPeers != NULL) {
- pData->pPermPeers = pPermPeers;
- pPermPeers = NULL;
+ (uchar*)strdup((char*)cs.pszStrmDrvrAuthMode));
+ if(cs.pPermPeers != NULL) {
+ pData->pPermPeers = cs.pPermPeers;
+ cs.pPermPeers = NULL;
}
}
@@ -691,21 +760,14 @@ ENDparseSelectorAct
static void
freeConfigVars(void)
{
- if(pszTplName != NULL) {
- free(pszTplName);
- pszTplName = NULL;
- }
- if(pszStrmDrvr != NULL) {
- free(pszStrmDrvr);
- pszStrmDrvr = NULL;
- }
- if(pszStrmDrvrAuthMode != NULL) {
- free(pszStrmDrvrAuthMode);
- pszStrmDrvrAuthMode = NULL;
- }
- if(pPermPeers != NULL) {
- free(pPermPeers);
- }
+ free(cs.pszTplName);
+ cs.pszTplName = NULL;
+ free(cs.pszStrmDrvr);
+ cs.pszStrmDrvr = NULL;
+ free(cs.pszStrmDrvrAuthMode);
+ cs.pszStrmDrvrAuthMode = NULL;
+ free(cs.pPermPeers);
+ cs.pPermPeers = NULL; /* TODO: fix in older builds! */
}
@@ -726,6 +788,7 @@ ENDmodExit
BEGINqueryEtryPt
CODESTARTqueryEtryPt
CODEqueryEtryPt_STD_OMOD_QUERIES
+CODEqueryEtryPt_TXIF_OMOD_QUERIES /* we support the transactional interface! */
ENDqueryEtryPt
@@ -737,10 +800,10 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a
freeConfigVars();
/* we now must reset all non-string values */
- iStrmDrvrMode = 0;
- bResendLastOnRecon = 0;
- iUDPRebindInterval = 0;
- iTCPRebindInterval = 0;
+ cs.iStrmDrvrMode = 0;
+ cs.bResendLastOnRecon = 0;
+ cs.iUDPRebindInterval = 0;
+ cs.iTCPRebindInterval = 0;
return RS_RET_OK;
}
@@ -748,20 +811,21 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a
BEGINmodInit(Fwd)
CODESTARTmodInit
+SCOPINGmodInit
*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
CODEmodInit_QueryRegCFSLineHdlr
CHKiRet(objUse(glbl, CORE_COMPONENT));
CHKiRet(objUse(errmsg, CORE_COMPONENT));
CHKiRet(objUse(net,LM_NET_FILENAME));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionforwarddefaulttemplate", 0, eCmdHdlrGetWord, NULL, &pszTplName, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionsendtcprebindinterval", 0, eCmdHdlrInt, NULL, &iTCPRebindInterval, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionsendudprebindinterval", 0, eCmdHdlrInt, NULL, &iUDPRebindInterval, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionsendstreamdriver", 0, eCmdHdlrGetWord, NULL, &pszStrmDrvr, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionsendstreamdrivermode", 0, eCmdHdlrInt, NULL, &iStrmDrvrMode, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionsendstreamdriverauthmode", 0, eCmdHdlrGetWord, NULL, &pszStrmDrvrAuthMode, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionforwarddefaulttemplate", 0, eCmdHdlrGetWord, NULL, &cs.pszTplName, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionsendtcprebindinterval", 0, eCmdHdlrInt, NULL, &cs.iTCPRebindInterval, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionsendudprebindinterval", 0, eCmdHdlrInt, NULL, &cs.iUDPRebindInterval, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionsendstreamdriver", 0, eCmdHdlrGetWord, NULL, &cs.pszStrmDrvr, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionsendstreamdrivermode", 0, eCmdHdlrInt, NULL, &cs.iStrmDrvrMode, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionsendstreamdriverauthmode", 0, eCmdHdlrGetWord, NULL, &cs.pszStrmDrvrAuthMode, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"actionsendstreamdriverpermittedpeer", 0, eCmdHdlrGetWord, setPermittedPeer, NULL, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionsendresendlastmsgonreconnect", 0, eCmdHdlrBinary, NULL, &bResendLastOnRecon, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionsendresendlastmsgonreconnect", 0, eCmdHdlrBinary, NULL, &cs.bResendLastOnRecon, NULL));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
ENDmodInit
diff --git a/tools/ompipe.c b/tools/ompipe.c
index 52f1c60e..2bd7f7b2 100644
--- a/tools/ompipe.c
+++ b/tools/ompipe.c
@@ -73,6 +73,16 @@ typedef struct _instanceData {
short fd; /* pipe descriptor for (current) pipe */
} instanceData;
+typedef struct configSettings_s {
+ EMPTY_STRUCT
+} configSettings_t;
+
+SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */
+
+BEGINinitConfVars /* (re)set config variables to default values */
+CODESTARTinitConfVars
+ENDinitConfVars
+
BEGINisCompatibleWithFeature
CODESTARTisCompatibleWithFeature
@@ -235,6 +245,7 @@ ENDqueryEtryPt
BEGINmodInit(Pipe)
CODESTARTmodInit
+SCOPINGmodInit
*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
CODEmodInit_QueryRegCFSLineHdlr
CHKiRet(objUse(errmsg, CORE_COMPONENT));
diff --git a/tools/omshell.c b/tools/omshell.c
index ed205a2f..648d28a4 100644
--- a/tools/omshell.c
+++ b/tools/omshell.c
@@ -57,6 +57,16 @@ typedef struct _instanceData {
} instanceData;
+typedef struct configSettings_s {
+ EMPTY_STRUCT /* remove this when data members are added */
+} configSettings_t;
+
+SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */
+
+BEGINinitConfVars /* (re)set config variables to default values */
+CODESTARTinitConfVars
+ENDinitConfVars
+
BEGINcreateInstance
CODESTARTcreateInstance
ENDcreateInstance
@@ -138,6 +148,7 @@ ENDqueryEtryPt
BEGINmodInit(Shell)
CODESTARTmodInit
+SCOPINGmodInit
*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
CODEmodInit_QueryRegCFSLineHdlr
CHKiRet(objUse(errmsg, CORE_COMPONENT));
diff --git a/tools/omusrmsg.c b/tools/omusrmsg.c
index a8ad568b..dd5c8004 100644
--- a/tools/omusrmsg.c
+++ b/tools/omusrmsg.c
@@ -95,6 +95,16 @@ typedef struct _instanceData {
char uname[MAXUNAMES][UNAMESZ+1];
} instanceData;
+typedef struct configSettings_s {
+ EMPTY_STRUCT
+} configSettings_t;
+
+SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */
+
+BEGINinitConfVars /* (re)set config variables to default values */
+CODESTARTinitConfVars
+ENDinitConfVars
+
BEGINcreateInstance
CODESTARTcreateInstance
@@ -277,9 +287,17 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1)
*/
if(!strncmp((char*) p, ":omusrmsg:", sizeof(":omusrmsg:") - 1)) {
p += sizeof(":omusrmsg:") - 1; /* eat indicator sequence (-1 because of '\0'!) */
- } else if(!*p || !((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z')
- || (*p >= '0' && *p <= '9') || *p == '_' || *p == '.' || *p == '*'))
+ } else {
+ if(!*p || !((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z')
+ || (*p >= '0' && *p <= '9') || *p == '_' || *p == '.' || *p == '*')) {
ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED);
+ } else {
+ errmsg.LogError(0, RS_RET_OUTDATED_STMT,
+ "action '%s' treated as ':omusrmsg:%s' - please "
+ "change syntax, '%s' will not be supported in the future",
+ p, p, p);
+ }
+ }
CHKiRet(createInstance(&pData));
@@ -330,6 +348,7 @@ ENDqueryEtryPt
BEGINmodInit(UsrMsg)
CODESTARTmodInit
+SCOPINGmodInit
*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
CODEmodInit_QueryRegCFSLineHdlr
CHKiRet(objUse(errmsg, CORE_COMPONENT));
diff --git a/tools/syslogd.c b/tools/syslogd.c
index 93f37e4a..9f8c88f4 100644
--- a/tools/syslogd.c
+++ b/tools/syslogd.c
@@ -243,7 +243,6 @@ static int bDebugPrintModuleList = 1;/* output module list in debug mode? */
static int bErrMsgToStderr = 1; /* print error messages to stderr (in addition to everything else)? */
int bReduceRepeatMsgs; /* reduce repeated message - 0 - no, 1 - yes */
int bAbortOnUncleanConfig = 0; /* abort run (rather than starting with partial config) if there was any issue in conf */
-int bActExecWhenPrevSusp; /* execute action only when previous one was suspended? */
/* end global config file state variables */
int MarkInterval = 20 * 60; /* interval between marks in seconds - read-only after startup */
@@ -291,7 +290,6 @@ static int iMainMsgQueueDeqtWinToHr = 25; /* hour begin of time frame when que
static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
{
bLogStatusMsgs = DFLT_bLogStatusMsgs;
- bActExecWhenPrevSusp = 0;
bDebugPrintTemplateList = 1;
bDebugPrintCfSysLineHandlerList = 1;
bDebugPrintModuleList = 1;
@@ -318,7 +316,6 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a
MainMsgQueType = QUEUETYPE_FIXED_ARRAY;
iMainMsgQueMaxDiskSpace = 0;
iMainMsgQueDeqBatchSize = 32;
- glbliActionResumeRetryCount = 0;
return RS_RET_OK;
}
@@ -2050,7 +2047,6 @@ static rsRetVal loadBuildInModules(void)
* This, I think, is the right thing to do. -- rgerhards, 2007-07-31
*/
CHKiRet(regCfSysLineHdlr((uchar *)"logrsyslogstatusmessages", 0, eCmdHdlrBinary, NULL, &bLogStatusMsgs, NULL));
- 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));
@@ -2078,7 +2074,6 @@ static rsRetVal loadBuildInModules(void)
CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuedequeuetimeend", 0, eCmdHdlrInt, NULL, &iMainMsgQueueDeqtWinToHr, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"abortonuncleanconfig", 0, eCmdHdlrBinary, NULL, &bAbortOnUncleanConfig, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"repeatedmsgreduction", 0, eCmdHdlrBinary, NULL, &bReduceRepeatMsgs, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"actionexeconlywhenpreviousissuspended", 0, eCmdHdlrBinary, NULL, &bActExecWhenPrevSusp, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"actionresumeinterval", 0, eCmdHdlrInt, setActionResumeInterval, NULL, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"template", 0, eCmdHdlrCustomHandler, conf.doNameLine, (void*)DIR_TEMPLATE, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"outchannel", 0, eCmdHdlrCustomHandler, conf.doNameLine, (void*)DIR_OUTCHANNEL, NULL));