libwebsockets icon indicating copy to clipboard operation
libwebsockets copied to clipboard

handshake message was revised?

Open bethebest0622 opened this issue 3 months ago • 12 comments

I upgraded libwebsockets today

This message:

1758003160973 HTTP/1.1 101 Switching Protocols Date: Tue, 16 Sep 2025 06:12:40 GMT Content-Type: application/json Connection: upgrade upgrade: websocket sec-websocket-accept: 5BJq6ihh1sc1WJpKs342nZb09YA= x-mbx-used-weight-1m: 5 x-response-time: 0ms

was received in event loop event LWS_CALLBACK_CLIENT_RECEIVE

which was not in this event for old version. Is there any neccessary reason to revise it?

could you let me know how to make it disappear in LWS_CALLBACK_CLIENT_RECEIVE

I am very latency-sensitive in event LWS_CALLBACK_CLIENT_RECEIVE, to do if every time may add the latency.

Thanks

bethebest0622 avatar Sep 16 '25 06:09 bethebest0622

and one more thing seems changed

the event_loop function's 4th argument and 5th argument, the void* and size_t

could you provide the change log, how can it make it compatible with old version?

bethebest0622 avatar Sep 16 '25 07:09 bethebest0622

I'm afraid in neither case do I understand what you're describing. The stuff about 'Switching Protocols' is a log? What does it mean to 'receive' this in the callback? As callback rx data?

'event_loop function' ... where do I find this?

If you do the work on lws, I'm sure we should take care about your convenience. But naturally if you don't, your convenience doesn't figure in anyone's calculations.

lws-team avatar Sep 16 '25 08:09 lws-team

sorry for the bad description;

There is a callback function in lws. it looks like:

int event_cb(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) {
  switch (reason) {
    case LWS_CALLBACK_CLIENT_RECEIVE: {
        // handle the message from server side
        // Receive message: "1758003160973 HTTP/1.1 101 Switching Protocols Date ...." here, which is never happend in old libwebsockets version
    }
    default:{}
  }
}

In the old version, I never receive the above message in the code case LWS_CALLBACK_CLIENT_RECEIVE.

but after upgrading(git pull),

I got this from the code, which makes my old code didn't work.

also, i found the void * in and size_t len seems changed.

I want to know how can I make the code work on new version(after git pull).

bethebest0622 avatar Sep 16 '25 08:09 bethebest0622

Well, all of the args depend on the reason. And when there is information provided with in / len, only len bytes of it are valid. At &in[len] and past that, anything could appear. Since you don't mention len, I guess you are just looking at garbage past len bytes. If you stop doing that, I am guessing this is a lot less confusing.

lws-team avatar Sep 16 '25 12:09 lws-team

Well, all of the args depend on the reason. And when there is information provided with in / len, only len bytes of it are valid. At &in[len] and past that, anything could appear. Since you don't mention len, I guess you are just looking at garbage past len bytes. If you stop doing that, I am guessing this is a lot less confusing.

I think it was not caused by the garbage bytes.

In my case, I have this function for event loop:

int event_cb(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len)

I received this for void * in, and the len is 4092 in event LWS_CALLBACK_CLIENT_RECEIVE.

{"arg":{"channel":"books","instId":"BCH-USDT-SWAP"},"action":"snapshot","data":[{"asks":[["549.3","287.9","0","15"],["549.4","701.5","0","35"],["549.5","470.7","0","29"],["549.6","824.8","0","32"],["549.7","1372.8","0","31"],["549.8","823.7","0","37"],["549.9","1042.8","0","26"],["550","436.3","0","34"],["550.1","448.2","0","29"],["550.2","345.6","0","26"],["550.3","381","0","19"],["550.4","362.1","0","19"],["550.5","602.1","0","19"],["550.6","148.1","0","18"],["550.7","113.3","0","12"],["550.8","197.4","0","17"],["550.9","162.3","0","14"],["551","153.7","0","17"],["551.1","143","0","19"],["551.2","184.1","0","25"],["551.3","131","0","15"],["551.4","133.8","0","20"],["551.5","140.5","0","15"],["551.6","279.9","0","21"],["551.7","165.7","0","11"],["551.8","202.4","0","17"],["551.9","148","0","11"],["552","323.2","0","34"],["552.1","248.4","0","17"],["552.2","229.9","0","17"],["552.3","226.3","0","16"],["552.4","360.7","0","19"],["552.5","433.6","0","21"],["552.6","184.8","0","19"],["552.7","168.1","0","16"],["552.8","520.5","0","19"],["552.9","969.4","0","16"],["553","540.9","0","18"],["553.1","222","0","17"],["553.2","210.7","0","13"],["553.3","165.6","0","15"],["553.4","205.5","0","19"],["553.5","293.8","0","24"],["553.6","237","0","26"],["553.7","166.3","0","11"],["553.8","229.4","0","18"],["553.9","187.9","0","14"],["554","196.9","0","17"],["554.1","172.7","0","11"],["554.2","178.8","0","12"],["554.3","149.5","0","10"],["554.4","1145.8","0","26"],["554.5","155.8","0","9"],["554.6","160.9","0","17"],["554.7","1460.4","0","12"],["554.8","163.3","0","14"],["554.9","156.2","0","13"],["555","171.3","0","20"],["555.1","219.5","0","15"],["555.2","144.2","0","11"],["555.3","112.1","0","14"],["555.4","417.4","0","13"],["555.5","114.6","0","12"],["555.6","111.4","0","10"],["555.7","168.4","0","13"],["555.8","136.8","0","12"],["555.9","108.3","0","18"],["556","111.9","0","16"],["556.1","100.7","0","9"],["556.2","109.5","0","10"],["556.3","111.7","0","11"],["556.4","103.1","0","11"],["556.5","132.3","0","14"],["556.6","181.5","0","10"],["556.7","98.2","0","11"],["556.8","112.3","0","19"],["556.9","124.9","0","12"],["557","97","0","6"],["557.1","101.7","0","8"],["557.2","144.1","0","9"],["557.3","101.8","0","12"],["557.4","2.3","0","9"],["557.5","1.7","0","3"],["557.6","1310.5","0","8"],["557.7","1304.2","0","5"],["557.8","0.5","0","3"],["557.9","5.1","0","13"],["558","1525.1","0","15"],["558.1","156.8","0","6"],["558.2","2","0","4"],["558.3","2.6","0","6"],["558.4","5.9","0","8"],["558.5","9.6","0","7"],["558.6","8.1","0","8"],["558.7","6","0","6"],["558.8","45.7","0","9"],["558.9","1508.8","0","4"],["559","1.3","0","8"],["559.1","7.1","0","14"],["559.2","136","0","17"],["559.3","5","0","8"],["559.4","9.9","0","6"],["559.5","0.3","0","3"],["559.6","0.2","0","2"],["559.7","6.9","0","10"],["559.8","30","0","9"],["559.9","0.7","0","4"],["560","528.9","0","19"],["560.1","5.4","0","4"],["560.2","4.6","0","4"],["560.3","6.5","0","11"],["560.4","85.3","0","3"],["560.5","45","0","6"],["560.6","5.4","0","5"],["560.7","0.9","0","5"],["560.8","162.4","0","10"],["560.9","5","0","4"],["561","55.7","0","7"],["561.1","0.6","0","4"],["561.2","10","0","7"],["561.3","6.3","0","11"],["561.4","4.6","0","4"],["561.5","50.4","0","4"],["561.6","4.4","0","7"],["561.7","5.8","0","3"],["561.8","4.7","0","7"],["561.9","3.6","0","5"],["562","11.6","0","9"],["562.1","5.6","0","7"],["562.2","12","0","5"],["562.3","11.4","0","11"],["562.4","0.7","0","4"],["562.5","1.5","0","5"],["562.6","26.6","0","4"],["562.7","13.9","0","10"],["562.8","45.8","0","4"],["562.9","0.3","0","3"],["563","32","0","9"],["563.1","10.7","0","9"],["563.2","0.1","0","1"],["563.3","2","0","12"],["563.4","4.8","0","3"],["563.5","10.5","0","7"],["563.6","13.2","0","9"],["563.7","6.8","0","5"],["563.8","6.4","0","8"],["563.9","6.2","0","8"],["564","13.8","0","14"],["564.1","4.9","0","4"],["564.2","0.9","0","6"],["564.3","4.6","0","7"],["564.4","11.5","0","7"],["564.5","0.9","0","5"],["564.6","1.2","0","4"],["564.7","4.8","0","4"],["564.8","9.3","0","7"],["564.9","5.1","0","3"],["565","2ϋ]

It seems the server side message was cut off the tail (the actual len is more than 4092). I confirmed the rx_buffer_size is enough(65535)

I do nothing on my code, the only difference is:

cut off tail used newest code(37686150755262571dc8956876521c1279db53a4)

the old-good version is 028d4dc2fb59dd90a6997eea04bcaed899adb0fe.

Besides, the newest code in main branch add this message in event LWS_CALLBACK_CLIENT_RECEIVE

1758787990651vHTTP/1.1 101 Switching Protocols
Date: Thu, 25 Sep 2025 08:13:10 GMT
Content-Type: application/json
Connection: upgrade
upgrade: websocket
sec-websocket-accept: VjV06WPqc0DxbWSPaeULHiQum0E=
x-mbx-used-weight-1m: 5
x-response-time: 0ms

which seems belong to event LWS_CALLBACK_CLIENT_ESTABLISHED before

could you have a look at this?

Thanks

bethebest0622 avatar Sep 25 '25 08:09 bethebest0622

I think it was not caused by the garbage bytes.

If you look beyond that valid part of heap or stack buffers, you'll see what used to be there. It's not surprising to see old message data composed there, since it was also composed on heap or stack and will sit there until something overwrites it.

The way lws deals with RX is that it calls back with whatever it read at that moment. So there is no relationship between the RX length and the message length, if the data is slow or memory is constrained it can fragment the RX into multiple goes until the message is done. So there is nothing strange about receiving part of the message, then subsequently the next part until it is complete.

lws-team avatar Sep 25 '25 08:09 lws-team

ok, so this is the fragment of the message.

how can i know this is the fragment?

I think in the old version, only the whole message comes, the callback fuction will be called.

The new version add this for latecny consideration?

bethebest0622 avatar Sep 25 '25 08:09 bethebest0622

I think in the old version, only the whole message comes, the callback fuction will be called.

Well, I think people should be free to think what they like. Certainly it's tiring to argue with them.

However telling me, who wrote it, what you think the old version does, is not a good bet... you're wrong, it has always read into its main buffer and passed up whatever it found in front of itself at that moment. To understand where the chunk you happen to have read fits into the message, there are some apis

/**
 * lws_is_final_fragment() - tests if received fragment is last part of ws message
 *
 * \param wsi: lws connection
 */
LWS_VISIBLE LWS_EXTERN int
lws_is_final_fragment(struct lws *wsi);

/**
 * lws_is_first_fragment() - tests if received fragment is first part of ws message
 *
 * \param wsi: lws connection
 */
LWS_VISIBLE LWS_EXTERN int
lws_is_first_fragment(struct lws *wsi);

from lws-ws-state.h that will help you.

lws-team avatar Sep 25 '25 08:09 lws-team

Well, I think people should be free to think what they like. Certainly it's tiring to argue with them.

I agreed, I apologized for the immature guess.

I seems understand the behind logic.

if the message is very large, the message will be splited into several parts.

i should append them until i get the final part

This is very reasonable, as the network handle the package with same logic.

Can I understand the new version problem as below?

**The old version append the fragment behind the libwebsockets library, so I dont need to handle the fragment append,

and the new version, increased the Custom flexibility, so the default behavior is to let user handle this in their own way?**

bethebest0622 avatar Sep 25 '25 09:09 bethebest0622

No, lws has never done fragment reassembly. In the extreme case it's impossible actually, ws supports fragments each of which can be much larger than any machine's RAM, and you can have any number of those fragments composing an "endless message".

But "endless messages" are quite useful, say you are streaming some huge live audio you don't know the size of, you might do GB of it. But you don't want to wait until the end f the audio show to present it all at once to the listener. You want to play what you have as it comes, on perhaps a very modest device. So lws leaves it up to you to decide if you need to reassemble it and present it as a single, contiguous "message". (lws also provides a stateful JSON decoder which is compatible with decoding what you have and continuing when more comes).

However if your network is fast, and lws has a large rx buffer (you can control the size in the context creation info .pt_serv_buf_size, the default actually depends on the platform ), and your messages fit in the rx buffer, then it might be able to read everything at once.

lws-team avatar Sep 25 '25 09:09 lws-team

However if your network is fast, and lws has a large rx buffer (you can control the size in the context creation info .pt_serv_buf_size, the default actually depends on the platform ), and your messages fit in the rx buffer, then it might be able to read everything at once.

Yes, this is the problem, I set the rxbuffer size with 65536, it's absolutely enough for the json text message, I expected all the message was read at once.

Here is my context create function

lws_context * WsBase::create_context() {
  if (ctx_) EE("Create Lws Context Again\n");
  struct lws_context_creation_info info;
  memset(&info, 0, sizeof(info));

  info.port = CONTEXT_PORT_NO_LISTEN;
  info.fd_limit_per_thread = cfg_->exists("fd_num") ? cfg_->lookup("fd_num") : 20;

  // here rx_size is 65535 !!!
  struct lws_protocols protocols[] = {{"ws", &event_cb, 4096, 65535, 1, NULL}, LWS_PROTOCOL_LIST_TERM};
  info.protocols = protocols;
  info.gid = -1; 
  info.uid = -1; 
  info.timeout_secs = 0;
  // lws_set_log_level(LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_DEBUG, NULL);

  info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
  return lws_create_context(&info);
}

I expect this will not be fragment.

Is libwebsockets setting method updated?

bethebest0622 avatar Sep 25 '25 09:09 bethebest0622

I expected all the message was read at once.

It may not all have come at the time we start reading it. It will wake the event loop when the first packet comes.

(you can control the size in the context creation info .pt_serv_buf_size, the default actually depends on the platform)

You need to set this above as well.

lws-team avatar Sep 25 '25 09:09 lws-team