cowboy icon indicating copy to clipboard operation
cowboy copied to clipboard

Adjust socket options (buffer sizes) from the websocket handler

Open larshesel opened this issue 5 years ago • 8 comments

This is a feature request.

For some of our uses cases it is important to be able to set various socket options from within a websocket handler. For example the desired sizes for some options like buffer, sndbuf, recbuf are not known when the handler is started but first later after this information has been retrieved externally after authentication.

For now the workaround exists to write a wrapper around cowboy_websocket which extracts the socket and adds it to the handler state.

larshesel avatar May 28 '19 09:05 larshesel

To be implemented via the new set_options command.

essen avatar May 28 '19 09:05 essen

I need to hear more about this feature.

This makes sense for HTTP/1.1 Websocket because Websocket takes over the protocol and thus is in direct control of the socket.

This makes no sense for HTTP/2 Websocket because there Websocket is just a normal stream.

My question is how do you determine the right size for those options and can there be a more generic approach that would work both for HTTP/1.1 and HTTP/2 Websocket?

Thanks.

essen avatar Oct 02 '19 11:10 essen

Sure - I'll try.

This is all in the context of VerneMQ and MQTT over websockets.

Often we can set some pre-defined (small) values for the sndbuf and recbuf sizes in order to not use all available memory when having thousands of MQTT devices over websockets - this is fine for most as they only send and receive small bits of data every so often. Then there are some specific MQTT clients which have much more traffic (usually due to a fan-in scenario) and hence benefits from larger values for sndbuf and recbuf. Usually we let this configuration for the specific clients come from an external source which is only queried after the MQTT websocket client has connected to VerneMQ and then VerneMQ will use check the credentials against and external database from which it may also retrieve the sndbuf and recbuf value overrides.

So I guess we don't really decide the values, i.e., we've outsourced the decision to those tuning the system.

Does this make sense?

larshesel avatar Oct 02 '19 12:10 larshesel

Yeah. Thanks! It just doesn't fit with set_options though so I'll have to think of something else.

essen avatar Oct 02 '19 12:10 essen

We worked around this by implementing a stream_handler and cowboy_sub_protocol (which you kindly suggested when we first discussed it on IRC) which inserts the socket into our websocket state - it would of course be nice to just be able to use set_options, but the current approach works perfectly. In other words, feel free to close this if this is a non-feature for you.

larshesel avatar Oct 02 '19 12:10 larshesel

Let's keep it open, it's useful to have but it will have to be implemented a different way. It just doesn't fit set_options which is about setting protocol options. Maybe Cowboy can have a callback when switching the entire connection to a new protocol that could be used to set transport options, in which case you could just send the socket to yourself and receive it in your Websocket handler directly if you need to do operations later.

essen avatar Oct 02 '19 13:10 essen

The proposed solution with a custom stream handler and implementing the cowboy_sub_protocol behaviour breaks a type contract when upgrading to Cowboy 2.7. Apparently Dialyzer doesn't like the recent addition of the _ => _ to the cowboy_req:req() type. See: https://travis-ci.org/vernemq/vernemq/jobs/616746997#L1061

dergraf avatar Nov 25 '19 19:11 dergraf

There's probably a type error in cowboy_websocket that leads to Dialyzer only seeing the HTTP/2 case for websocket_handshake. Could you extract a module reproducing this behavior? For example when you put that module in the Cowboy source and run make dialyze.

essen avatar Nov 25 '19 19:11 essen