#include <limits.h>
#include <sys/socket.h>
#include <sys/un.h>
+#include <pthread.h>
#include "../server/citadel_defs.h"
#include "../server/server.h"
#include "../server/citadel_dirs.h"
#include <libcitadel.h>
+char ctdldir[PATH_MAX]=CTDLDIR;
+
char *words[] = {
"lorem","ipsum","dolor","sit","amet","consectetuer","adipiscing","elit","integer","in","mi","a","mauris",
"ornare","sagittis","suspendisse","potenti","suspendisse","dapibus","dignissim","dolor","nam",
};
int nwords = sizeof(words) / sizeof(char *);
-int serv_sock = (-1);
int uds_connectsock(char *sockpath) {
int s;
// input binary data from socket
-void serv_read(char *buf, int bytes) {
+void serv_read(int serv_sock, char *buf, int bytes) {
int len, rlen;
len = 0;
// send binary to server
-void serv_write(char *buf, int nbytes) {
+void serv_write(int serv_sock, char *buf, int nbytes) {
int bytes_written = 0;
int retval;
while (bytes_written < nbytes) {
// input string from socket - implemented in terms of serv_read()
-void serv_gets(char *buf) {
+void serv_gets(int serv_sock, char *buf) {
int i;
// Read one character at a time.
for (i = 0;; i++) {
- serv_read(&buf[i], 1);
+ serv_read(serv_sock, &buf[i], 1);
if (buf[i] == '\n' || i == (SIZ-1))
break;
}
// If we got a long line, discard characters until the newline.
if (i == (SIZ-1)) {
while (buf[i] != '\n') {
- serv_read(&buf[i], 1);
+ serv_read(serv_sock, &buf[i], 1);
}
}
// send line to server - implemented in terms of serv_write()
-void serv_puts(char *buf) {
- serv_write(buf, strlen(buf));
- serv_write("\n", 1);
+void serv_puts(int serv_sock, char *buf) {
+ serv_write(serv_sock, buf, strlen(buf));
+ serv_write(serv_sock, "\n", 1);
}
char *test_user = "Load Test User";
-void perform_random_thing(void) {
+void perform_random_thing(int serv_sock) {
int op = random() % 3;
char buf[SIZ];
int i;
// Random operation 0 : change rooms
if (op == 0) {
snprintf(buf, sizeof(buf), "GOTO %s", random_rooms[random() % nrooms]);
- serv_puts(buf);
- serv_gets(buf);
+ serv_puts(serv_sock, buf);
+ serv_gets(serv_sock, buf);
}
// Random operation 1 : post a message
if (op == 1) {
- serv_puts("ENT0 1");
- serv_gets(buf);
+ serv_puts(serv_sock, "ENT0 1");
+ serv_gets(serv_sock, buf);
if (buf[0] == '4') {
bigness = random() % 500;
for (i=0; i<bigness; ++i) {
strcat(buf, words[random() % nwords]);
if ( (i != 0) && ((i % 10) == 0) ) {
- serv_puts(buf);
+ serv_puts(serv_sock, buf);
strcpy(buf, "");
}
else {
strcat(buf, " ");
}
}
- serv_puts(buf);
- serv_puts("000");
+ serv_puts(serv_sock, buf);
+ serv_puts(serv_sock, "000");
}
}
selected_msg = 0;
do {
- serv_puts("MSGS ALL");
- serv_gets(buf);
+ serv_puts(serv_sock, "MSGS ALL");
+ serv_gets(serv_sock, buf);
if (buf[0] == '1') {
- while (serv_gets(buf), strcmp(buf, "000")) {
+ while (serv_gets(serv_sock, buf), strcmp(buf, "000")) {
++total_msgs;
if ((random() % total_msgs) == 0) {
selected_msg = atol(buf);
}
}
snprintf(buf, sizeof buf, "DELE %ld", selected_msg);
- serv_puts(buf);
- serv_gets(buf);
+ serv_puts(serv_sock, buf);
+ serv_gets(serv_sock, buf);
} while ( (buf[0] != '2') && (total_msgs > 0));
}
}
-void do_stuff(void) {
+void do_stuff(int serv_sock) {
int i;
char buf[SIZ];
snprintf(buf, sizeof buf, "CREU %s", test_user);
- printf("< %s\n", buf);
- serv_puts(buf);
- serv_gets(buf);
- printf("> %s\n", buf);
+ serv_puts(serv_sock, buf);
+ serv_gets(serv_sock, buf);
snprintf(buf, sizeof buf, "ASUP %s|640k_enough_ne1|0|||6|", test_user);
- printf("< %s\n", buf);
- serv_puts(buf);
- serv_gets(buf);
- printf("> %s\n", buf);
+ serv_puts(serv_sock, buf);
+ serv_gets(serv_sock, buf);
snprintf(buf, sizeof buf, "USER %s", test_user);
- printf("< %s\n", buf);
- serv_puts(buf);
- serv_gets(buf);
- printf("> %s\n", buf);
+ serv_puts(serv_sock, buf);
+ serv_gets(serv_sock, buf);
snprintf(buf, sizeof buf, "PASS 640k_enough_ne1");
- printf("< %s\n", buf);
- serv_puts(buf);
- serv_gets(buf);
- printf("> %s\n", buf);
+ serv_puts(serv_sock, buf);
+ serv_gets(serv_sock, buf);
for (i=0; i<nrooms; ++i) {
snprintf(buf, sizeof buf, "CRE8 1|%s|", random_rooms[i]);
- printf("< %s\n", buf);
- serv_puts(buf);
- serv_gets(buf);
- printf("> %s\n", buf);
+ serv_puts(serv_sock, buf);
+ serv_gets(serv_sock, buf);
}
snprintf(buf, sizeof(buf), "GOTO %s", random_rooms[0]);
- printf("< %s\n", buf);
- serv_puts(buf);
- serv_gets(buf);
- printf("> %s\n", buf);
+ serv_puts(serv_sock, buf);
+ serv_gets(serv_sock, buf);
+
+ printf("\033[%d;0H\033[33m%ld\033[0m", 7+serv_sock, serv_sock-3);
long ops = 0;
while(1) {
alarm(30);
- perform_random_thing();
- printf(" \033[32mOperations completed: \033[33m%ld\033[0m\r", ++ops);
+ perform_random_thing(serv_sock);
+ printf("\033[%d;5H\033[33m%8ld\033[0m", 7+serv_sock, ++ops);
fflush(stdout);
}
}
+void *loadtest(void *blah) {
+ char buf[SIZ];
+ int serv_sock;
+
+ serv_sock = uds_connectsock(file_citadel_admin_socket);
+ serv_gets(serv_sock, buf);
+
+ do_stuff(serv_sock);
+
+ close(serv_sock);
+}
// Main loop. Do things and have fun.
int main(int argc, char **argv) {
int a;
- char buf[SIZ];
- char ctdldir[PATH_MAX]=CTDLDIR;
+ int nthreads = 3;
+
+ fprintf(stderr, "\033[2J\033[H"
+ "\033[44m\033[33m\033[1m \033[K\033[0m\n"
+ "\033[44m\033[33m\033[1m Load testing utility for Citadel \033[K\033[0m\n"
+ "\033[44m\033[33m\033[1m Copyright (c) 2023 by citadel.org et al. \033[K\033[0m\n"
+ "\033[44m\033[33m\033[1m This program is open source software. Use, duplication, or disclosure \033[K\033[0m\n"
+ "\033[44m\033[33m\033[1m is subject to the terms of the GNU General Public license v3. \033[K\033[0m\n"
+ "\033[44m\033[33m\033[1m \033[K\033[0m\n");
// Parse command line
- while ((a = getopt(argc, argv, "h:")) != EOF) {
+ while ((a = getopt(argc, argv, "h:n:")) != EOF) {
switch (a) {
case 'h':
strncpy(ctdldir, optarg, sizeof ctdldir);
break;
+ case 'n':
+ nthreads = atoi(optarg);
+ break;
default:
- fprintf(stderr, "loadtest: usage: %s [-h server_dir]\n", argv[0]);
+ fprintf(stderr, "loadtest: usage: %s [-h server_dir] [-n number_of_threads]\n", argv[0]);
return(1);
}
}
- fprintf(stderr, "loadtest: started (pid=%d) connecting to Citadel server with data directory %s\n",
- (int) getpid(),
- ctdldir
- );
- fflush(stderr);
-
if (chdir(ctdldir) != 0) {
fprintf(stderr, "loadtest: %s: %s\n", ctdldir, strerror(errno));
exit(errno);
}
- serv_sock = uds_connectsock(file_citadel_admin_socket);
- serv_gets(buf);
- printf("> %s\n", buf);
+ for (a=0; a<(nthreads-1); ++a) {
+ pthread_t thread;
+ pthread_attr_t attr;
+ int ret = 0;
- do_stuff();
+ ret = pthread_attr_init(&attr);
+ ret = pthread_attr_setstacksize(&attr, THREADSTACKSIZE);
+ ret = pthread_create(&thread, &attr, loadtest, NULL);
+ if (ret != 0) {
+ exit(ret);
+ }
- close(serv_sock);
+ }
+ loadtest(NULL);
return(0);
}