libh2o websocket server send asynchronous
zhemant opened this issue · comments
HI,
I am trying to use libh2o for websockets. I managed to get basic working where a client is able to connect to the server. I want to send asynchronous messages to multiple clients when connected. something similar to #572. For some reason, I can only send 2 messages no matter how many messages I add to queue.
When I use only 1 client, the async function I have looks as below. This as it is works but only sends 2 messages. When I uncomment ws_conn->sock->_cb.write = 0;
then it sends all messages from the queue to the client.
int send_ws_message(void * websocket_ptr, char * message, bool on_connect) {
h2o_websocket_conn_t * ws_conn = (h2o_websocket_conn_t *) websocket_ptr;
struct wslay_event_msg msgarg = {WSLAY_TEXT_FRAME, (uint8_t *) message, strlen(message)};
wslay_event_queue_msg(ws_conn->ws_ctx, &msgarg);
h2o_websocket_proceed(ws_conn);
// ws_conn->sock->_cb.write = 0;
return 1;
}
But this only works for 1 client. If I add a second client this does not work.
Does anyone has any example which I can take a look at or if any one can help me to figure out whats am I missing here?
Really appreciate your time and help.
I was able to reproduce with the given example WebSocket. The changes for replicating the issue are as below:
diff --git a/examples/libh2o/websocket.c b/examples/libh2o/websocket.c
index 2c30d7081..a5e90ab24 100644
--- a/examples/libh2o/websocket.c
+++ b/examples/libh2o/websocket.c
@@ -28,6 +28,20 @@
#include "h2o.h"
#include "h2o/websocket.h"
+static void *send_msg(void* ptr) {
+ h2o_websocket_conn_t *conn = (h2o_websocket_conn_t *)ptr;
+ for(int i=0;i<5;i++){
+ sleep(1);
+ char str[256];
+ snprintf(str,256,"hello-%i",i);
+ struct wslay_event_msg msgarg = {1, (uint8_t*)str, strlen(str)};
+ wslay_event_queue_msg(conn->ws_ctx, &msgarg);
+ h2o_websocket_proceed(conn);
+ //conn->sock->_cb.write = 0;
+ }
+ pthread_exit(NULL);
+}
+
static void on_ws_message(h2o_websocket_conn_t *conn, const struct wslay_event_on_msg_recv_arg *arg)
{
if (arg == NULL) {
@@ -39,6 +53,8 @@ static void on_ws_message(h2o_websocket_conn_t *conn, const struct wslay_event_o
struct wslay_event_msg msgarg = {arg->opcode, arg->msg, arg->msg_length};
wslay_event_queue_msg(conn->ws_ctx, &msgarg);
}
+ pthread_t threadid;
+ pthread_create(&threadid,NULL, send_msg, conn );
}
static int on_req(h2o_handler_t *self, h2o_req_t *req)
To install h2o with evloop and websocket
apt install build-essentials cmake libssl-dev zlib1g-dev libuv1-dev
# install wslay from git as given in instructions in this comment https://github.com/h2o/h2o/issues/3043#issuecomment-1200549757
cmake .. -DBUILD_SHARED_LIBS=on -DWITH_MRUBY=off
make
make examples-websocket-evloop
with this the defualt example should run. Once the above changes are made and a websocket client is connected we can see only 2 messages are sent to the client and the remaining messages are not sent. and if we uncomment conn->sock->_cb.write = 0;
then it sends all messages, but on websocket client disconnect it segfaults.
@zhemant IIUC normally all h2o api(except multi thread API) should be called in h2o event loop thread.
you can not create a thread with pthread_create(3) call h2o functions in this thread, this is wrong.
Maybe you can create a timer and call your send function when timed out.