First attempt at fixing the websocket test

master
Jessie Murray 3 years ago
parent 80139110c5
commit c46b85ab7a
No known key found for this signature in database
GPG Key ID: E7E4D57EDDA744C5

@ -1,6 +1,6 @@
OUT=websocket pubsub
CFLAGS=-O3 -Wall -Wextra
LDFLAGS=-levent -lpthread -lrt
LDFLAGS=-levent -lpthread
all: $(OUT) Makefile

@ -1,4 +1,4 @@
/* http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76 */
/* https://datatracker.ietf.org/doc/html/rfc6455 */
#include <stdlib.h>
#define _GNU_SOURCE
@ -19,6 +19,13 @@ struct host_info {
short port;
};
enum worker_state {
WS_INITIAL,
WS_SENT_HANDSHAKE,
WS_RECEIVED_RESPONSE,
WS_COMPLETE
};
/* worker_thread, with counter of remaining messages */
struct worker_thread {
struct host_info *hi;
@ -29,14 +36,24 @@ struct worker_thread {
int msg_sent;
int byte_count;
pthread_t thread;
enum worker_state state;
struct evbuffer *buffer;
struct evbuffer *rbuffer;
int got_header;
struct evbuffer *wbuffer;
int verbose;
int fd;
struct event ev_r;
struct event ev_w;
};
static void
wait_for_possible_read(struct worker_thread *wt);
static void
wait_for_possible_write(struct worker_thread *wt);
void
process_message(struct worker_thread *wt, size_t sz) {
@ -55,15 +72,37 @@ process_message(struct worker_thread *wt, size_t sz) {
}
}
/**
* Called when we can write to the socket.
*/
void
websocket_write(int fd, short event, void *ptr) {
websocket_can_write(int fd, short event, void *ptr) {
int ret;
struct worker_thread *wt = ptr;
printf("%s (wt=%p, fd=%d)\n", __func__, wt, fd);
if(event != EV_WRITE) {
return;
}
switch (wt->state)
{
case WS_INITIAL: /* still sending initial HTTP request */
ret = evbuffer_write(wt->wbuffer, fd);
printf("evbuffer_write returned %d\n", ret);
printf("evbuffer_get_length returned %d\n", evbuffer_get_length(wt->wbuffer));
if (evbuffer_get_length(wt->wbuffer) != 0) { /* not all written */
wait_for_possible_write(wt);
return;
}
/* otherwise, we've sent the full request, time to read the response */
wt->state = WS_SENT_HANDSHAKE;
wait_for_possible_read(wt);
return;
default:
break;
}
#if 0
char message[] = "\x00[\"SET\",\"key\",\"value\"]\xff\x00[\"GET\",\"key\"]\xff";
ret = write(fd, message, sizeof(message)-1);
if(ret != sizeof(message)-1) {
@ -73,25 +112,31 @@ websocket_write(int fd, short event, void *ptr) {
wt->msg_sent += 2;
if(wt->msg_sent < wt->msg_target) {
event_set(&wt->ev_w, fd, EV_WRITE, websocket_write, wt);
event_set(&wt->ev_w, fd, EV_WRITE, websocket_can_write, wt);
event_base_set(wt->base, &wt->ev_w);
ret = event_add(&wt->ev_w, NULL);
}
#endif
}
static void
websocket_read(int fd, short event, void *ptr) {
websocket_can_read(int fd, short event, void *ptr) {
char packet[2048], *pos;
int ret, success = 1;
struct worker_thread *wt = ptr;
printf("%s (wt=%p)\n", __func__, wt);
if(event != EV_READ) {
return;
}
/* read message */
ret = read(fd, packet, sizeof(packet));
ret = evbuffer_read(wt->rbuffer, fd, 65536);
printf("evbuffer_read() returned %d\n", ret);
#if 0
pos = packet;
if(ret > 0) {
char *data, *last;
@ -103,22 +148,22 @@ websocket_read(int fd, short event, void *ptr) {
return; /* not yet */
} else { /* start monitoring possible writes */
printf("start monitoring possible writes\n");
evbuffer_add(wt->buffer, frame_start + 2, ret - (frame_start + 2 - packet));
evbuffer_add(wt->rbuffer, frame_start + 2, ret - (frame_start + 2 - packet));
wt->got_header = 1;
event_set(&wt->ev_w, fd, EV_WRITE,
websocket_write, wt);
websocket_can_write, wt);
event_base_set(wt->base, &wt->ev_w);
ret = event_add(&wt->ev_w, NULL);
}
} else {
/* we've had the header already, now bufffer data. */
evbuffer_add(wt->buffer, packet, ret);
evbuffer_add(wt->rbuffer, packet, ret);
}
while(1) {
data = (char*)EVBUFFER_DATA(wt->buffer);
sz = EVBUFFER_LENGTH(wt->buffer);
data = (char*)EVBUFFER_DATA(wt->rbuffer);
sz = EVBUFFER_LENGTH(wt->rbuffer);
if(sz == 0) { /* no data */
break;
@ -136,7 +181,7 @@ websocket_read(int fd, short event, void *ptr) {
process_message(ptr, msg_sz); /* record packet */
/* drain including frame delimiters (+2 bytes) */
evbuffer_drain(wt->buffer, msg_sz + 2);
evbuffer_drain(wt->rbuffer, msg_sz + 2);
}
} else {
printf("ret=%d\n", ret);
@ -147,6 +192,24 @@ websocket_read(int fd, short event, void *ptr) {
close(fd);
event_base_loopexit(wt->base, NULL);
}
#endif
}
static void
wait_for_possible_read(struct worker_thread *wt) {
printf("%s (wt=%p)\n", __func__, wt);
event_set(&wt->ev_r, wt->fd, EV_READ, websocket_can_read, wt);
event_base_set(wt->base, &wt->ev_r);
event_add(&wt->ev_r, NULL);
}
static void
wait_for_possible_write(struct worker_thread *wt) {
printf("%s (wt=%p)\n", __func__, wt);
event_set(&wt->ev_r, wt->fd, EV_WRITE, websocket_can_write, wt);
event_base_set(wt->base, &wt->ev_r);
event_add(&wt->ev_r, NULL);
}
void*
@ -157,10 +220,9 @@ worker_main(void *ptr) {
"Connection: Upgrade\r\n"
"Upgrade: WebSocket\r\n"
"Origin: http://%s:%d\r\n"
"Sec-WebSocket-Key1: 18x 6]8vM;54 *(5: { U1]8 z [ 8\r\n"
"Sec-WebSocket-Key2: 1_ tx7X d < nw 334J702) 7]o}` 0\r\n"
"Sec-WebSocket-Key: webdis-websocket-test-key\r\n"
"\r\n"
"Tm[K T2u";
;
struct worker_thread *wt = ptr;
@ -184,27 +246,29 @@ worker_main(void *ptr) {
}
/* initialize worker thread */
wt->fd = fd;
wt->base = event_base_new();
wt->buffer = evbuffer_new();
wt->rbuffer = evbuffer_new();
wt->wbuffer = evbuffer_new(); /* write buffer */
wt->byte_count = 0;
wt->got_header = 0;
/* send handshake */
/* build handshake buffer */
/*
ws_handshake_sz = sizeof(ws_handshake)
+ 2*strlen(wt->hi->host) + 500;
ws_handshake = calloc(ws_handshake_sz, 1);
ws_handshake_sz = (size_t)sprintf(ws_handshake, ws_template,
wt->hi->host, wt->hi->port,
wt->hi->host, wt->hi->port);
ret = write(fd, ws_handshake, ws_handshake_sz);
struct event ev_r;
event_set(&ev_r, fd, EV_READ | EV_PERSIST, websocket_read, wt);
event_base_set(wt->base, &ev_r);
event_add(&ev_r, NULL);
*/
int added = evbuffer_add_printf(wt->wbuffer, ws_template, wt->hi->host, wt->hi->port,
wt->hi->host, wt->hi->port);
wait_for_possible_write(wt); /* request callback */
/* go! */
event_base_dispatch(wt->base);
printf("event_base_dispatch returned\n");
event_base_free(wt->base);
free(ws_handshake);
return NULL;
@ -240,14 +304,14 @@ main(int argc, char *argv[]) {
int i, opt;
char *colon;
double total = 0, total_bytes = 0;
int verbose = 0;
int verbose = 0, single = 0;
struct host_info hi = {host_default, port_default};
struct worker_thread *workers;
/* getopt */
while ((opt = getopt(argc, argv, "h:p:c:n:v")) != -1) {
while ((opt = getopt(argc, argv, "h:p:c:n:vs")) != -1) {
switch (opt) {
case 'h':
colon = strchr(optarg, ':');
@ -277,6 +341,11 @@ main(int argc, char *argv[]) {
case 'v':
verbose = 1;
break;
case 's':
single = 1;
thread_count = 1;
break;
default: /* '?' */
usage(argv[0], host_default, port_default,
thread_count_default,
@ -289,10 +358,19 @@ main(int argc, char *argv[]) {
workers = calloc(sizeof(struct worker_thread), thread_count);
clock_gettime(CLOCK_MONOTONIC, &t0);
if (single) {
printf("Single-threaded mode\n");
workers[0].msg_target = msg_target;
workers[0].hi = &hi;
workers[0].verbose = verbose;
workers[0].state = WS_INITIAL;
worker_main(&workers[0]);
} else {
for (i = 0; i < thread_count; ++i) {
workers[i].msg_target = msg_target;
workers[i].hi = &hi;
workers[i].verbose = verbose;
workers[i].state = WS_INITIAL;
pthread_create(&workers[i].thread, NULL,
worker_main, &workers[i]);
@ -304,6 +382,7 @@ main(int argc, char *argv[]) {
total += workers[i].msg_received;
total_bytes += workers[i].byte_count;
}
}
/* timing */
clock_gettime(CLOCK_MONOTONIC, &t1);

Loading…
Cancel
Save