websocket test: make WS mask configurable

master
Jessie Murray 3 years ago
parent fd8f0b16e0
commit 657197f737
No known key found for this signature in database
GPG Key ID: E7E4D57EDDA744C5

@ -18,7 +18,7 @@
#include <event.h> #include <event.h>
#include <http_parser.h> #include <http_parser.h>
struct host_info{ struct host_info {
char *host; char *host;
short port; short port;
}; };
@ -31,6 +31,12 @@ enum worker_state {
WS_COMPLETE WS_COMPLETE
}; };
enum mask_config {
MASK_NEVER,
MASK_ALWAYS,
MASK_ALTERNATE
};
/* worker_thread, with counter of remaining messages */ /* worker_thread, with counter of remaining messages */
struct worker_thread { struct worker_thread {
struct host_info *hi; struct host_info *hi;
@ -45,6 +51,10 @@ struct worker_thread {
enum worker_state state; enum worker_state state;
int timeout_seconds; int timeout_seconds;
/* masking */
enum mask_config mask_cfg;
int mask_applied;
struct evbuffer *rbuffer; struct evbuffer *rbuffer;
int got_header; int got_header;
@ -141,6 +151,7 @@ void
websocket_can_write(int fd, short event, void *ptr) { websocket_can_write(int fd, short event, void *ptr) {
int ret; int ret;
struct worker_thread *wt = ptr; struct worker_thread *wt = ptr;
(void) event;
wt->debug("%s (wt=%p, fd=%d)\n", __func__, wt, fd); wt->debug("%s (wt=%p, fd=%d)\n", __func__, wt, fd);
switch (wt->state) { switch (wt->state) {
@ -182,6 +193,7 @@ websocket_can_read(int fd, short event, void *ptr) {
int ret; int ret;
struct worker_thread *wt = ptr; struct worker_thread *wt = ptr;
(void) event;
wt->debug("%s (wt=%p)\n", __func__, wt); wt->debug("%s (wt=%p)\n", __func__, wt);
/* read message */ /* read message */
@ -279,21 +291,35 @@ ws_on_headers_complete(http_parser *p) {
static void static void
ws_enqueue_frame_for_command(struct worker_thread *wt, char *cmd, size_t sz) { ws_enqueue_frame_for_command(struct worker_thread *wt, char *cmd, size_t sz) {
int include_mask = (wt->mask_cfg == MASK_ALWAYS ||
(wt->mask_cfg == MASK_ALTERNATE && wt->msg_sent % 2 == 0)) ? 1 : 0;
unsigned char mask[4]; unsigned char mask[4];
for (int i = 0; i < 4; i++) { for (int i = 0; include_mask && i < 4; i++) { /* only if mask is needed */
mask[i] = rand() & 0xff; mask[i] = rand() & 0xff;
} }
uint8_t len = (uint8_t)(sz); /* (1 << 7) | length. */ uint8_t len = (uint8_t)(sz); /* (1 << 7) | length. */
len |= (1 << 7); /* set masking bit ON */ if (include_mask) {
len |= (1 << 7); /* set masking bit ON */
}
for (size_t i = 0; i < sz; i++) { /* apply the mask to the payload */
for (size_t i = 0; include_mask && i < sz; i++) {
cmd[i] = (cmd[i] ^ mask[i % 4]) & 0xff; cmd[i] = (cmd[i] ^ mask[i % 4]) & 0xff;
} }
/* 0x81 = 10000001b: FIN bit (only one message in the frame), text frame */ /* 0x81 = 10000001b:
1: FIN bit (meaning there's only one message in the frame),
0: RSV1 bit (reserved),
0: RSV2 bit (reserved),
0: RSV3 bit (reserved),
0001: text frame */
evbuffer_add(wt->wbuffer, "\x81", 1); evbuffer_add(wt->wbuffer, "\x81", 1);
evbuffer_add(wt->wbuffer, &len, 1); evbuffer_add(wt->wbuffer, &len, 1);
evbuffer_add(wt->wbuffer, mask, 4); if (include_mask) { /* only include mask in the frame if needed */
evbuffer_add(wt->wbuffer, mask, 4);
}
evbuffer_add(wt->wbuffer, cmd, sz); evbuffer_add(wt->wbuffer, cmd, sz);
wt->mask_applied += include_mask;
} }
static void static void
@ -407,10 +433,12 @@ void usage(const char *argv0, char *host_default, short port_default,
"\t[--port|-p] PORT\t(default = %d)\n" "\t[--port|-p] PORT\t(default = %d)\n"
"\t[--clients|-c] THREADS\t(default = %d)\n" "\t[--clients|-c] THREADS\t(default = %d)\n"
"\t[--messages|-n] COUNT\t(number of messages per thread, default = %d)\n" "\t[--messages|-n] COUNT\t(number of messages per thread, default = %d)\n"
"\t[--mask|-m] MASK_CFG\t(%d: always, %d: never, %d: alternate, default = always)\n"
"\t[--max-time|-t] SECONDS\t(max time to give to the run, default = unlimited)\n" "\t[--max-time|-t] SECONDS\t(max time to give to the run, default = unlimited)\n"
"\t[--verbose|-v]\t\t(extremely verbose output)\n", "\t[--verbose|-v]\t\t(extremely verbose output)\n",
argv0, host_default, (int)port_default, argv0, host_default, (int)port_default,
thread_count_default, messages_default); thread_count_default, messages_default,
MASK_ALWAYS, MASK_NEVER, MASK_ALTERNATE);
} }
int int
@ -430,6 +458,7 @@ main(int argc, char *argv[]) {
long total = 0, total_bytes = 0; long total = 0, total_bytes = 0;
int verbose = 0; int verbose = 0;
int timeout_seconds = -1; int timeout_seconds = -1;
enum mask_config mask_cfg = MASK_ALWAYS;
struct host_info hi = {host_default, port_default}; struct host_info hi = {host_default, port_default};
@ -442,10 +471,11 @@ main(int argc, char *argv[]) {
{"port", required_argument, NULL, 'p'}, {"port", required_argument, NULL, 'p'},
{"clients", required_argument, NULL, 'c'}, {"clients", required_argument, NULL, 'c'},
{"messages", required_argument, NULL, 'n'}, {"messages", required_argument, NULL, 'n'},
{"mask", required_argument, NULL, 'm'},
{"max-time", required_argument, NULL, 't'}, {"max-time", required_argument, NULL, 't'},
{"verbose", no_argument, NULL, 'v'}, {"verbose", no_argument, NULL, 'v'},
{0, 0, 0, 0}}; {0, 0, 0, 0}};
while ((opt = getopt_long(argc, argv, "h:p:c:n:t:vs", long_options, NULL)) != -1) { while ((opt = getopt_long(argc, argv, "h:p:c:n:m:t:vs", long_options, NULL)) != -1) {
switch (opt) { switch (opt) {
case 'h': case 'h':
colon = strchr(optarg, ':'); colon = strchr(optarg, ':');
@ -472,6 +502,15 @@ main(int argc, char *argv[]) {
msg_target = atoi(optarg); msg_target = atoi(optarg);
break; break;
case 'm':
mask_cfg = atoi(optarg);
if (mask_cfg < MASK_NEVER || mask_cfg > MASK_ALTERNATE) {
fprintf(stderr, "Invalid mask configuration: %d (range is [%d .. %d])\n",
mask_cfg, MASK_NEVER, MASK_ALTERNATE);
exit(EXIT_FAILURE);
}
break;
case 't': case 't':
timeout_seconds = atoi(optarg); timeout_seconds = atoi(optarg);
break; break;
@ -500,6 +539,7 @@ main(int argc, char *argv[]) {
workers[i].state = WS_INITIAL; workers[i].state = WS_INITIAL;
workers[i].debug = verbose ? debug_verbose : debug_noop; workers[i].debug = verbose ? debug_verbose : debug_noop;
workers[i].timeout_seconds = timeout_seconds; workers[i].timeout_seconds = timeout_seconds;
workers[i].mask_cfg = mask_cfg;
pthread_create(&workers[i].thread, NULL, pthread_create(&workers[i].thread, NULL,
worker_main, &workers[i]); worker_main, &workers[i]);
} }
@ -517,9 +557,15 @@ main(int argc, char *argv[]) {
float mili1 = t1.tv_sec * 1000 + t1.tv_nsec / 1000000; float mili1 = t1.tv_sec * 1000 + t1.tv_nsec / 1000000;
if (total != 0) { if (total != 0) {
int total_masked = 0;
for (i = 0; i < thread_count; ++i) {
total_masked += workers[i].mask_applied;
}
double kb_per_sec = ((double)total_bytes / (double)(mili1 - mili0)) / 1.024; double kb_per_sec = ((double)total_bytes / (double)(mili1 - mili0)) / 1.024;
printf("Read %ld messages (%ld bytes) in %0.2f sec: %0.2f msg/sec (%0.2f KB/sec)\n", printf("Sent+received %ld messages (%d sent masked) for a total of %ld bytes in %0.2f sec: %0.2f msg/sec (%0.2f KB/sec)\n",
total, total,
total_masked,
total_bytes, total_bytes,
(mili1 - mili0) / 1000.0, (mili1 - mili0) / 1000.0,
1000 * ((double)total) / (mili1 - mili0), 1000 * ((double)total) / (mili1 - mili0),

Loading…
Cancel
Save