summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRainer Gerhards <rgerhards@adiscon.com>2009-04-09 13:50:35 +0200
committerRainer Gerhards <rgerhards@adiscon.com>2009-04-09 13:50:35 +0200
commit4bd01053c5efd872d79baee7e23e0dbcdc4167ba (patch)
treee814663e63c81dfc8f53f7b5a1b3eea54f208a73
parent9b34b305d8de2012a969675148950b7e10a1924b (diff)
parentde38f744de1ce746e6e61098fd4a05ac76ef71a0 (diff)
downloadrsyslog-4bd01053c5efd872d79baee7e23e0dbcdc4167ba.tar.gz
rsyslog-4bd01053c5efd872d79baee7e23e0dbcdc4167ba.tar.xz
rsyslog-4bd01053c5efd872d79baee7e23e0dbcdc4167ba.zip
Merge branch 'tcpflood' into nextmaster
Conflicts: ChangeLog
-rw-r--r--ChangeLog4
-rw-r--r--tests/Makefile.am7
-rw-r--r--tests/chkseq.c76
-rwxr-xr-xtests/manytcp.sh13
-rwxr-xr-xtests/tcpfloodbin0 -> 17972 bytes
-rw-r--r--tests/tcpflood.c245
-rw-r--r--tools/syslogd.c8
7 files changed, 342 insertions, 11 deletions
diff --git a/ChangeLog b/ChangeLog
index db0efb1a..792c108c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -5,7 +5,9 @@ Version 4.3.0 [DEVEL] (rgerhards), 2009-03-??
performance. This is also necessary towards the long-term goal
of loadable library modules.
- added new RainerScript function "tolower"
-- improved testbench, added tests for tcp-based reception
+- improved testbench
+ * added tests for tcp-based reception
+ * added tcp-load test (1000 connections, 20,000 messages)
- bugfix: solved potential memory leak in msg processing, could manifest
itself in imtcp
---------------------------------------------------------------------------
diff --git a/tests/Makefile.am b/tests/Makefile.am
index fa662a3e..53a81a93 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,6 +1,6 @@
TESTRUNS = rt_init rscript
-check_PROGRAMS = $(TESTRUNS) ourtail nettester
-TESTS = $(TESTRUNS) cfg.sh parsertest.sh omod-if-array.sh
+check_PROGRAMS = $(TESTRUNS) ourtail nettester tcpflood chkseq
+TESTS = $(TESTRUNS) cfg.sh parsertest.sh omod-if-array.sh manytcp.sh
TESTS_ENVIRONMENT = RSYSLOG_MODDIR='$(abs_top_builddir)'/runtime/.libs/
DISTCLEANFILES=rsyslog.pid
test_files = testbench.h runtime-dummy.c
@@ -27,10 +27,13 @@ EXTRA_DIST= 1.rstest 2.rstest 3.rstest err1.rstest \
testsuites/omod-if-array.conf \
testsuites/1.omod-if-array \
parsertest.sh \
+ manytcp.sh \
omod-if-array.sh \
cfg.sh
ourtail_SOURCES = ourtail.c
+tcpflood_SOURCES = tcpflood.c
+chkseq_SOURCES = chkseq.c
nettester_SOURCES = nettester.c getline.c
nettester_LDADD = $(SOL_LIBS)
diff --git a/tests/chkseq.c b/tests/chkseq.c
new file mode 100644
index 00000000..3203c250
--- /dev/null
+++ b/tests/chkseq.c
@@ -0,0 +1,76 @@
+/* Checks if a file consists of line of strictly monotonically
+ * increasing numbers. An expected start and end number may
+ * be set.
+ *
+ * Params
+ * argv[1] file to check
+ * argv[2] start number
+ * argv[3] end number
+ *
+ * Part of the testbench for rsyslog.
+ *
+ * Copyright 2009 Rainer Gerhards and Adiscon GmbH.
+ *
+ * This file is part of rsyslog.
+ *
+ * Rsyslog is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Rsyslog is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Rsyslog. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * A copy of the GPL can be found in the file "COPYING" in this distribution.
+ */
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char *argv[])
+{
+ FILE *fp;
+ int val;
+ int i;
+ int ret = 0;
+ int start, end;
+
+ if(argc != 4) {
+ printf("Invalid call of chkseq\n");
+ printf("Usage: chkseq file start end\n");
+ exit(1);
+ }
+
+ start = atoi(argv[2]);
+ end = atoi(argv[3]);
+
+ if(start > end) {
+ printf("start must be less than or equal end!\n");
+ exit(1);
+ }
+
+ /* read file */
+ fp = fopen(argv[1], "r");
+ if(fp == NULL) {
+ perror(argv[1]);
+ exit(1);
+ }
+
+ for(i = start ; i < end ; ++i) {
+ if(fscanf(fp, "%d\n", &val) != 1) {
+ printf("scanf error in index i=%d\n", i);
+ exit(1);
+ }
+ if(val != i) {
+ printf("read value %d, but expected value %d\n", val, i);
+ exit(1);
+ }
+ }
+
+ exit(ret);
+}
diff --git a/tests/manytcp.sh b/tests/manytcp.sh
new file mode 100755
index 00000000..3accfb8a
--- /dev/null
+++ b/tests/manytcp.sh
@@ -0,0 +1,13 @@
+rm -f rsyslog.out.log # work file
+../tools/rsyslogd -c4 -u2 -n -irsyslog.pid -M../runtime/.libs:../.libs -ftestsuites/manytcp.conf &
+echo "rsyslogd started with pid " `cat rsyslog.pid`
+./tcpflood 127.0.0.1 13514 1000 20000
+sleep 1
+kill `cat rsyslog.pid`
+rm -f work
+sort < rsyslog.out.log > work
+./chkseq work 0 19999
+if [ "$?" -ne "0" ]; then
+ echo "sequence error detected"
+ exit 1
+fi
diff --git a/tests/tcpflood b/tests/tcpflood
new file mode 100755
index 00000000..ae00fcd5
--- /dev/null
+++ b/tests/tcpflood
Binary files differ
diff --git a/tests/tcpflood.c b/tests/tcpflood.c
new file mode 100644
index 00000000..83f0d1ee
--- /dev/null
+++ b/tests/tcpflood.c
@@ -0,0 +1,245 @@
+/* Opens a large number of tcp connections and sends
+ * messages over them. This is used for stress-testing.
+ *
+ * Params
+ * argv[1] target address
+ * argv[2] target port
+ * argv[3] number of connections
+ * argv[4] number of messages to send (connection is random)
+ *
+ * Part of the testbench for rsyslog.
+ *
+ * Copyright 2009 Rainer Gerhards and Adiscon GmbH.
+ *
+ * This file is part of rsyslog.
+ *
+ * Rsyslog is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Rsyslog is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Rsyslog. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * A copy of the GPL can be found in the file "COPYING" in this distribution.
+ */
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <assert.h>
+#include <unistd.h>
+#include <string.h>
+#include <netinet/in.h>
+
+#define EXIT_FAILURE 1
+#define INVALID_SOCKET -1
+/* Name of input file, must match $IncludeConfig in test suite .conf files */
+#define NETTEST_INPUT_CONF_FILE "nettest.input.conf" /* name of input file, must match $IncludeConfig in .conf files */
+
+static char *targetIP;
+static int targetPort;
+static int numMsgsToSend; /* number of messages to send */
+static int numConnections; /* number of connections to create */
+static int *sockArray; /* array of sockets to use */
+
+
+/* open a single tcp connection
+ */
+int openConn(int *fd)
+{
+ int sock;
+ struct sockaddr_in addr;
+
+ if((sock=socket(AF_INET, SOCK_STREAM, 0))==-1) {
+ perror("socket()");
+ return(1);
+ }
+
+ memset((char *) &addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(targetPort);
+ if(inet_aton(targetIP, &addr.sin_addr)==0) {
+ fprintf(stderr, "inet_aton() failed\n");
+ return(1);
+ }
+ if(connect(sock, (struct sockaddr*)&addr, sizeof(addr)) != 0) {
+ perror("connect()");
+ fprintf(stderr, "connect() failed\n");
+ return(1);
+ }
+
+ *fd = sock;
+ return 0;
+}
+
+
+/* open all requested tcp connections
+ * this includes allocating the connection array
+ */
+int openConnections(void)
+{
+ int i;
+ char msgBuf[128];
+ size_t lenMsg;
+
+ write(1, " open connections", sizeof(" open connections")-1);
+ sockArray = calloc(numConnections, sizeof(int));
+ for(i = 0 ; i < numConnections ; ++i) {
+ if(i % 10 == 0) {
+ lenMsg = sprintf(msgBuf, "\retb\b\b\b\b%5.5d", i);
+ write(1, msgBuf, lenMsg);
+ }
+ if(openConn(&(sockArray[i])) != 0) {
+ printf("error in trying to open connection i=%d\n", i);
+ return 1;
+ }
+ }
+ lenMsg = sprintf(msgBuf, "\retb\b\b\b\b%5.5d open connections\n", i);
+ write(1, msgBuf, lenMsg);
+
+ return 0;
+}
+
+
+/* send messages to the tcp connections we keep open. We use
+ * a very basic format that helps identify the message
+ * (via msgnum:<number>: e.g. msgnum:00000001:). This format is suitable
+ * for extracton to field-based properties.
+ * The first numConnection messages are sent sequentially, as are the
+ * last. All messages in between are sent over random connections.
+ * Note that message numbers start at 0.
+ */
+int sendMessages(void)
+{
+ int i;
+ int socknum;
+ int lenBuf;
+ char buf[2048];
+ char msgBuf[128];
+ size_t lenMsg;
+
+ srand(time(NULL)); /* seed is good enough for our needs */
+
+ lenMsg = sprintf(msgBuf, "\retb\b\b\b\b%5.5d messages sent", 0);
+ write(1, msgBuf, lenMsg);
+ for(i = 0 ; i < numMsgsToSend ; ++i) {
+ if(i < numConnections)
+ socknum = i;
+ else if(i >= numMsgsToSend - numConnections)
+ socknum = i - (numMsgsToSend - numConnections);
+ else
+ socknum = rand() % numConnections;
+ lenBuf = sprintf(buf, "<167>Mar 1 01:00:00 172.20.245.8 tag msgnum:%8.8d:\n", i);
+ if(send(sockArray[socknum], buf, lenBuf, 0) != lenBuf) {
+ perror("send test data");
+ fprintf(stderr, "send() failed\n");
+ return(1);
+ }
+ if(i % 100 == 0) {
+ lenMsg = sprintf(msgBuf, "\retb\b\b\b\b%5.5d", i);
+ write(1, msgBuf, lenMsg);
+ }
+ }
+ lenMsg = sprintf(msgBuf, "\retb\b\b\b\b%5.5d messages sent\n", i);
+ write(1, msgBuf, lenMsg);
+
+ return 0;
+}
+
+
+/* send a message via TCP
+ * We open the connection on the initial send, and never close it
+ * (let the OS do that). If a conneciton breaks, we do NOT try to
+ * recover, so all test after that one will fail (and the test
+ * driver probably hang. returns 0 if ok, something else otherwise.
+ * We use traditional framing '\n' at EOR for this tester. It may be
+ * worth considering additional framing modes.
+ * rgerhards, 2009-04-08
+ */
+int
+tcpSend(char *buf, int lenBuf)
+{
+ static int sock = INVALID_SOCKET;
+ struct sockaddr_in addr;
+
+ if(sock == INVALID_SOCKET) {
+ /* first time, need to connect to target */
+ if((sock=socket(AF_INET, SOCK_STREAM, 0))==-1) {
+ perror("socket()");
+ return(1);
+ }
+
+ memset((char *) &addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(13514);
+ if(inet_aton("127.0.0.1", &addr.sin_addr)==0) {
+ fprintf(stderr, "inet_aton() failed\n");
+ return(1);
+ }
+ if(connect(sock, (struct sockaddr*)&addr, sizeof(addr)) != 0) {
+ fprintf(stderr, "connect() failed\n");
+ return(1);
+ }
+ }
+
+ /* send test data */
+ if(send(sock, buf, lenBuf, 0) != lenBuf) {
+ perror("send test data");
+ fprintf(stderr, "send() failed\n");
+ return(1);
+ }
+
+ /* send record terminator */
+ if(send(sock, "\n", 1, 0) != 1) {
+ perror("send record terminator");
+ fprintf(stderr, "send() failed\n");
+ return(1);
+ }
+
+ return 0;
+}
+
+
+/* Run the test suite. This must be called with exactly one parameter, the
+ * name of the test suite. For details, see file header comment at the top
+ * of this file.
+ * rgerhards, 2009-04-03
+ */
+int main(int argc, char *argv[])
+{
+ int ret = 0;
+ static char buf[1024];
+
+ setvbuf(stdout, _IONBF, buf, 48);
+
+ if(argc != 5) {
+ printf("Invalid call of tcpflood\n");
+ printf("Usage: tcpflood target-host target-port num-connections num-messages\n");
+ exit(1);
+ }
+
+ targetIP = argv[1];
+ targetPort = atoi(argv[2]);
+ numConnections = atoi(argv[3]);
+ numMsgsToSend = atoi(argv[4]);
+
+ if(openConnections() != 0) {
+ printf("error opening connections\n");
+ exit(1);
+ }
+
+ if(sendMessages() != 0) {
+ printf("error sending messages\n");
+ exit(1);
+ }
+ exit(ret);
+}
diff --git a/tools/syslogd.c b/tools/syslogd.c
index 0badac19..a4f0059b 100644
--- a/tools/syslogd.c
+++ b/tools/syslogd.c
@@ -3591,18 +3591,10 @@ int realMain(int argc, char **argv)
fprintf(stderr, "-t option only supported in compatibility modes 0 to 2 - ignored\n");
break;
case 'T':/* chroot() immediately at program startup, but only for testing, NOT security yet */
-{
-char buf[1024];
-getcwd(buf, 1024);
-printf("pwd: '%s'\n", buf);
-printf("chroot to '%s'\n", arg);
if(chroot(arg) != 0) {
perror("chroot");
exit(1);
}
-getcwd(buf, 1024);
-printf("pwd: '%s'\n", buf);
-}
break;
case 'u': /* misc user settings */
iHelperUOpt = atoi(arg);