From 2b5a7f10f5cde91a6463a23daeeb7fbab051e642 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 10 Jun 2011 19:49:42 +0200 Subject: somewhat improved debug logging --- runtime/nsd_ptcp.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/runtime/nsd_ptcp.c b/runtime/nsd_ptcp.c index c8915231..69eb7684 100644 --- a/runtime/nsd_ptcp.c +++ b/runtime/nsd_ptcp.c @@ -334,6 +334,12 @@ AcceptConnReq(nsd_t *pNsd, nsd_t **ppNew) iNewSock = accept(pThis->sock, (struct sockaddr*) &addr, &addrlen); if(iNewSock < 0) { + if(Debug) { + char errStr[1024]; + rs_strerror_r(errno, errStr, sizeof(errStr)); + dbgprintf("nds_ptcp: error accepting connection on socket %d, errno %d: %s\n", + pThis->sock, errno, errStr); + } ABORT_FINALIZE(RS_RET_ACCEPT_ERR); } -- cgit v1.2.3 From 2c81df12bcbe85d819a43227cc9adb05d8d0fe29 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 10 Jun 2011 22:50:25 +0200 Subject: 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. Note: this is a backport from v6. In v5, we currently do not have the toolchain to verify the original problem and that it is solved. So this patch is preliminary and subject to change as work progresses. --- ChangeLog | 5 +++++ runtime/nsdsel_gtls.c | 1 + tcpsrv.c | 9 ++++++--- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 665ed184..d28a6bf0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,9 @@ --------------------------------------------------------------------------- +Version 5.8.2 [V5-stable] (rgerhards), 2011-06-?? +- 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] +--------------------------------------------------------------------------- Version 5.8.1 [V5-stable] (rgerhards), 2011-05-19 - bugfix: invalid processing in QUEUE_FULL condition If the the multi-submit interface was used and a QUEUE_FULL condition diff --git a/runtime/nsdsel_gtls.c b/runtime/nsdsel_gtls.c index 1a389a00..aff55af2 100644 --- a/runtime/nsdsel_gtls.c +++ b/runtime/nsdsel_gtls.c @@ -177,6 +177,7 @@ doRetry(nsd_gtls_t *pNsd) finalize_it: if(iRet != RS_RET_OK && iRet != RS_RET_CLOSED && iRet != RS_RET_RETRY) pNsd->bAbortConn = 1; /* request abort */ +dbgprintf("XXXXXX: doRetry: iRet %d, pNsd->bAbortConn %d\n", iRet, pNsd->bAbortConn); RETiRet; } diff --git a/tcpsrv.c b/tcpsrv.c index 9972a135..0b822511 100644 --- a/tcpsrv.c +++ b/tcpsrv.c @@ -556,6 +556,7 @@ RunSelect(tcpsrv_t *pThis) int bIsReady; tcps_sess_t *pNewSess; nssel_t *pSel = NULL; + rsRetVal localRet; ISOBJ_TYPE_assert(pThis, tcpsrv); @@ -604,8 +605,8 @@ RunSelect(tcpsrv_t *pThis) while(nfds && iTCPSess != -1) { if(glbl.GetGlobalInputTermState() == 1) ABORT_FINALIZE(RS_RET_FORCE_TERM); - CHKiRet(nssel.IsReady(pSel, pThis->pSessions[iTCPSess]->pStrm, NSDSEL_RD, &bIsReady, &nfds)); - if(bIsReady) { + localRet = nssel.IsReady(pSel, pThis->pSessions[iTCPSess]->pStrm, NSDSEL_RD, &bIsReady, &nfds); + if(bIsReady || localRet != RS_RET_OK) { doReceive(pThis, &pThis->pSessions[iTCPSess], NULL); --nfds; /* indicate we have processed one */ } @@ -618,7 +619,9 @@ finalize_it: /* this is a very special case - this time only we do not exit the * crashed, which made sense (the rest of the engine was not prepared for * that) -- rgerhards, 2008-05-19 */ - /*EMPTY*/; + if(pSel != NULL) { /* cleanup missing? happens during err exit! */ + nssel.Destruct(&pSel); + } } /* note that this point is usually not reached */ -- cgit v1.2.3 From d5906846156e49cad90736b949712fe17eb8edba Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 14 Jun 2011 11:47:17 +0200 Subject: backported current tcpflood testing tool so that we can improve v5's testbench as well --- tests/Makefile.am | 3 +- tests/tcpflood.c | 609 +++++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 557 insertions(+), 55 deletions(-) diff --git a/tests/Makefile.am b/tests/Makefile.am index 930aa304..8e178ab8 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -426,7 +426,8 @@ uxsockrcvr_SOURCES = uxsockrcvr.c uxsockrcvr_LDADD = $(SOL_LIBS) tcpflood_SOURCES = tcpflood.c -tcpflood_LDADD = $(SOL_LIBS) +tcpflood_CPPFLAGS = $(PTHREADS_CFLAGS) +tcpflood_LDADD = $(SOL_LIBS) $(PTHREADS_LIBS) syslog_caller_SOURCES = syslog_caller.c syslog_caller_LDADD = $(SOL_LIBS) diff --git a/tests/tcpflood.c b/tests/tcpflood.c index 3e7053c9..49b1e9e6 100644 --- a/tests/tcpflood.c +++ b/tests/tcpflood.c @@ -16,6 +16,7 @@ * bytes as forth. Add -r to randomize the amount of extra * data included in the range 1..(value of -d). * -r randomize amount of extra data added (-d must be > 0) + * -s (silent) do not show progress indicator (never done on non-tty) * -f support for testing dynafiles. If given, include a dynafile ID * in the range 0..(f-1) as the SECOND field, shifting all field values * one field to the right. Zero (default) disables this functionality. @@ -32,6 +33,24 @@ * -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 + * -R number of times the test shall be run (very useful for gathering performance + * data and other repetitive things). Default: 1 + * -S number of seconds to sleep between different runs (-R) Default: 30 + * -X generate sTats data records. Default: off + * -e encode output in CSV (not yet everywhere supported) + * for performance data: + * each inidividual line has the runtime of one test + * the last line has 0 in field 1, followed by numberRuns,TotalRuntime, + * Average,min,max + * -T transport to use. Currently supported: "udp", "tcp" (default) + * Note: UDP supports a single target port, only + * -W wait time between sending batches of messages, in microseconds (Default: 0) + * -b number of messages within a batch (default: 100,000,000 millions) + * -Y use multiple threads, one per connection (which means 1 if one only connection + * is configured!) + * -z private key file for TLS mode + * -Z cert (public key) file for TLS mode + * -L loglevel to use for GnuTLS troubleshooting (0-off to 10-all, 0 default) * * Part of the testbench for rsyslog. * @@ -66,7 +85,15 @@ #include #include #include +#include #include +#include +#include +#ifdef ENABLE_GNUTLS +# include +# include + GCRY_THREAD_OPTION_PTHREAD_IMPL; +#endif #define EXIT_FAILURE 1 #define INVALID_SOCKET -1 @@ -74,6 +101,7 @@ #define NETTEST_INPUT_CONF_FILE "nettest.input.conf" /* name of input file, must match $IncludeConfig in .conf files */ #define MAX_EXTRADATA_LEN 100*1024 +#define MAX_SENDBUF 2 * MAX_EXTRADATA_LEN static char *targetIP = "127.0.0.1"; static char *msgPRI = "167"; @@ -83,10 +111,11 @@ static int dynFileIDs = 0; static int extraDataLen = 0; /* amount of extra data to add to message */ static int bRandomizeExtraData = 0; /* randomize amount of extra data added */ static int numMsgsToSend; /* number of messages to send */ -static int numConnections = 1; /* number of connections to create */ +static unsigned 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 bSilent = 0; /* completely silent operation */ 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 */ @@ -95,6 +124,75 @@ 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) */ +static int numRuns = 1; /* number of times the test shall be run */ +static int sleepBetweenRuns = 30; /* number of seconds to sleep between runs */ +static int bStatsRecords = 0; /* generate stats records */ +static int bCSVoutput = 0; /* generate output in CSV (where applicable) */ +static long long batchsize = 100000000ll; +static int waittime = 0; +static int runMultithreaded = 0; /* run tests in multithreaded mode */ +static int numThrds = 1; /* number of threads to use */ +static char *tlsCertFile = NULL; +static char *tlsKeyFile = NULL; +static int tlsLogLevel = 0; + +#ifdef ENABLE_GNUTLS +static gnutls_session_t *sessArray; /* array of TLS sessions to use */ +static gnutls_certificate_credentials tlscred; +#endif + +/* variables for managing multi-threaded operations */ +int runningThreads; /* number of threads currently running */ +int doRun; /* shall sender thread begin to run? */ +pthread_mutex_t thrdMgmt; /* mutex for controling startup/shutdown */ +pthread_cond_t condStarted; +pthread_cond_t condDoRun; + +/* the following struct provides information for a generator instance (thread) */ +struct instdata { + /* lower and upper bounds for the thread in question */ + unsigned long long lower; + unsigned long long numMsgs; /* number of messages to send */ + unsigned long long numSent; /* number of messages already sent */ + unsigned idx; /**< index of fd to be used for sending */ + pthread_t thread; /**< thread processing this instance */ +} *instarray = NULL; + +/* the following structure is used to gather performance data */ +struct runstats { + unsigned long long totalRuntime; + unsigned long minRuntime; + unsigned long maxRuntime; + int numRuns; +}; + +static int udpsock; /* socket for sending in UDP mode */ +static struct sockaddr_in udpRcvr; /* remote receiver in UDP mode */ + +static enum { TP_UDP, TP_TCP, TP_TLS } transport = TP_TCP; + +/* forward definitions */ +static void initTLSSess(int); +static int sendTLS(int i, char *buf, int lenBuf); +static void closeTLSSess(int __attribute__((unused)) i); + +/* prepare send subsystem for UDP send */ +static inline int +setupUDP(void) +{ + if((udpsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) + return 1; + + memset((char *) &udpRcvr, 0, sizeof(udpRcvr)); + udpRcvr.sin_family = AF_INET; + udpRcvr.sin_port = htons(targetPort); + if(inet_aton(targetIP, &udpRcvr.sin_addr)==0) { + fprintf(stderr, "inet_aton() failed\n"); + return(1); + } + + return 0; +} /* open a single tcp connection @@ -150,12 +248,18 @@ int openConn(int *fd) */ int openConnections(void) { - int i; + unsigned i; char msgBuf[128]; size_t lenMsg; + if(transport == TP_UDP) + return setupUDP(); + if(bShowProgress) write(1, " open connections", sizeof(" open connections")-1); +# ifdef ENABLE_GNUTLS + sessArray = calloc(numConnections, sizeof(gnutls_session_t)); +# endif sockArray = calloc(numConnections, sizeof(int)); for(i = 0 ; i < numConnections ; ++i) { if(i % 10 == 0) { @@ -166,9 +270,14 @@ int openConnections(void) printf("error in trying to open connection i=%d\n", i); return 1; } + if(transport == TP_TLS) { + initTLSSess(i); + } + } + if(bShowProgress) { + lenMsg = sprintf(msgBuf, "\r%5.5d open connections\n", i); + write(1, msgBuf, lenMsg); } - lenMsg = sprintf(msgBuf, "\r%5.5d open connections\n", i); - write(1, msgBuf, lenMsg); return 0; } @@ -183,11 +292,14 @@ int openConnections(void) */ void closeConnections(void) { - int i; + unsigned i; size_t lenMsg; struct linger ling; char msgBuf[128]; + if(transport == TP_UDP) + return; + if(bShowProgress) write(1, " close connections", sizeof(" close connections")-1); for(i = 0 ; i < numConnections ; ++i) { @@ -204,11 +316,15 @@ void closeConnections(void) ling.l_onoff = 1; ling.l_linger = 1; setsockopt(sockArray[i], SOL_SOCKET, SO_LINGER, &ling, sizeof(ling)); + if(transport == TP_TLS) + closeTLSSess(i); close(sockArray[i]); } } - lenMsg = sprintf(msgBuf, "\r%5.5d close connections\n", i); - write(1, msgBuf, lenMsg); + if(bShowProgress) { + lenMsg = sprintf(msgBuf, "\r%5.5d close connections\n", i); + write(1, msgBuf, lenMsg); + } } @@ -218,12 +334,11 @@ void closeConnections(void) * of constructing test messages. -- rgerhards, 2010-03-31 */ static inline void -genMsg(char *buf, size_t maxBuf, int *pLenBuf) +genMsg(char *buf, size_t maxBuf, int *pLenBuf, struct instdata *inst) { 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) { @@ -262,11 +377,9 @@ genMsg(char *buf, size_t maxBuf, int *pLenBuf) /* use fixed message format from command line */ *pLenBuf = snprintf(buf, maxBuf, "%s\n", MsgToSend); } + ++inst->numSent; - if(numMsgsGen++ >= numMsgsToSend) - *pLenBuf = 0; /* indicate end of run */ - -finalize_it: ; +finalize_it: /*EMPTY to keep the compiler happy */; } /* send messages to the tcp connections we keep open. We use @@ -277,50 +390,72 @@ finalize_it: ; * last. All messages in between are sent over random connections. * Note that message numbers start at 0. */ -int sendMessages(void) +int sendMessages(struct instdata *inst) { - int i = 0; + unsigned i = 0; int socknum; int lenBuf; - int lenSend; - char *statusText; + int lenSend = 0; + char *statusText = ""; char buf[MAX_EXTRADATA_LEN + 1024]; + char sendBuf[MAX_SENDBUF]; + int offsSendBuf = 0; - if(dataFile == NULL) { - printf("Sending %d messages.\n", numMsgsToSend); - statusText = "messages"; - } else { - printf("Sending file '%s' %d times.\n", dataFile, numFileIterations); - statusText = "kb"; + if(!bSilent) { + if(dataFile == NULL) { + printf("Sending %llu messages.\n", inst->numMsgs); + statusText = "messages"; + } else { + printf("Sending file '%s' %d times.\n", dataFile, + numFileIterations); + statusText = "kb"; + } } if(bShowProgress) 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 { - int rnd = rand(); - socknum = rnd % numConnections; + while(i < inst->numMsgs) { + if(runMultithreaded) { + socknum = inst->idx; + } else { + if(i < numConnections) + socknum = i; + else if(i >= inst->numMsgs - numConnections) { + socknum = i - (inst->numMsgs - numConnections); + } else { + int rnd = rand(); + 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); + genMsg(buf, sizeof(buf), &lenBuf, inst); /* generate the message to send according to params */ + if(transport == TP_TCP) { + 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); + } else if(transport == TP_UDP) { + lenSend = sendto(udpsock, buf, lenBuf, 0, &udpRcvr, sizeof(udpRcvr)); + } else if(transport == TP_TLS) { + if(offsSendBuf + lenBuf < MAX_SENDBUF) { + memcpy(sendBuf+offsSendBuf, buf, lenBuf); + offsSendBuf += lenBuf; + lenSend = lenBuf; /* simulate "good" call */ + } else { + lenSend = sendTLS(socknum, sendBuf, offsSendBuf); + lenSend = (lenSend == offsSendBuf) ? lenBuf : -1; + memcpy(sendBuf, buf, lenBuf); + offsSendBuf = lenBuf; } } - 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", - sockArray[socknum], i, msgNum); + printf("send() failed at socket %d, index %d, msgNum %lld\n", + sockArray[socknum], i, inst->numSent); fflush(stderr); return(1); } @@ -328,7 +463,7 @@ int sendMessages(void) if(bShowProgress) printf("\r%8.8d", i); } - if(bRandConnDrop) { + if(!runMultithreaded && bRandConnDrop) { /* if we need to randomly drop connections, see if we * are a victim */ @@ -338,14 +473,333 @@ int sendMessages(void) sockArray[socknum] = -1; } } + if(inst->numSent % batchsize == 0) { + usleep(waittime); + } ++msgNum; ++i; } - printf("\r%8.8d %s sent\n", i, statusText); + if(transport == TP_TLS && offsSendBuf != 0) { + /* send remaining buffer */ + lenSend = sendTLS(socknum, sendBuf, offsSendBuf); + } + if(!bSilent) + printf("\r%8.8d %s sent\n", i, statusText); + + return 0; +} + + +/* this is the thread that starts a generator + */ +static void * +thrdStarter(void *arg) +{ + struct instdata *inst = (struct instdata*) arg; + pthread_mutex_lock(&thrdMgmt); + runningThreads++; + pthread_cond_signal(&condStarted); + while(doRun == 0) { + pthread_cond_wait(&condDoRun, &thrdMgmt); + } + pthread_mutex_unlock(&thrdMgmt); + if(sendMessages(inst) != 0) { + printf("error sending messages\n"); + } + return NULL; +} + + +/* This function initializes the actual traffic generators. The function sets up all required + * parameter blocks and starts threads. It returns when all threads are ready to run + * and the main task must just enable them. + */ +static inline void +prepareGenerators() +{ + int i; + long long msgsThrd; + long long starting = 0; + + if(runMultithreaded) { + bSilent = 1; + numThrds = numConnections; + } else { + numThrds = 1; + } + + runningThreads = 0; + doRun = 0; + pthread_mutex_init(&thrdMgmt, NULL); + pthread_cond_init(&condStarted, NULL); + pthread_cond_init(&condDoRun, NULL); + + if(instarray != NULL) { + free(instarray); + } + instarray = calloc(numThrds, sizeof(struct instdata)); + msgsThrd = numMsgsToSend / numThrds; + + for(i = 0 ; i < numThrds ; ++i) { + instarray[i].lower = starting; + instarray[i].numMsgs = msgsThrd; + instarray[i].numSent = 0; + instarray[i].idx = i; + pthread_create(&(instarray[i].thread), NULL, thrdStarter, instarray + i); + /*printf("started thread %x\n", (unsigned) instarray[i].thread);*/ + starting += msgsThrd; + } +} + +/* Let all generators run. Threads must have been started. Here we wait until + * all threads are initialized and then broadcast that they can begin to run. + */ +static inline void +runGenerators() +{ + pthread_mutex_lock(&thrdMgmt); + while(runningThreads != numThrds){ + pthread_cond_wait(&condStarted, &thrdMgmt); + } + doRun = 1; + pthread_cond_broadcast(&condDoRun); + pthread_mutex_unlock(&thrdMgmt); +} + + +/* Wait for all traffic generators to stop. + */ +static inline void +waitGenerators() +{ + int i; + for(i = 0 ; i < numThrds ; ++i) { + pthread_join(instarray[i].thread, NULL); + /*printf("thread %x stopped\n", (unsigned) instarray[i].thread);*/ + } + pthread_mutex_destroy(&thrdMgmt); + pthread_cond_destroy(&condStarted); + pthread_cond_destroy(&condDoRun); +} + +/* functions related to computing statistics on the runtime of a test. This is + * a separate function primarily not to mess up the test driver. + * rgerhards, 2010-12-08 + */ +static inline void +endTiming(struct timeval *tvStart, struct runstats *stats) +{ + long sec, usec; + unsigned long runtime; + struct timeval tvEnd; + + gettimeofday(&tvEnd, NULL); + if(tvStart->tv_usec > tvEnd.tv_usec) { + tvEnd.tv_sec--; + tvEnd.tv_usec += 1000000; + } + + sec = tvEnd.tv_sec - tvStart->tv_sec; + usec = tvEnd.tv_usec - tvStart->tv_usec; + + runtime = sec * 1000 + (usec / 1000); + stats->totalRuntime += runtime; + if(runtime < stats->minRuntime) + stats->minRuntime = runtime; + if(runtime > stats->maxRuntime) + stats->maxRuntime = runtime; + + if(!bSilent || bStatsRecords) { + if(bCSVoutput) { + printf("%ld.%3.3ld\n", runtime / 1000, runtime % 1000); + } else { + printf("runtime: %ld.%3.3ld\n", runtime / 1000, runtime % 1000); + } + } +} + + +/* generate stats summary record at end of run + */ +static inline void +genStats(struct runstats *stats) +{ + long unsigned avg; + avg = stats->totalRuntime / stats->numRuns; + + if(bCSVoutput) { + printf("#numRuns,TotalRuntime,AvgRuntime,MinRuntime,MaxRuntime\n"); + printf("%d,%llu.%3.3d,%lu.%3.3lu,%lu.%3.3lu,%lu.%3.3lu\n", + stats->numRuns, + stats->totalRuntime / 1000, (int) stats->totalRuntime % 1000, + avg / 1000, avg % 1000, + stats->minRuntime / 1000, stats->minRuntime % 1000, + stats->maxRuntime / 1000, stats->maxRuntime % 1000); + } else { + printf("Runs: %d\n", stats->numRuns); + printf("Runtime:\n"); + printf(" total: %llu.%3.3d\n", stats->totalRuntime / 1000, + (int) stats->totalRuntime % 1000); + printf(" avg: %lu.%3.3lu\n", avg / 1000, avg % 1000); + printf(" min: %lu.%3.3lu\n", stats->minRuntime / 1000, stats->minRuntime % 1000); + printf(" max: %lu.%3.3lu\n", stats->maxRuntime / 1000, stats->maxRuntime % 1000); + printf("All times are wallclock time.\n"); + } +} + + +/* Run the actual test. This function handles various meta-parameters, like + * a specified number of iterations, performance measurement and so on... + * rgerhards, 2010-12-08 + */ +static int +runTests(void) +{ + struct timeval tvStart; + struct runstats stats; + int run; + + stats.totalRuntime = 0; + stats.minRuntime = (unsigned long long) 0xffffffffffffffffll; + stats.maxRuntime = 0; + stats.numRuns = numRuns; + run = 1; + while(1) { /* loop broken inside */ + if(!bSilent) + printf("starting run %d\n", run); + prepareGenerators(); + gettimeofday(&tvStart, NULL); + runGenerators(); + waitGenerators(); + endTiming(&tvStart, &stats); + if(run == numRuns) + break; + if(!bSilent) + printf("sleeping %d seconds before next run\n", sleepBetweenRuns); + sleep(sleepBetweenRuns); + ++run; + } + + if(bStatsRecords) { + genStats(&stats); + } return 0; } +# if defined(ENABLE_GNUTLS) +/* This defines a log function to be provided to GnuTLS. It hopefully + * helps us track down hard to find problems. + * rgerhards, 2008-06-20 + */ +static void tlsLogFunction(int level, const char *msg) +{ + printf("GnuTLS (level %d): %s", level, msg); + +} + + +/* global init GnuTLS + */ +static void +initTLS(void) +{ + int r; + + /* order of gcry_control and gnutls_global_init matters! */ + gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); + gnutls_global_init(); + /* set debug mode, if so required by the options */ + if(tlsLogLevel > 0) { + gnutls_global_set_log_function(tlsLogFunction); + gnutls_global_set_log_level(tlsLogLevel); + } + + r = gnutls_certificate_allocate_credentials(&tlscred); + if(r != GNUTLS_E_SUCCESS) { + printf("error allocating credentials\n"); + gnutls_perror(r); + exit(1); + } + r = gnutls_certificate_set_x509_key_file(tlscred, tlsCertFile, tlsKeyFile, GNUTLS_X509_FMT_PEM); + if(r != GNUTLS_E_SUCCESS) { + printf("error setting certificate files -- have you mixed up key and certificate?\n"); + printf("If in doubt, try swapping the files in -z/-Z\n"); + printf("Certifcate is: '%s'\n", tlsCertFile); + printf("Key is: '%s'\n", tlsKeyFile); + gnutls_perror(r); + r = gnutls_certificate_set_x509_key_file(tlscred, tlsKeyFile, tlsCertFile, + GNUTLS_X509_FMT_PEM); + if(r == GNUTLS_E_SUCCESS) { + printf("Tried swapping files, this seems to work " + "(but results may be unpredictable!)\n"); + } else { + exit(1); + } + } +} + + +static void +initTLSSess(int i) +{ + int r; + gnutls_init(sessArray + i, GNUTLS_CLIENT); + + /* Use default priorities */ + gnutls_set_default_priority(sessArray[i]); + + /* put our credentials to the current session */ + r = gnutls_credentials_set(sessArray[i], GNUTLS_CRD_CERTIFICATE, tlscred); + if(r != GNUTLS_E_SUCCESS) { + fprintf (stderr, "Setting credentials failed\n"); + gnutls_perror(r); + exit(1); + } + + /* NOTE: the following statement generates a cast warning, but there seems to + * be no way around it with current GnuTLS. Do NOT try to "fix" the situation! + */ + gnutls_transport_set_ptr(sessArray[i], (gnutls_transport_ptr_t) sockArray[i]); + + /* Perform the TLS handshake */ + r = gnutls_handshake(sessArray[i]); + if(r < 0) { + fprintf (stderr, "TLS Handshake failed\n"); + gnutls_perror(r); + exit(1); + } +} + +static int +sendTLS(int i, char *buf, int lenBuf) +{ + int lenSent; + int r; + + lenSent = 0; + while(lenSent != lenBuf) { + r = gnutls_record_send(sessArray[i], buf + lenSent, lenBuf - lenSent); + if(r < 0) + break; + lenSent += r; + } + + return lenSent; +} + +static void +closeTLSSess(int i) +{ + gnutls_bye(sessArray[i], GNUTLS_SHUT_RDWR); + gnutls_deinit(sessArray[i]); +} +# else /* NO TLS available */ +static void initTLS(void) {} +static void initTLSSess(int __attribute__((unused)) i) {} +static int sendTLS(int i, char *buf, int lenBuf) { return 0; } +static void closeTLSSess(int __attribute__((unused)) i) {} +# endif /* Run the test. * rgerhards, 2009-04-03 @@ -370,18 +824,17 @@ int main(int argc, char *argv[]) setvbuf(stdout, buf, _IONBF, 48); - if(!isatty(1)) - bShowProgress = 0; - - while((opt = getopt(argc, argv, "f:F:t:p:c:C:m:i:I:P:d:Dn:M:rB")) != -1) { + while((opt = getopt(argc, argv, "b:ef:F:t:p:c:C:m:i:I:P:d:Dn:L:M:rsBR:S:T:XW:Yz:Z:")) != -1) { switch (opt) { + case 'b': batchsize = atoll(optarg); + break; case 't': targetIP = optarg; break; case 'p': targetPort = atoi(optarg); break; case 'n': numTargetPorts = atoi(optarg); break; - case 'c': numConnections = atoi(optarg); + case 'c': numConnections = (unsigned) atoi(optarg); break; case 'C': numFileIterations = atoi(optarg); break; @@ -406,6 +859,8 @@ int main(int argc, char *argv[]) break; case 'F': frameDelim = atoi(optarg); break; + case 'L': tlsLogLevel = atoi(optarg); + break; case 'M': MsgToSend = optarg; break; case 'I': dataFile = optarg; @@ -414,20 +869,61 @@ int main(int argc, char *argv[]) */ numMsgsToSend = 1000000; break; + case 's': bSilent = 1; + break; case 'B': bBinaryFile = 1; break; + case 'R': numRuns = atoi(optarg); + break; + case 'S': sleepBetweenRuns = atoi(optarg); + break; + case 'X': bStatsRecords = 1; + break; + case 'e': bCSVoutput = 1; + break; + case 'T': if(!strcmp(optarg, "udp")) { + transport = TP_UDP; + } else if(!strcmp(optarg, "tcp")) { + transport = TP_TCP; + } else if(!strcmp(optarg, "tls")) { +# if defined(ENABLE_GNUTLS) + transport = TP_TLS; +# else + fprintf(stderr, "compiled without TLS support!\n", optarg); + exit(1); +# endif + } else { + fprintf(stderr, "unknown transport '%s'\n", optarg); + exit(1); + } + break; + case 'W': waittime = atoi(optarg); + break; + case 'Y': runMultithreaded = 1; + break; + case 'z': tlsKeyFile = optarg; + break; + case 'Z': tlsCertFile = optarg; + break; default: printf("invalid option '%c' or value missing - terminating...\n", opt); exit (1); break; } } + if(bStatsRecords && waittime) { + fprintf(stderr, "warning: generating performance stats and using a waittime " + "is somewhat contradictory!\n"); + } + + if(!isatty(1) || bSilent) + bShowProgress = 0; + 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) { @@ -446,22 +942,27 @@ int main(int argc, char *argv[]) } } + if(transport == TP_TLS) { + initTLS(); + } + if(openConnections() != 0) { printf("error opening connections\n"); exit(1); } - if(sendMessages() != 0) { - printf("error sending messages\n"); + if(runTests() != 0) { + printf("error running tests\n"); exit(1); } closeConnections(); /* this is important so that we do not finish too early! */ - if(nConnDrops > 0) + if(nConnDrops > 0 && !bSilent) printf("-D option initiated %ld connection closures\n", nConnDrops); - printf("End of tcpflood Run\n"); + if(!bSilent) + printf("End of tcpflood Run\n"); exit(ret); } -- cgit v1.2.3 From f50f24a7750bc3ad66b339ed3fcc0fdc544a1e15 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 14 Jun 2011 12:18:39 +0200 Subject: backporting TLS-based test --- tests/Makefile.am | 6 ++++++ tests/manytcp-too-few-tls.sh | 15 +++++++++++++++ tests/testsuites/manytcp-too-few-tls.conf | 22 ++++++++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100755 tests/manytcp-too-few-tls.sh create mode 100644 tests/testsuites/manytcp-too-few-tls.conf diff --git a/tests/Makefile.am b/tests/Makefile.am index 8e178ab8..3ee69413 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -96,6 +96,12 @@ TESTS += \ imptcp_conndrop.sh endif +if ENABLE_GNUTLS +if HAVE_VALGRIND +TESTS += manytcp-too-few-tls.sh +endif +endif + if ENABLE_OMUXSOCK TESTS += uxsock_simple.sh endif diff --git a/tests/manytcp-too-few-tls.sh b/tests/manytcp-too-few-tls.sh new file mode 100755 index 00000000..899a87dc --- /dev/null +++ b/tests/manytcp-too-few-tls.sh @@ -0,0 +1,15 @@ +# test many concurrent tcp connections +echo \[manytcp-too-few-tls.sh\]: test concurrent tcp connections +source $srcdir/diag.sh init +source $srcdir/diag.sh startup-vg manytcp-too-few-tls.conf +echo wait for DH param generation -- NOT needed in v6! +sleep 15 +# the config file specifies exactly 1100 connections +source $srcdir/diag.sh tcpflood -c1000 -m40000 +# the sleep below is needed to prevent too-early termination of the tcp listener +sleep 1 +source $srcdir/diag.sh shutdown-when-empty # shut down rsyslogd when done processing messages +source $srcdir/diag.sh wait-shutdown-vg # we need to wait until rsyslogd is finished! +source $srcdir/diag.sh check-exit-vg +source $srcdir/diag.sh seq-check 0 39999 +source $srcdir/diag.sh exit diff --git a/tests/testsuites/manytcp-too-few-tls.conf b/tests/testsuites/manytcp-too-few-tls.conf new file mode 100644 index 00000000..5269e73b --- /dev/null +++ b/tests/testsuites/manytcp-too-few-tls.conf @@ -0,0 +1,22 @@ +# Test for tcp "flood" testing +# rgerhards, 2009-04-08 +$IncludeConfig diag-common.conf + +$ModLoad ../plugins/imtcp/.libs/imtcp +$MainMsgQueueTimeoutShutdown 10000 +$MaxOpenFiles 200 +$InputTCPMaxSessions 1100 +# 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 + +$InputTCPServerStreamDriverMode 1 +$InputTCPServerStreamDriverAuthMode anon +$InputTCPServerRun 13514 + +$template outfmt,"%msg:F,58:2%\n" +$template dynfile,"rsyslog.out.log" # trick to use relative path names! +:msg, contains, "msgnum:" ?dynfile;outfmt -- cgit v1.2.3 From fdc25fb14b6acc1484a59f55746bd4041e0103ff Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 14 Jun 2011 12:23:33 +0200 Subject: bugfix: TLS-induced smaller memory still existed, now fixed --- runtime/nsd_gtls.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/runtime/nsd_gtls.c b/runtime/nsd_gtls.c index 152dc8de..ca4b2928 100644 --- a/runtime/nsd_gtls.c +++ b/runtime/nsd_gtls.c @@ -1121,6 +1121,7 @@ gtlsEndSess(nsd_gtls_t *pThis) } } gnutls_deinit(pThis->sess); + pThis->bHaveSess = 0; } RETiRet; } @@ -1174,6 +1175,8 @@ CODESTARTobjDestruct(nsd_gtls) gnutls_x509_crt_deinit(pThis->ourCert); if(pThis->bOurKeyIsInit) gnutls_x509_privkey_deinit(pThis->ourKey); + if(pThis->bHaveSess) + gnutls_deinit(pThis->sess); ENDobjDestruct(nsd_gtls) -- cgit v1.2.3