summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--Makefile.am4
-rw-r--r--configure.ac16
-rw-r--r--doc/Makefile.am1
-rw-r--r--doc/imuxsock.html2
-rw-r--r--doc/omuxsock.html43
-rw-r--r--doc/rsyslog_conf_modules.html1
-rw-r--r--plugins/omuxsock/Makefile.am8
-rw-r--r--plugins/omuxsock/omuxsock.c315
-rw-r--r--runtime/rsyslog.h1
-rw-r--r--tests/Makefile.am6
-rw-r--r--tests/testsuites/uxsock_simple.conf10
-rwxr-xr-xtests/uxsock_simple.sh31
-rw-r--r--tests/uxsockrcvr.c157
14 files changed, 599 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index f27ddd6b..43be22bd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,5 @@
---------------------------------------------------------------------------
+<<<<<<< HEAD
Version 5.5.7 [V5-BETA] (rgerhards), 2010-08-??
- changed omudpspoof default spoof address to simplify typical use case
thanks to David Lang for suggesting this
@@ -473,6 +474,11 @@ increase.
superior performance (for databases potentially far superior performance)
- increased ompgsql performance by adapting to new transactional
output module interface
+=======
+Version 4.7.3 [v4-devel] (rgerhards), 2010-??-??
+- added omuxsock, which permits to write message to local Unix sockets
+ this is the counterpart to imuxsock, enabling fast local forwarding
+>>>>>>> 80ff634c841d692c1d9f335b88e225d6ce7317f7
---------------------------------------------------------------------------
Version 4.7.2 [v4-devel] (rgerhards), 2010-05-03
- bugfix: problems with atomic operations emulaton
diff --git a/Makefile.am b/Makefile.am
index f4cd98f4..67ae66bc 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -117,6 +117,9 @@ endif
if ENABLE_OMUDPSPOOF
SUBDIRS += plugins/omudpspoof
+
+if ENABLE_OMUXSOCK
+SUBDIRS += plugins/omuxsock
endif
if ENABLE_OMTEMPLATE
@@ -179,6 +182,7 @@ DISTCHECK_CONFIGURE_FLAGS= --enable-gssapi_krb5 \
--enable-omruleset \
--enable-omprog \
--enable-imdiag \
+ --enable-omuxsock \
--enable-shave \
--enable-extended-tests \
--enable-memcheck
diff --git a/configure.ac b/configure.ac
index bcfdaf2f..117c08dc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -909,6 +909,20 @@ AM_CONDITIONAL(ENABLE_GUI, test x$enable_gui = xyes)
AC_SUBST(RELP_CFLAGS)
AC_SUBST(RELP_LIBS)
+
+# settings for omuxsock
+AC_ARG_ENABLE(omuxsock,
+ [AS_HELP_STRING([--enable-omuxsock],[Compiles stdout module @<:@default=no@:>@])],
+ [case "${enableval}" in
+ yes) enable_omuxsock="yes" ;;
+ no) enable_omuxsock="no" ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for --enable-omuxsock) ;;
+ esac],
+ [enable_omuxsock=no]
+)
+AM_CONDITIONAL(ENABLE_OMUXSOCK, test x$enable_omuxsock = xyes)
+
+
# This provides a vehicle to integrate custom modules, that are not
# part of rsyslog, into the build process. It is named cust1, so that
# additional such modules can easily be added.
@@ -983,6 +997,7 @@ AC_CONFIG_FILES([Makefile \
plugins/pmlastmsg/Makefile \
plugins/omruleset/Makefile \
plugins/omdbalerting/Makefile \
+ plugins/omuxsock/Makefile \
plugins/imfile/Makefile \
plugins/imsolaris/Makefile \
plugins/imrelp/Makefile \
@@ -1029,6 +1044,7 @@ echo " omstdout module will be compiled: $enable_omstdout"
echo " omruleset module will be compiled: $enable_omruleset"
echo " omdbalerting module will be compiled: $enable_omdbalerting"
echo " omudpspoof module will be compiled: $enable_omudpspoof"
+echo " omuxsock module will be compiled: $enable_omuxsock"
echo " output template module will be compiled: $enable_omtemplate"
echo
echo "---{ parser modules }---"
diff --git a/doc/Makefile.am b/doc/Makefile.am
index e4e7696b..4b39e633 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -108,6 +108,7 @@ html_files = \
gssapi.html \
licensing.html \
ommail.html \
+ omuxsock.html \
omrelp.html \
syslog_parsing.html \
troubleshoot.html \
diff --git a/doc/imuxsock.html b/doc/imuxsock.html
index 15c365a6..381374d2 100644
--- a/doc/imuxsock.html
+++ b/doc/imuxsock.html
@@ -100,7 +100,7 @@ $InputUnixListenSocketHostName /var/run/sshd/dev/log
<p><font size="2">This documentation is part of the
<a href="http://www.rsyslog.com/">rsyslog</a>
project.<br>
-Copyright © 2008 by <a href="http://www.gerhards.net/rainer">Rainer
+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>
diff --git a/doc/omuxsock.html b/doc/omuxsock.html
new file mode 100644
index 00000000..4ffc53eb
--- /dev/null
+++ b/doc/omuxsock.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><title>Unix sockets output module (omuxsock) - sending syslog messages to local socket</title>
+<a href="features.html">back</a>
+</head>
+<body>
+<h1>Mail Output Module (omuxsock)</h1>
+<p><b>Module Name:&nbsp;&nbsp;&nbsp; omuxsock</b></p>
+<p><b>Available since:&nbsp;&nbsp;&nbsp;</b> 4.7.3, 5.5.7</p>
+<p><b>Author: </b>Rainer Gerhards &lt;rgerhards@adiscon.com&gt;</p>
+<p><b>Description</b>:</p>
+<p>This module supports sending syslog messages to local Unix sockets.
+Thus it provided a fast message-passing interface between different rsyslog
+instances. The counterpart to omuxsock is <a href="imuxsock.html">imuxsock</a>.
+Note that the template used together with omuxsock must be suitable to be
+processed by the receiver.
+<p><b>Configuration Directives</b>:</p>
+<ul>
+<li><b>$OMUxSockSocket</b><br>
+Name of the socket to send data to. This has no default and <b>must</b>
+be set.
+</li>
+<li><b>$OMUxSockDefaultTemplate</b><br>
+This can be used to override the default template to be used together
+with omuxsock. This is primarily useful if there are many forwarding
+actions and each of them should use the same template.</li>
+</ul>
+<b>Caveats/Known Bugs:</b>
+<p>Currently, only datagram sockets are supported.
+<p><b>Sample:</b></p>
+<p>The following sample writes all messages to the "/tmp/socksample" socket.
+</p>
+<textarea rows="4" cols="80">$ModLoad omucsock
+$OMUxSockSocket /tmp/socksample
+*.* :omuxsock:
+</textarea>
+[<a href="manual.html">manual index</a>] [<a href="http://www.rsyslog.com/">rsyslog site</a>]</p>
+<p><font size="2">This documentation is part of the <a href="http://www.rsyslog.com/">rsyslog</a>
+project.<br>
+Copyright &copy; 2010 by <a href="http://www.gerhards.net/rainer">Rainer Gerhards</a> and
+<a href="http://www.adiscon.com/">Adiscon</a>.
+Released under the GNU GPL version 3 or higher.</font></p>
+
+</body></html>
diff --git a/doc/rsyslog_conf_modules.html b/doc/rsyslog_conf_modules.html
index ef83d2ec..213769d2 100644
--- a/doc/rsyslog_conf_modules.html
+++ b/doc/rsyslog_conf_modules.html
@@ -63,6 +63,7 @@ SQLLite, Ingres, Oracle, mSQL)</li>
permits rsyslog to alert folks by mail if something important happens</li>
<li><a href="omoracle.html">omoracle</a> - output module for Oracle (native OCI interface)</li>
<li><a href="omudpspoof.html">omudpspoof</a> - output module sending UDP syslog messages with a spoofed address</li>
+<li><a href="omuxsock.html">omuxsock</a> - output module Unix domain sockets</li>
</ul>
<a name="pm"></a><h2>Parser Modules</h2>
diff --git a/plugins/omuxsock/Makefile.am b/plugins/omuxsock/Makefile.am
new file mode 100644
index 00000000..997232d9
--- /dev/null
+++ b/plugins/omuxsock/Makefile.am
@@ -0,0 +1,8 @@
+pkglib_LTLIBRARIES = omuxsock.la
+
+omuxsock_la_SOURCES = omuxsock.c
+omuxsock_la_CPPFLAGS = $(RSRT_CFLAGS) $(PTHREADS_CFLAGS)
+omuxsock_la_LDFLAGS = -module -avoid-version
+omuxsock_la_LIBADD =
+
+EXTRA_DIST =
diff --git a/plugins/omuxsock/omuxsock.c b/plugins/omuxsock/omuxsock.c
new file mode 100644
index 00000000..c66e63aa
--- /dev/null
+++ b/plugins/omuxsock/omuxsock.c
@@ -0,0 +1,315 @@
+/* omuxsock.c
+ * This is the implementation of datgram unix domain socket forwarding.
+ *
+ * NOTE: read comments in module-template.h to understand how this file
+ * works!
+ *
+ * File begun on 2007-07-20 by RGerhards (extracted from syslogd.c)
+ * This file is under development and has not yet arrived at being fully
+ * self-contained and a real object. So far, it is mostly an excerpt
+ * of the "old" message code without any modifications. However, it
+ * helps to have things at the right place one we go to the meat of it.
+ *
+ * Copyright 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 <time.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <assert.h>
+#include <errno.h>
+#include <unistd.h>
+#include "conf.h"
+#include "srUtils.h"
+#include "template.h"
+#include "msg.h"
+#include "cfsysline.h"
+#include "module-template.h"
+#include "glbl.h"
+#include "errmsg.h"
+#include "unicode-helper.h"
+
+MODULE_TYPE_OUTPUT
+
+/* internal structures
+ */
+DEF_OMOD_STATIC_DATA
+DEFobjCurrIf(errmsg)
+DEFobjCurrIf(glbl)
+
+#define INVLD_SOCK -1
+
+typedef struct _instanceData {
+ permittedPeers_t *pPermPeers;
+ uchar *sockName;
+ int sock;
+ int bIsConnected; /* are we connected to remote host? 0 - no, 1 - yes, UDP means addr resolved */
+ struct sockaddr_un addr;
+} 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 */
+
+static rsRetVal doTryResume(instanceData *pData);
+
+/* Close socket.
+ */
+static inline rsRetVal
+closeSocket(instanceData *pData)
+{
+ DEFiRet;
+ if(pData->sock != INVLD_SOCK) {
+ close(pData->sock);
+ pData->sock = INVLD_SOCK;
+ }
+pData->bIsConnected = 0; // TODO: remove this variable altogether
+ RETiRet;
+}
+
+
+
+BEGINcreateInstance
+CODESTARTcreateInstance
+ pData->sock = INVLD_SOCK;
+ENDcreateInstance
+
+
+BEGINisCompatibleWithFeature
+CODESTARTisCompatibleWithFeature
+ if(eFeat == sFEATURERepeatedMsgReduction)
+ iRet = RS_RET_OK;
+ENDisCompatibleWithFeature
+
+
+BEGINfreeInstance
+CODESTARTfreeInstance
+ /* final cleanup */
+ closeSocket(pData);
+ free(pData->sockName);
+ENDfreeInstance
+
+
+BEGINdbgPrintInstInfo
+CODESTARTdbgPrintInstInfo
+ DBGPRINTF("%s", pData->sockName);
+ENDdbgPrintInstInfo
+
+
+/* Send a message via UDP
+ * rgehards, 2007-12-20
+ */
+static rsRetVal sendMsg(instanceData *pData, char *msg, size_t len)
+{
+ DEFiRet;
+ unsigned lenSent = 0;
+
+ if(pData->sock == INVLD_SOCK) {
+ CHKiRet(doTryResume(pData));
+ }
+
+ if(pData->sock != INVLD_SOCK) {
+ /* we need to track if we have success sending to the remote
+ * peer. Success is indicated by at least one sendto() call
+ * succeeding. We track this be bSendSuccess. We can not simply
+ * rely on lsent, as a call might initially work, but a later
+ * call fails. Then, lsent has the error status, even though
+ * the sendto() succeeded. -- rgerhards, 2007-06-22
+ */
+ lenSent = sendto(pData->sock, msg, len, 0, &pData->addr, sizeof(pData->addr));
+ if(lenSent == len) {
+ int eno = errno;
+ char errStr[1024];
+ DBGPRINTF("omuxsock suspending: sendto(), socket %d, error: %d = %s.\n",
+ pData->sock, eno, rs_strerror_r(eno, errStr, sizeof(errStr)));
+ }
+ }
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* open socket to remote system
+ */
+static inline rsRetVal
+openSocket(instanceData *pData)
+{
+ DEFiRet;
+ assert(pData->sock == INVLD_SOCK);
+
+ if((pData->sock = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
+ char errStr[1024];
+ int eno = errno;
+ DBGPRINTF("error %d creating AF_UNIX/SOCK_DGRAM: %s.\n",
+ eno, rs_strerror_r(eno, errStr, sizeof(errStr)));
+ pData->sock = INVLD_SOCK;
+ ABORT_FINALIZE(RS_RET_NO_SOCKET);
+
+ }
+
+ /* set up server address structure */
+ memset(&pData->addr, 0, sizeof(pData->addr));
+ pData->addr.sun_family = AF_UNIX;
+ strcpy(pData->addr.sun_path, (char*)pData->sockName);
+
+finalize_it:
+ if(iRet != RS_RET_OK) {
+ closeSocket(pData);
+ }
+ RETiRet;
+}
+
+
+
+/* try to resume connection if it is not ready
+ */
+static rsRetVal doTryResume(instanceData *pData)
+{
+ DEFiRet;
+
+ DBGPRINTF("omuxsock trying to resume\n");
+ closeSocket(pData);
+ iRet = openSocket(pData);
+
+ if(iRet != RS_RET_OK) {
+ iRet = RS_RET_SUSPENDED;
+ }
+
+ RETiRet;
+}
+
+
+BEGINtryResume
+CODESTARTtryResume
+ iRet = doTryResume(pData);
+ENDtryResume
+
+BEGINdoAction
+ char *psz = NULL; /* temporary buffering */
+ register unsigned l;
+ int iMaxLine;
+CODESTARTdoAction
+ CHKiRet(doTryResume(pData));
+
+ iMaxLine = glbl.GetMaxLine();
+
+ DBGPRINTF(" omuxsock:%s\n", pData->sockName);
+
+ psz = (char*) ppString[0];
+ l = strlen((char*) psz);
+ if((int) l > iMaxLine)
+ l = iMaxLine;
+
+ CHKiRet(sendMsg(pData, psz, l));
+
+finalize_it:
+ENDdoAction
+
+
+BEGINparseSelectorAct
+CODESTARTparseSelectorAct
+CODE_STD_STRING_REQUESTparseSelectorAct(1)
+
+ /* first check if this config line is actually for us */
+ if(strncmp((char*) p, ":omuxsock:", sizeof(":omuxsock:") - 1)) {
+ ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED);
+ }
+
+ /* ok, if we reach this point, we have something for us */
+ p += sizeof(":omuxsock:") - 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;
+ CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, 0, tplName == NULL ? UCHAR_CONSTANT("RSYSLOG_TraditionalForwardFormat")
+ : tplName ));
+
+ if(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 */
+
+CODE_STD_FINALIZERparseSelectorAct
+ENDparseSelectorAct
+
+
+/* a common function to free our configuration variables - used both on exit
+ * and on $ResetConfig processing. -- rgerhards, 2008-05-16
+ */
+static inline void
+freeConfigVars(void)
+{
+ free(tplName);
+ tplName = NULL;
+ free(sockName);
+ sockName = NULL;
+}
+
+
+BEGINmodExit
+CODESTARTmodExit
+ /* release what we no longer need */
+ objRelease(errmsg, CORE_COMPONENT);
+ objRelease(glbl, CORE_COMPONENT);
+
+ freeConfigVars();
+ENDmodExit
+
+
+BEGINqueryEtryPt
+CODESTARTqueryEtryPt
+CODEqueryEtryPt_STD_OMOD_QUERIES
+ENDqueryEtryPt
+
+
+/* Reset config variables for this module to default values.
+ * rgerhards, 2008-03-28
+ */
+static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
+{
+ freeConfigVars();
+ return RS_RET_OK;
+}
+
+
+BEGINmodInit()
+CODESTARTmodInit
+ *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(regCfSysLineHdlr((uchar *)"omuxsockdefaulttemplate", 0, eCmdHdlrGetWord, NULL, &tplName, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"omuxsocksocket", 0, eCmdHdlrGetWord, NULL, &sockName, NULL));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
+ENDmodInit
+
+/* vim:set ai:
+ */
diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h
index a8b5d401..81b446e3 100644
--- a/runtime/rsyslog.h
+++ b/runtime/rsyslog.h
@@ -449,6 +449,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth
RS_RET_ERR_EPOLL_CTL = -2163, /**< epol_ctll() returned with an unexpected error code */
RS_RET_TIMEOUT = -2164, /**< timeout occured during operation */
RS_RET_RCV_ERR = -2165, /**< error occured during socket rcv operation */
+ RS_RET_NO_SOCK_CONFIGURED = -2166, /**< no socket (name) was configured where one is required */
/* RainerScript error messages (range 1000.. 1999) */
RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 7f9d8cd5..d630da3a 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,6 +1,6 @@
if ENABLE_TESTBENCH
TESTRUNS = rt_init rscript
-check_PROGRAMS = $(TESTRUNS) ourtail nettester tcpflood chkseq msleep randomgen diagtalker
+check_PROGRAMS = $(TESTRUNS) ourtail nettester tcpflood chkseq msleep randomgen diagtalker uxsockrcvr
TESTS = $(TESTRUNS) cfg.sh \
arrayqueue.sh \
linkedlistqueue.sh \
@@ -34,6 +34,7 @@ TESTS = $(TESTRUNS) cfg.sh \
complex1.sh \
queue-persist.sh \
pipeaction.sh \
+ uxsock_simple.sh \
execonlyonce.sh \
execonlywhenprevsuspended.sh \
execonlywhenprevsuspended2.sh \
@@ -224,6 +225,8 @@ EXTRA_DIST= 1.rstest 2.rstest 3.rstest err1.rstest \
testsuites/pipeaction.conf \
pipe_noreader.sh \
testsuites/pipe_noreader.conf \
+ uxsock_simple.sh \
+ testsuites/uxsock_simple.conf \
asynwr_simple.sh \
testsuites/asynwr_simple.conf \
asynwr_timeout.sh \
@@ -293,6 +296,7 @@ EXTRA_DIST= 1.rstest 2.rstest 3.rstest err1.rstest \
testsuites/dircreate_off.conf \
cfg.sh
+uxsockrcvr_SOURCES = uxsockrcvr.c
ourtail_SOURCES = ourtail.c
msleep_SOURCES = msleep.c
chkseq_SOURCES = chkseq.c
diff --git a/tests/testsuites/uxsock_simple.conf b/tests/testsuites/uxsock_simple.conf
new file mode 100644
index 00000000..efffdd90
--- /dev/null
+++ b/tests/testsuites/uxsock_simple.conf
@@ -0,0 +1,10 @@
+# Test for pipe output action (see .sh file for details)
+# rgerhards, 2009-11-05
+$IncludeConfig diag-common.conf
+
+$MainMsgQueueTimeoutShutdown 10000
+
+$ModLoad ../plugins/omuxsock/.libs/omuxsock
+$template outfmt,"%msg:F,58:2%\n"
+$OMUXSockSocket rsyslog-testbench-dgram-uxsock
+:msg, contains, "msgnum:" :omuxsock:;outfmt
diff --git a/tests/uxsock_simple.sh b/tests/uxsock_simple.sh
new file mode 100755
index 00000000..7f00f4bc
--- /dev/null
+++ b/tests/uxsock_simple.sh
@@ -0,0 +1,31 @@
+# This tests basic omuxsock functionality. A socket receiver is started which sends
+# all data to an output file, then a rsyslog instance is started which generates
+# messages and sends them to the unix socket. Datagram sockets are being used.
+# added 2010-08-06 by Rgerhards
+echo ===============================================================================
+echo \[uxsock_simple.sh\]: simple tests for omuxsock functionality
+
+# create the pipe and start a background process that copies data from
+# it to the "regular" work file
+source $srcdir/diag.sh init
+./uxsockrcvr -srsyslog-testbench-dgram-uxsock -orsyslog.out.log &
+BGPROCESS=$!
+echo background uxsockrcvr process id is $BGPROCESS
+
+# now do the usual run
+source $srcdir/diag.sh startup uxsock_simple.conf
+# 10000 messages should be enough
+source $srcdir/diag.sh injectmsg 0 10000
+source $srcdir/diag.sh shutdown-when-empty # shut down rsyslogd when done processing messages
+source $srcdir/diag.sh wait-shutdown
+
+# wait for the cp process to finish, do pipe-specific cleanup
+echo shutting down uxsockrcvr...
+# TODO: we should do this more reliable in the long run! (message counter? timeout?)
+kill $BGPROCESS
+wait $BGPROCESS
+echo background process has terminated, continue test...
+
+# and continue the usual checks
+source $srcdir/diag.sh seq-check 0 9999
+source $srcdir/diag.sh exit
diff --git a/tests/uxsockrcvr.c b/tests/uxsockrcvr.c
new file mode 100644
index 00000000..551f0ef3
--- /dev/null
+++ b/tests/uxsockrcvr.c
@@ -0,0 +1,157 @@
+/* receives messages from a specified unix sockets and writes
+ * output to specfied file.
+ *
+ * Command line options:
+ * -s name of socket (required)
+ * -o name of output file (stdout if not given)
+ * -l add newline after each message received (default: do not add anything)
+ *
+ * Part of the testbench for rsyslog.
+ *
+ * Copyright 2010 Rainer Gerhards and Adiscon GmbH.
+ *
+ * This file is part of rsyslog.
+ *
+ * Rsyslog is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Rsyslog is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Rsyslog. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * A copy of the GPL can be found in the file "COPYING" in this distribution.
+ */
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <getopt.h>
+#include <sys/un.h>
+#include <netdb.h>
+
+char *sockName = NULL;
+int sock;
+int addNL = 0;
+
+
+/* called to clean up on exit
+ */
+void
+cleanup(void)
+{
+ unlink(sockName);
+ close(sock);
+}
+
+
+void
+doTerm(int __attribute__((unused)) signum)
+{
+ exit(1);
+}
+
+
+void
+usage(void)
+{
+ fprintf(stderr, "usage: uxsockrcvr -s /socket/name -o /output/file -l\n"
+ "-l adds newline after each message received\n"
+ "-s MUST be specified\n"
+ "if -o ist not specified, stdout is used\n");
+ exit(1);
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ int opt;
+ int rlen;
+ FILE *fp = stdout;
+ unsigned char data[128*1024];
+ struct sockaddr_un addr; /* address of server */
+ struct sockaddr from;
+ socklen_t fromlen;
+
+ if(argc < 2) {
+ fprintf(stderr, "error: too few arguments!\n");
+ usage();
+ }
+
+ while((opt = getopt(argc, argv, "s:o:l")) != EOF) {
+ switch((char)opt) {
+ case 'l':
+ addNL = 1;
+ break;
+ case 's':
+ sockName = optarg;
+ break;
+ case 'o':
+ if((fp = fopen(optarg, "w")) == NULL) {
+ perror(optarg);
+ exit(1);
+ }
+ break;
+ default:usage();
+ }
+ }
+
+ if(sockName == NULL) {
+ fprintf(stderr, "error: -s /socket/name must be specified!\n");
+ exit(1);
+ }
+
+ if(signal(SIGTERM, doTerm) == SIG_ERR) {
+ perror("signal(SIGTERM, ...)");
+ exit(1);
+ }
+ if(signal(SIGINT, doTerm) == SIG_ERR) {
+ perror("signal(SIGINT, ...)");
+ exit(1);
+ }
+
+ /* Create a UNIX datagram socket for server */
+ if ((sock = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
+ perror("server: socket");
+ exit(1);
+ }
+
+ atexit(cleanup);
+
+ /* Set up address structure for server socket */
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ strcpy(addr.sun_path, sockName);
+
+ if (bind(sock, (struct sockaddr*) &addr, sizeof(addr)) < 0) {
+ close(sock);
+ perror("server: bind");
+ exit(1);
+ }
+
+ /* we now run in an endless loop. We do not check who sends us
+ * data. This should be no problem for our testbench use.
+ */
+ while(1) {
+ fromlen = sizeof(from);
+ rlen = recvfrom(sock, data, 2000, 0, &from, &fromlen);
+ if(rlen == -1) {
+ perror("uxsockrcvr : recv\n");
+ exit(1);
+ } else {
+ fwrite(data, 1, rlen, fp);
+ if(addNL)
+ fputc('\n', fp);
+ }
+ }
+
+ return 0;
+}