95
124
static char frameDelim = '\n'; /* default frame delimiter */
96
125
FILE *dataFP = NULL; /* file pointer for data file, if used */
97
126
static long nConnDrops = 0; /* counter: number of time connection was dropped (-D option) */
127
static int numRuns = 1; /* number of times the test shall be run */
128
static int sleepBetweenRuns = 30; /* number of seconds to sleep between runs */
129
static int bStatsRecords = 0; /* generate stats records */
130
static int bCSVoutput = 0; /* generate output in CSV (where applicable) */
131
static long long batchsize = 100000000ll;
132
static int waittime = 0;
133
static int runMultithreaded = 0; /* run tests in multithreaded mode */
134
static int numThrds = 1; /* number of threads to use */
135
static char *tlsCertFile = NULL;
136
static char *tlsKeyFile = NULL;
137
static int tlsLogLevel = 0;
140
static gnutls_session_t *sessArray; /* array of TLS sessions to use */
141
static gnutls_certificate_credentials tlscred;
144
/* variables for managing multi-threaded operations */
145
int runningThreads; /* number of threads currently running */
146
int doRun; /* shall sender thread begin to run? */
147
pthread_mutex_t thrdMgmt; /* mutex for controling startup/shutdown */
148
pthread_cond_t condStarted;
149
pthread_cond_t condDoRun;
151
/* the following struct provides information for a generator instance (thread) */
153
/* lower and upper bounds for the thread in question */
154
unsigned long long lower;
155
unsigned long long numMsgs; /* number of messages to send */
156
unsigned long long numSent; /* number of messages already sent */
157
unsigned idx; /**< index of fd to be used for sending */
158
pthread_t thread; /**< thread processing this instance */
161
/* the following structure is used to gather performance data */
163
unsigned long long totalRuntime;
164
unsigned long minRuntime;
165
unsigned long maxRuntime;
169
static int udpsock; /* socket for sending in UDP mode */
170
static struct sockaddr_in udpRcvr; /* remote receiver in UDP mode */
172
static enum { TP_UDP, TP_TCP, TP_TLS } transport = TP_TCP;
174
/* forward definitions */
175
static void initTLSSess(int);
176
static int sendTLS(int i, char *buf, int lenBuf);
177
static void closeTLSSess(int __attribute__((unused)) i);
179
/* prepare send subsystem for UDP send */
183
if((udpsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
186
memset((char *) &udpRcvr, 0, sizeof(udpRcvr));
187
udpRcvr.sin_family = AF_INET;
188
udpRcvr.sin_port = htons(targetPort);
189
if(inet_aton(targetIP, &udpRcvr.sin_addr)==0) {
190
fprintf(stderr, "inet_aton() failed\n");
100
198
/* open a single tcp connection
277
390
* last. All messages in between are sent over random connections.
278
391
* Note that message numbers start at 0.
280
int sendMessages(void)
393
int sendMessages(struct instdata *inst)
399
char *statusText = "";
287
400
char buf[MAX_EXTRADATA_LEN + 1024];
401
char sendBuf[MAX_SENDBUF];
289
if(dataFile == NULL) {
290
printf("Sending %d messages.\n", numMsgsToSend);
291
statusText = "messages";
293
printf("Sending file '%s' %d times.\n", dataFile, numFileIterations);
405
if(dataFile == NULL) {
406
printf("Sending %llu messages.\n", inst->numMsgs);
407
statusText = "messages";
409
printf("Sending file '%s' %d times.\n", dataFile,
296
414
if(bShowProgress)
297
415
printf("\r%8.8d %s sent", 0, statusText);
298
while(1) { /* broken inside loop! */
299
if(i < numConnections)
301
else if(i >= numMsgsToSend - numConnections)
302
socknum = i - (numMsgsToSend - numConnections);
305
socknum = rnd % numConnections;
307
genMsg(buf, sizeof(buf), &lenBuf); /* generate the message to send according to params */
309
break; /* end of processing! */
310
if(sockArray[socknum] == -1) {
311
/* connection was dropped, need to re-establish */
312
if(openConn(&(sockArray[socknum])) != 0) {
313
printf("error in trying to re-open connection %d\n", socknum);
317
lenSend = send(sockArray[socknum], buf, lenBuf, 0);
416
while(i < inst->numMsgs) {
417
if(runMultithreaded) {
420
if(i < numConnections)
422
else if(i >= inst->numMsgs - numConnections) {
423
socknum = i - (inst->numMsgs - numConnections);
426
socknum = rnd % numConnections;
429
genMsg(buf, sizeof(buf), &lenBuf, inst); /* generate the message to send according to params */
430
if(transport == TP_TCP) {
431
if(sockArray[socknum] == -1) {
432
/* connection was dropped, need to re-establish */
433
if(openConn(&(sockArray[socknum])) != 0) {
434
printf("error in trying to re-open connection %d\n", socknum);
438
lenSend = send(sockArray[socknum], buf, lenBuf, 0);
439
} else if(transport == TP_UDP) {
440
lenSend = sendto(udpsock, buf, lenBuf, 0, &udpRcvr, sizeof(udpRcvr));
441
} else if(transport == TP_TLS) {
442
if(offsSendBuf + lenBuf < MAX_SENDBUF) {
443
memcpy(sendBuf+offsSendBuf, buf, lenBuf);
444
offsSendBuf += lenBuf;
445
lenSend = lenBuf; /* simulate "good" call */
447
lenSend = sendTLS(socknum, sendBuf, offsSendBuf);
448
lenSend = (lenSend == offsSendBuf) ? lenBuf : -1;
449
memcpy(sendBuf, buf, lenBuf);
450
offsSendBuf = lenBuf;
318
453
if(lenSend != lenBuf) {
319
454
printf("\r%5.5d\n", i);
321
456
perror("send test data");
322
printf("send() failed at socket %d, index %d, msgNum %d\n",
323
sockArray[socknum], i, msgNum);
457
printf("send() failed at socket %d, index %d, msgNum %lld\n",
458
sockArray[socknum], i, inst->numSent);
338
473
sockArray[socknum] = -1;
476
if(inst->numSent % batchsize == 0) {
344
printf("\r%8.8d %s sent\n", i, statusText);
482
if(transport == TP_TLS && offsSendBuf != 0) {
483
/* send remaining buffer */
484
lenSend = sendTLS(socknum, sendBuf, offsSendBuf);
487
printf("\r%8.8d %s sent\n", i, statusText);
493
/* this is the thread that starts a generator
496
thrdStarter(void *arg)
498
struct instdata *inst = (struct instdata*) arg;
499
pthread_mutex_lock(&thrdMgmt);
501
pthread_cond_signal(&condStarted);
503
pthread_cond_wait(&condDoRun, &thrdMgmt);
505
pthread_mutex_unlock(&thrdMgmt);
506
if(sendMessages(inst) != 0) {
507
printf("error sending messages\n");
513
/* This function initializes the actual traffic generators. The function sets up all required
514
* parameter blocks and starts threads. It returns when all threads are ready to run
515
* and the main task must just enable them.
522
long long starting = 0;
524
if(runMultithreaded) {
526
numThrds = numConnections;
533
pthread_mutex_init(&thrdMgmt, NULL);
534
pthread_cond_init(&condStarted, NULL);
535
pthread_cond_init(&condDoRun, NULL);
537
if(instarray != NULL) {
540
instarray = calloc(numThrds, sizeof(struct instdata));
541
msgsThrd = numMsgsToSend / numThrds;
543
for(i = 0 ; i < numThrds ; ++i) {
544
instarray[i].lower = starting;
545
instarray[i].numMsgs = msgsThrd;
546
instarray[i].numSent = 0;
547
instarray[i].idx = i;
548
pthread_create(&(instarray[i].thread), NULL, thrdStarter, instarray + i);
549
/*printf("started thread %x\n", (unsigned) instarray[i].thread);*/
550
starting += msgsThrd;
554
/* Let all generators run. Threads must have been started. Here we wait until
555
* all threads are initialized and then broadcast that they can begin to run.
560
pthread_mutex_lock(&thrdMgmt);
561
while(runningThreads != numThrds){
562
pthread_cond_wait(&condStarted, &thrdMgmt);
565
pthread_cond_broadcast(&condDoRun);
566
pthread_mutex_unlock(&thrdMgmt);
570
/* Wait for all traffic generators to stop.
576
for(i = 0 ; i < numThrds ; ++i) {
577
pthread_join(instarray[i].thread, NULL);
578
/*printf("thread %x stopped\n", (unsigned) instarray[i].thread);*/
580
pthread_mutex_destroy(&thrdMgmt);
581
pthread_cond_destroy(&condStarted);
582
pthread_cond_destroy(&condDoRun);
585
/* functions related to computing statistics on the runtime of a test. This is
586
* a separate function primarily not to mess up the test driver.
587
* rgerhards, 2010-12-08
590
endTiming(struct timeval *tvStart, struct runstats *stats)
593
unsigned long runtime;
594
struct timeval tvEnd;
596
gettimeofday(&tvEnd, NULL);
597
if(tvStart->tv_usec > tvEnd.tv_usec) {
599
tvEnd.tv_usec += 1000000;
602
sec = tvEnd.tv_sec - tvStart->tv_sec;
603
usec = tvEnd.tv_usec - tvStart->tv_usec;
605
runtime = sec * 1000 + (usec / 1000);
606
stats->totalRuntime += runtime;
607
if(runtime < stats->minRuntime)
608
stats->minRuntime = runtime;
609
if(runtime > stats->maxRuntime)
610
stats->maxRuntime = runtime;
612
if(!bSilent || bStatsRecords) {
614
printf("%ld.%3.3ld\n", runtime / 1000, runtime % 1000);
616
printf("runtime: %ld.%3.3ld\n", runtime / 1000, runtime % 1000);
622
/* generate stats summary record at end of run
625
genStats(struct runstats *stats)
628
avg = stats->totalRuntime / stats->numRuns;
631
printf("#numRuns,TotalRuntime,AvgRuntime,MinRuntime,MaxRuntime\n");
632
printf("%d,%llu.%3.3d,%lu.%3.3lu,%lu.%3.3lu,%lu.%3.3lu\n",
634
stats->totalRuntime / 1000, (int) stats->totalRuntime % 1000,
635
avg / 1000, avg % 1000,
636
stats->minRuntime / 1000, stats->minRuntime % 1000,
637
stats->maxRuntime / 1000, stats->maxRuntime % 1000);
639
printf("Runs: %d\n", stats->numRuns);
640
printf("Runtime:\n");
641
printf(" total: %llu.%3.3d\n", stats->totalRuntime / 1000,
642
(int) stats->totalRuntime % 1000);
643
printf(" avg: %lu.%3.3lu\n", avg / 1000, avg % 1000);
644
printf(" min: %lu.%3.3lu\n", stats->minRuntime / 1000, stats->minRuntime % 1000);
645
printf(" max: %lu.%3.3lu\n", stats->maxRuntime / 1000, stats->maxRuntime % 1000);
646
printf("All times are wallclock time.\n");
651
/* Run the actual test. This function handles various meta-parameters, like
652
* a specified number of iterations, performance measurement and so on...
653
* rgerhards, 2010-12-08
658
struct timeval tvStart;
659
struct runstats stats;
662
stats.totalRuntime = 0;
663
stats.minRuntime = (unsigned long long) 0xffffffffffffffffll;
664
stats.maxRuntime = 0;
665
stats.numRuns = numRuns;
667
while(1) { /* loop broken inside */
669
printf("starting run %d\n", run);
671
gettimeofday(&tvStart, NULL);
674
endTiming(&tvStart, &stats);
678
printf("sleeping %d seconds before next run\n", sleepBetweenRuns);
679
sleep(sleepBetweenRuns);
690
# if defined(ENABLE_GNUTLS)
691
/* This defines a log function to be provided to GnuTLS. It hopefully
692
* helps us track down hard to find problems.
693
* rgerhards, 2008-06-20
695
static void tlsLogFunction(int level, const char *msg)
697
printf("GnuTLS (level %d): %s", level, msg);
702
/* global init GnuTLS
709
/* order of gcry_control and gnutls_global_init matters! */
710
gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
711
gnutls_global_init();
712
/* set debug mode, if so required by the options */
713
if(tlsLogLevel > 0) {
714
gnutls_global_set_log_function(tlsLogFunction);
715
gnutls_global_set_log_level(tlsLogLevel);
718
r = gnutls_certificate_allocate_credentials(&tlscred);
719
if(r != GNUTLS_E_SUCCESS) {
720
printf("error allocating credentials\n");
724
r = gnutls_certificate_set_x509_key_file(tlscred, tlsCertFile, tlsKeyFile, GNUTLS_X509_FMT_PEM);
725
if(r != GNUTLS_E_SUCCESS) {
726
printf("error setting certificate files -- have you mixed up key and certificate?\n");
727
printf("If in doubt, try swapping the files in -z/-Z\n");
728
printf("Certifcate is: '%s'\n", tlsCertFile);
729
printf("Key is: '%s'\n", tlsKeyFile);
731
r = gnutls_certificate_set_x509_key_file(tlscred, tlsKeyFile, tlsCertFile,
732
GNUTLS_X509_FMT_PEM);
733
if(r == GNUTLS_E_SUCCESS) {
734
printf("Tried swapping files, this seems to work "
735
"(but results may be unpredictable!)\n");
747
gnutls_init(sessArray + i, GNUTLS_CLIENT);
749
/* Use default priorities */
750
gnutls_set_default_priority(sessArray[i]);
752
/* put our credentials to the current session */
753
r = gnutls_credentials_set(sessArray[i], GNUTLS_CRD_CERTIFICATE, tlscred);
754
if(r != GNUTLS_E_SUCCESS) {
755
fprintf (stderr, "Setting credentials failed\n");
760
/* NOTE: the following statement generates a cast warning, but there seems to
761
* be no way around it with current GnuTLS. Do NOT try to "fix" the situation!
763
gnutls_transport_set_ptr(sessArray[i], (gnutls_transport_ptr_t) sockArray[i]);
765
/* Perform the TLS handshake */
766
r = gnutls_handshake(sessArray[i]);
768
fprintf (stderr, "TLS Handshake failed\n");
775
sendTLS(int i, char *buf, int lenBuf)
781
while(lenSent != lenBuf) {
782
r = gnutls_record_send(sessArray[i], buf + lenSent, lenBuf - lenSent);
794
gnutls_bye(sessArray[i], GNUTLS_SHUT_RDWR);
795
gnutls_deinit(sessArray[i]);
797
# else /* NO TLS available */
798
static void initTLS(void) {}
799
static void initTLSSess(int __attribute__((unused)) i) {}
800
static int sendTLS(int __attribute__((unused)) i, char __attribute__((unused)) *buf, int __attribute__((unused)) lenBuf) { return 0; }
801
static void closeTLSSess(int __attribute__((unused)) i) {}
351
805
* rgerhards, 2009-04-03
415
870
numMsgsToSend = 1000000;
872
case 's': bSilent = 1;
417
874
case 'B': bBinaryFile = 1;
876
case 'R': numRuns = atoi(optarg);
878
case 'S': sleepBetweenRuns = atoi(optarg);
880
case 'X': bStatsRecords = 1;
882
case 'e': bCSVoutput = 1;
884
case 'T': if(!strcmp(optarg, "udp")) {
886
} else if(!strcmp(optarg, "tcp")) {
888
} else if(!strcmp(optarg, "tls")) {
889
# if defined(ENABLE_GNUTLS)
892
fprintf(stderr, "compiled without TLS support: "
893
"\"-Ttls\" not supported!\n");
897
fprintf(stderr, "unknown transport '%s'\n", optarg);
901
case 'W': waittime = atoi(optarg);
903
case 'Y': runMultithreaded = 1;
905
case 'z': tlsKeyFile = optarg;
907
case 'Z': tlsCertFile = optarg;
419
909
default: printf("invalid option '%c' or value missing - terminating...\n", opt);
915
if(bStatsRecords && waittime) {
916
fprintf(stderr, "warning: generating performance stats and using a waittime "
917
"is somewhat contradictory!\n");
920
if(!isatty(1) || bSilent)
425
923
if(numConnections > 20) {
426
924
/* if we use many (whatever this means, 20 is randomly picked)
427
925
* connections, we need to make sure we have a high enough
428
926
* limit. -- rgerhards, 2010-03-25
430
struct rlimit maxFiles;
431
928
maxFiles.rlim_cur = numConnections + 20;
432
929
maxFiles.rlim_max = numConnections + 20;
433
930
if(setrlimit(RLIMIT_NOFILE, &maxFiles) < 0) {