h2o / h2o

H2O - the optimized HTTP/1, HTTP/2, HTTP/3 server

Home Page:https://h2o.examp1e.net

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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.