From 7e1060295a63242bc22394b6873de6e6db2b4765 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 25 Mar 2010 11:21:10 +0100 Subject: manytcp test tool must tell OS to provide enough file handles On some platforms, the default is too low to carry out all test cases --- tests/tcpflood.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'tests/tcpflood.c') diff --git a/tests/tcpflood.c b/tests/tcpflood.c index 32bf959d..259b84b3 100644 --- a/tests/tcpflood.c +++ b/tests/tcpflood.c @@ -370,6 +370,20 @@ int main(int argc, char *argv[]) } } + if(numConnections > 20) { + /* if we use many (whatever this means, 20 is randomly picked) + * connections, we need to make sure we have a high enough + * limit. -- rgerhards, 2010-03-25 + */ + struct rlimit maxFiles; + maxFiles.rlim_cur = numConnections + 20; + maxFiles.rlim_max = numConnections + 20; + if(setrlimit(RLIMIT_NOFILE, &maxFiles) < 0) { + perror("setrlimit to increase file handles failed"); + exit(1); + } + } + if(openConnections() != 0) { printf("error opening connections\n"); exit(1); -- cgit v1.2.3 From b628ec633ebd8bdf2e1ddb168b7b63ea2c1bb87c Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 25 Mar 2010 17:21:36 +0100 Subject: added missing header --- tests/tcpflood.c | 1 + 1 file changed, 1 insertion(+) (limited to 'tests/tcpflood.c') diff --git a/tests/tcpflood.c b/tests/tcpflood.c index 259b84b3..68c1c097 100644 --- a/tests/tcpflood.c +++ b/tests/tcpflood.c @@ -54,6 +54,7 @@ #include #include #include +#include #define EXIT_FAILURE 1 #define INVALID_SOCKET -1 -- cgit v1.2.3 From 2cd132eebb84dbcffcf0c20b9354c14f797c29cd Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 7 Apr 2010 12:42:41 +0200 Subject: enhanced nettester tool so that it re-uses it's callers environment this enables us to work with the "usual" environment tweaks (for debugging and other purposes), without the need for any special handling in nettester itself --- tests/tcpflood.c | 142 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 109 insertions(+), 33 deletions(-) (limited to 'tests/tcpflood.c') diff --git a/tests/tcpflood.c b/tests/tcpflood.c index 68c1c097..e92d1308 100644 --- a/tests/tcpflood.c +++ b/tests/tcpflood.c @@ -20,6 +20,14 @@ * one field to the right. Zero (default) disables this functionality. * -M the message to be sent. Disables all message format options, as * only that exact same message is sent. + * -I read specified input file, do NOT generate own test data. The test + * completes when eof is reached. + * -B The specified file (-I) is binary. No data processing is done by + * tcpflood. If multiple connections are specified, data is read in + * chunks and spread across the connections without taking any record + * delemiters into account. + * -C when input from a file is read, this file is transmitted -C times + * (C like cycle, running out of meaningful option switches ;)) * * Part of the testbench for rsyslog. * @@ -76,6 +84,10 @@ static int *sockArray; /* array of sockets to use */ static int msgNum = 0; /* initial message number to start with */ static int bShowProgress = 1; /* show progress messages */ static char *MsgToSend = NULL; /* if non-null, this is the actual message to send */ +static int bBinaryFile = 0; /* is -I file binary */ +static char *dataFile = NULL; /* name of data file, if NULL, generate own data */ +static int numFileIterations = 1;/* how often is file data to be sent? */ +FILE *dataFP = NULL; /* file pointer for data file, if used */ /* open a single tcp connection @@ -167,8 +179,8 @@ int openConnections(void) void closeConnections(void) { int i; - char msgBuf[128]; size_t lenMsg; + char msgBuf[128]; if(bShowProgress) write(1, " close connections", sizeof(" close connections")-1); @@ -187,6 +199,62 @@ void closeConnections(void) } +/* generate the message to be sent according to program command line parameters. + * this has been moved to its own function as we now have various different ways + * of constructing test messages. -- rgerhards, 2010-03-31 + */ +static inline void +genMsg(char *buf, size_t maxBuf, int *pLenBuf) +{ + int edLen; /* actual extra data length to use */ + char extraData[MAX_EXTRADATA_LEN + 1]; + char dynFileIDBuf[128] = ""; + static int numMsgsGen = 0; + int done; + + if(dataFP != NULL) { + /* get message from file */ + do { + done = 1; + *pLenBuf = fread(buf, 1, 1024, dataFP); + if(feof(dataFP)) { + if(--numFileIterations > 0) { + rewind(dataFP); + done = 0; /* need new iteration */ + } else { + *pLenBuf = 0; + goto finalize_it; + } + } + } while(!done); /* Attention: do..while()! */ + } else if(MsgToSend == NULL) { + if(dynFileIDs > 0) { + snprintf(dynFileIDBuf, maxBuf, "%d:", rand() % dynFileIDs); + } + if(extraDataLen == 0) { + *pLenBuf = snprintf(buf, maxBuf, "<%s>Mar 1 01:00:00 172.20.245.8 tag msgnum:%s%8.8d:\n", + msgPRI, dynFileIDBuf, msgNum); + } else { + if(bRandomizeExtraData) + edLen = ((long) rand() + extraDataLen) % extraDataLen + 1; + else + edLen = extraDataLen; + memset(extraData, 'X', edLen); + extraData[edLen] = '\0'; + *pLenBuf = snprintf(buf, maxBuf, "<%s>Mar 1 01:00:00 172.20.245.8 tag msgnum:%s%8.8d:%d:%s\n", + msgPRI, dynFileIDBuf, msgNum, edLen, extraData); + } + } else { + /* use fixed message format from command line */ + *pLenBuf = snprintf(buf, maxBuf, "%s\n", MsgToSend); + } + + if(numMsgsGen++ >= numMsgsToSend) + *pLenBuf = 0; /* indicate end of run */ + +finalize_it: ; +} + /* send messages to the tcp connections we keep open. We use * a very basic format that helps identify the message * (via msgnum:: e.g. msgnum:00000001:). This format is suitable @@ -197,52 +265,42 @@ void closeConnections(void) */ int sendMessages(void) { - int i; + int i = 0; int socknum; int lenBuf; int lenSend; - int edLen; /* actual extra data length to use */ - char dynFileIDBuf[128] = ""; + char *statusText; char buf[MAX_EXTRADATA_LEN + 1024]; - char extraData[MAX_EXTRADATA_LEN + 1]; - printf("Sending %d messages.\n", numMsgsToSend); + if(dataFile == NULL) { + printf("Sending %d messages.\n", numMsgsToSend); + statusText = "messages"; + } else { + printf("Sending file '%s' %d times.\n", dataFile, numFileIterations); + statusText = "kb"; + } if(bShowProgress) - printf("\r%8.8d messages sent", 0); - for(i = 0 ; i < numMsgsToSend ; ++i) { + printf("\r%8.8d %s sent", 0, statusText); + while(1) { /* broken inside loop! */ if(i < numConnections) socknum = i; else if(i >= numMsgsToSend - numConnections) socknum = i - (numMsgsToSend - numConnections); - else - socknum = rand() % numConnections; - if(MsgToSend == NULL) { - if(dynFileIDs > 0) { - sprintf(dynFileIDBuf, "%d:", rand() % dynFileIDs); - } - if(extraDataLen == 0) { - lenBuf = sprintf(buf, "<%s>Mar 1 01:00:00 172.20.245.8 tag msgnum:%s%8.8d:\n", - msgPRI, dynFileIDBuf, msgNum); - } else { - if(bRandomizeExtraData) - edLen = ((long) rand() + extraDataLen) % extraDataLen + 1; - else - edLen = extraDataLen; - memset(extraData, 'X', edLen); - extraData[edLen] = '\0'; - lenBuf = sprintf(buf, "<%s>Mar 1 01:00:00 172.20.245.8 tag msgnum:%s%8.8d:%d:%s\n", - msgPRI, dynFileIDBuf, msgNum, edLen, extraData); - } - } else { - /* use fixed message format from command line */ - lenBuf = sprintf(buf, "%s\n", MsgToSend); + else { + int rnd = rand(); + //socknum = rand() % numConnections; + socknum = rnd % numConnections; } + genMsg(buf, sizeof(buf), &lenBuf); /* generate the message to send according to params */ + if(lenBuf == 0) + break; /* end of processing! */ lenSend = send(sockArray[socknum], buf, lenBuf, 0); if(lenSend != lenBuf) { printf("\r%5.5d\n", i); fflush(stdout); perror("send test data"); - printf("send() failed at socket %d, index %d, msgNum %d\n", socknum, i, msgNum); + printf("send() failed at socket %d, index %d, msgNum %d\n", + sockArray[socknum], i, msgNum); fflush(stderr); return(1); } @@ -251,8 +309,9 @@ int sendMessages(void) printf("\r%8.8d", i); } ++msgNum; + ++i; } - printf("\r%8.8d messages sent\n", i); + printf("\r%8.8d %s sent\n", i, statusText); return 0; } @@ -336,7 +395,7 @@ int main(int argc, char *argv[]) if(!isatty(1)) bShowProgress = 0; - while((opt = getopt(argc, argv, "f:t:p:c:m:i:P:d:n:M:r")) != -1) { + while((opt = getopt(argc, argv, "f:t:p:c:C:m:i:I:P:d:n:M:rB")) != -1) { switch (opt) { case 't': targetIP = optarg; break; @@ -346,6 +405,8 @@ int main(int argc, char *argv[]) break; case 'c': numConnections = atoi(optarg); break; + case 'C': numFileIterations = atoi(optarg); + break; case 'm': numMsgsToSend = atoi(optarg); break; case 'i': msgNum = atoi(optarg); @@ -365,6 +426,14 @@ int main(int argc, char *argv[]) break; case 'M': MsgToSend = optarg; break; + case 'I': dataFile = optarg; + /* in this mode, we do not know the num messages to send, so + * we set a (high) number to keep the code happy. + */ + numMsgsToSend = 1000000; + break; + case 'B': bBinaryFile = 1; + break; default: printf("invalid option '%c' or value missing - terminating...\n", opt); exit (1); break; @@ -385,6 +454,13 @@ int main(int argc, char *argv[]) } } + if(dataFile != NULL) { + if((dataFP = fopen(dataFile, "r")) == NULL) { + perror(dataFile); + exit(1); + } + } + if(openConnections() != 0) { printf("error opening connections\n"); exit(1); -- cgit v1.2.3 From c664adfa1683763ae503f2da9e8d4d528d6634d1 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 10 Aug 2010 19:34:42 +0200 Subject: more testbench improvements and new tests --- tests/tcpflood.c | 95 ++++++++++++++++++++++---------------------------------- 1 file changed, 37 insertions(+), 58 deletions(-) (limited to 'tests/tcpflood.c') diff --git a/tests/tcpflood.c b/tests/tcpflood.c index d8c3f038..ee43449e 100644 --- a/tests/tcpflood.c +++ b/tests/tcpflood.c @@ -28,6 +28,8 @@ * delemiters into account. * -C when input from a file is read, this file is transmitted -C times * (C like cycle, running out of meaningful option switches ;)) + * -D randomly drop and re-establish connections. Useful for stress-testing + * the TCP receiver. * * Part of the testbench for rsyslog. * @@ -82,11 +84,13 @@ static int numConnections = 1; /* number of connections to create */ static int *sockArray; /* array of sockets to use */ static int msgNum = 0; /* initial message number to start with */ static int bShowProgress = 1; /* show progress messages */ +static int bRandConnDrop = 0; /* randomly drop connections? */ static char *MsgToSend = NULL; /* if non-null, this is the actual message to send */ static int bBinaryFile = 0; /* is -I file binary */ static char *dataFile = NULL; /* name of data file, if NULL, generate own data */ static int numFileIterations = 1;/* how often is file data to be sent? */ FILE *dataFP = NULL; /* file pointer for data file, if used */ +static long nConnDrops = 0; /* counter: number of time connection was dropped (-D option) */ /* open a single tcp connection @@ -153,8 +157,6 @@ int openConnections(void) if(i % 10 == 0) { if(bShowProgress) printf("\r%5.5d", i); - //lenMsg = sprintf(msgBuf, "\r%5.5d", i); - //write(1, msgBuf, lenMsg); } if(openConn(&(sockArray[i])) != 0) { printf("error in trying to open connection i=%d\n", i); @@ -179,6 +181,7 @@ void closeConnections(void) { int i; size_t lenMsg; + struct linger ling; char msgBuf[128]; if(bShowProgress) @@ -190,7 +193,15 @@ void closeConnections(void) write(1, msgBuf, lenMsg); } } - close(sockArray[i]); + if(sockArray[i] != -1) { + /* we try to not overrun the receiver by trying to flush buffers + * *during* close(). -- rgerhards, 2010-08-10 + */ + ling.l_onoff = 1; + ling.l_linger = 1; + setsockopt(sockArray[i], SOL_SOCKET, SO_LINGER, &ling, sizeof(ling)); + close(sockArray[i]); + } } lenMsg = sprintf(msgBuf, "\r%5.5d close connections\n", i); write(1, msgBuf, lenMsg); @@ -287,12 +298,18 @@ int sendMessages(void) socknum = i - (numMsgsToSend - numConnections); else { int rnd = rand(); - //socknum = rand() % numConnections; socknum = rnd % numConnections; } genMsg(buf, sizeof(buf), &lenBuf); /* generate the message to send according to params */ if(lenBuf == 0) break; /* end of processing! */ + if(sockArray[socknum] == -1) { + /* connection was dropped, need to re-establish */ + if(openConn(&(sockArray[socknum])) != 0) { + printf("error in trying to re-open connection %d\n", socknum); + exit(1); + } + } lenSend = send(sockArray[socknum], buf, lenBuf, 0); if(lenSend != lenBuf) { printf("\r%5.5d\n", i); @@ -307,6 +324,16 @@ int sendMessages(void) if(bShowProgress) printf("\r%8.8d", i); } + if(bRandConnDrop) { + /* if we need to randomly drop connections, see if we + * are a victim + */ + if(rand() > (int) (RAND_MAX * 0.95)) { + ++nConnDrops; + close(sockArray[socknum]); + sockArray[socknum] = -1; + } + } ++msgNum; ++i; } @@ -316,59 +343,6 @@ int sendMessages(void) } -/* 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. * rgerhards, 2009-04-03 */ @@ -394,7 +368,7 @@ int main(int argc, char *argv[]) if(!isatty(1)) bShowProgress = 0; - while((opt = getopt(argc, argv, "f:t:p:c:C:m:i:I:P:d:n:M:rB")) != -1) { + while((opt = getopt(argc, argv, "f:t:p:c:C:m:i:I:P:d:Dn:M:rB")) != -1) { switch (opt) { case 't': targetIP = optarg; break; @@ -419,6 +393,8 @@ int main(int argc, char *argv[]) exit(1); } break; + case 'D': bRandConnDrop = 1; + break; case 'r': bRandomizeExtraData = 1; break; case 'f': dynFileIDs = atoi(optarg); @@ -456,7 +432,10 @@ int main(int argc, char *argv[]) exit(1); } + if(nConnDrops > 0) + printf("-D option initiated %ld connection closures\n", nConnDrops); printf("End of tcpflood Run\n"); + closeConnections(); /* this is important so that we do not finish too early! */ exit(ret); } -- cgit v1.2.3 From 809ed1768b83bc0c5392f943f4820523494e8285 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 11 Aug 2010 15:06:50 +0200 Subject: imptcp: added $InputPTCPServerAddtlFrameDelimiter directive also improved testbench --- tests/tcpflood.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'tests/tcpflood.c') diff --git a/tests/tcpflood.c b/tests/tcpflood.c index ee43449e..f3aa4e7f 100644 --- a/tests/tcpflood.c +++ b/tests/tcpflood.c @@ -30,6 +30,7 @@ * (C like cycle, running out of meaningful option switches ;)) * -D randomly drop and re-establish connections. Useful for stress-testing * the TCP receiver. + * -F USASCII value for frame delimiter (in octet-stuffing mode), default LF * * Part of the testbench for rsyslog. * @@ -89,6 +90,7 @@ static char *MsgToSend = NULL; /* if non-null, this is the actual message to sen static int bBinaryFile = 0; /* is -I file binary */ static char *dataFile = NULL; /* name of data file, if NULL, generate own data */ static int numFileIterations = 1;/* how often is file data to be sent? */ +static char frameDelim = '\n'; /* default frame delimiter */ FILE *dataFP = NULL; /* file pointer for data file, if used */ static long nConnDrops = 0; /* counter: number of time connection was dropped (-D option) */ @@ -242,8 +244,8 @@ genMsg(char *buf, size_t maxBuf, int *pLenBuf) snprintf(dynFileIDBuf, maxBuf, "%d:", rand() % dynFileIDs); } if(extraDataLen == 0) { - *pLenBuf = snprintf(buf, maxBuf, "<%s>Mar 1 01:00:00 172.20.245.8 tag msgnum:%s%8.8d:\n", - msgPRI, dynFileIDBuf, msgNum); + *pLenBuf = snprintf(buf, maxBuf, "<%s>Mar 1 01:00:00 172.20.245.8 tag msgnum:%s%8.8d:%c", + msgPRI, dynFileIDBuf, msgNum, frameDelim); } else { if(bRandomizeExtraData) edLen = ((long) rand() + extraDataLen) % extraDataLen + 1; @@ -251,8 +253,8 @@ genMsg(char *buf, size_t maxBuf, int *pLenBuf) edLen = extraDataLen; memset(extraData, 'X', edLen); extraData[edLen] = '\0'; - *pLenBuf = snprintf(buf, maxBuf, "<%s>Mar 1 01:00:00 172.20.245.8 tag msgnum:%s%8.8d:%d:%s\n", - msgPRI, dynFileIDBuf, msgNum, edLen, extraData); + *pLenBuf = snprintf(buf, maxBuf, "<%s>Mar 1 01:00:00 172.20.245.8 tag msgnum:%s%8.8d:%d:%s%c", + msgPRI, dynFileIDBuf, msgNum, edLen, extraData, frameDelim); } } else { /* use fixed message format from command line */ @@ -368,7 +370,7 @@ int main(int argc, char *argv[]) if(!isatty(1)) bShowProgress = 0; - while((opt = getopt(argc, argv, "f:t:p:c:C:m:i:I:P:d:Dn:M:rB")) != -1) { + while((opt = getopt(argc, argv, "f:F:t:p:c:C:m:i:I:P:d:Dn:M:rB")) != -1) { switch (opt) { case 't': targetIP = optarg; break; @@ -399,6 +401,8 @@ int main(int argc, char *argv[]) break; case 'f': dynFileIDs = atoi(optarg); break; + case 'F': frameDelim = atoi(optarg); + break; case 'M': MsgToSend = optarg; break; case 'I': dataFile = optarg; -- cgit v1.2.3