vti/protocol-websocket

Server drops connection randomly

cc32d9 opened this issue ยท 14 comments

I wrote this test script that starts a WS server and dumps the JSON messages coming in:
https://github.com/EOSChronicleProject/eos-chronicle/blob/master/testing/chronicle-ws-dumper.pl

The problem is, it starts working properly, and then closes the connection for no apparent reason. Net::WebSocket::Server reports protocol error, so probably some options in frame encoding are not understood by the Protocol::Websocket library.

I will attach a packet capture. The Perl server is running on localhost:8800. Wireshark does not show any errors.

the websocket connection is configured as binary.

The client seems to be sending a lot of continuation frames - there's still no FIN frame even by the time the server is already dead, i.e. the RST frame is sent at the end of the capture. Perhaps you've hit some kind of internal message length limit?

I'm sending messages with Boost library, calling write() or async_write()

https://www.boost.org/doc/libs/1_67_0/libs/beast/doc/html/beast/using_websocket/send_and_receive_messages.html

It's supposed to divide messages into smaller frames internally.

oh, wait. Net::WebSocket::Server::Connection sets the maximum payload size to 64k:

https://metacpan.org/source/Net::WebSocket::Server::Connection

I'll check with a bigger value now.

actually here, line 162:
https://metacpan.org/source/Net::WebSocket::Server::Connection#L162

it creates a new frame with default parameters, and that object has max payload size of 64k. So I;ll need to set the package variable $MAX_PAYLOAD_SIZE for that.

This might be it, since exceeding max_frame_size causes next_bytes to die, which would've caused the code to break out the while loop and return 1002 in the connection close frame, since $@ would be set to the string that the evaled function died with. Incidentally, 1002 is what the server returned according to the capture.

I set $Protocol::WebSocket::Frame::MAX_PAYLOAD_SIZE = 100*1024*1024; , but it still the same behavior. I keep digging.

You could also just modify your local copy of Net::WebSocket::Server::Connection to print $@ inside that if, that would certainly help a lot. It might have also failed due to too many continuation frames.

yes, that's what I did. I get:

Too many fragments at /usr/local/share/perl/5.26.2/Protocol/WebSocket/Frame.pm line 231

you set maximum number of fragments to 128. Is there a way to increase that? Does the protocol allow it?

No, the protocol does not place any restrictions on the number of frames. This is purely an implementation limit that you're free to raise.
In fact, the RFC itself says (under "implementation note") the payload of fragmented frames may be delivered to the client (i.e. a client using a WebSocket API in a program) without waiting for the last fragment. Perhaps this (c|sh)ould be implemented here (or in Net::WebSocket::Server) to encourage such usage.

In my use-case, I need the whole message, and it may be quite large, even multiple megabytes.

Could you maybe define another package variable instead of hard-coding 128 fragments? That would help me a lot.

Sure, I guess that would work. I'll prepare a PR shortly.

Thanks. In the meanwhile I set the hardcoded value to 12800, and it runs beautifully :)