Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

Re^2: WebSocket idle

by noxxi (Pilgrim)
on Jan 20, 2018 at 11:02 UTC ( [id://1207572]=note: print w/replies, xml ) Need Help??


in reply to Re: WebSocket idle
in thread WebSocket idle

> I wasn't able to find much about non-blocking sockets with SSL, so hopefully someone can confirm if I did this right.

For dealing with non-blocking sockets please see the relevant section in the documentation. Please note especially that you cannot simply rely on IO::Select as you did to get notified if new data are available, because data might still be buffered internally in the SSL stack. See the section about common usage errors for details.

Replies are listed 'Best First'.
Re^3: WebSocket idle
by chris212 (Scribe) on Jan 21, 2018 at 02:18 UTC

    That sample code is where my code changes came from. I'm relying on the websocket module to notify me when data is available, right? I can't read 1 byte at a time like they did because the websocket messages are read with $ept->get_next_message(); Before I made the change, it would get caught in a loop without reading any new data, I'm guessing because SSL needed to be renegotiated like I read in the doc I did find, preventing the websocket module from seeing more data. My change with the select seems to have resolved it.

    I also added a 100ms sleep if there is no message received since the last iteration based on sequence numbers in the messages, but that may never happen because I don't think it goes more than a second without a message.

      > That sample code is where my code changes came from

      Please look closer at the example code in IO::Socket::SSL you've based your code from. The example code is specifically dealing with the case that there are still buffered data (using pending) before calling can_read again. Your code misses this part. While the code then will work for cases where each websocket frame is in its own SSL frame it will spuriously fail in case multiple websocket frame are contained in one SSL frame.

      > Before I made the change, it would get caught in a loop without reading any new data, I'm guessing because SSL needed to be renegotiated like I read in the doc I did find...

      In your first code you made the socket non-blocking but then did not check for the socket to be readable at all (can_read) and instead run a busy loop where it always tried to read from the socket and most times immediately failed with EAGAIN since no data where available on the socket. Adding the can_read fixed this but introduced the problem that you don't deal properly with multiple websocket frames inside a single SSL frame. The part about renegotiation instead (i.e. dealing with SSL_WANT_WRITE) is probably unused in most cases since usually no renegotiation will happen on the socket.

        I don't understand. Why would multiple websocket frames in one SSL frame cause the code to fail? Why would $ept->get_next_message() not read each websocket frame even if can_read is called while there is more data buffered/pending? Also, before using select, $ept->get_next_message() did not immediately fail most times because there is always more data to read after sleeping for a second. I don't rely on can_read to know when data is available, I rely on $ept->get_next_message().

        Yes, if there is no data buffered/pending, then $ept->get_next_message() will return undef. That is by design. When that happens, it will call somethinghard. Unless we already called it since parsing the last websocket frame, in which case we will sleep for 100ms and there will probably be more data by then.

        Maybe there is something more efficient I can do with the select instead of a sleep? I can't read 1 byte like in that example code because then $ept->get_next_message() will be missing that data when it tries to read the next frame from the socket, right? Only the remaining data from that SSL frame after that byte will still be in the socket buffer? Maybe I should do a $sel->can_read(1) to block for up to a second until there is more data? That might be cleaner, but it shouldn't fail without it.

        It is a little difficult trying to convert that example to my code where I don't actually read the data directly from the socket, but through get_next_message.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1207572]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others avoiding work at the Monastery: (5)
As of 2024-04-16 04:58 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found