vi / websocat

Command-line client for WebSockets, like netcat (or curl) for ws:// with advanced socat-like functions
MIT License
7.17k stars 278 forks source link

Requests #12

Open dev31337 opened 6 years ago

dev31337 commented 6 years ago

Hi,

Thank you for this amazing tool.

I'm unfortunately not familiar with Rust (only C, C++, C#, PHP, JS) so my only option is to make a request to you (instead of coding/submitting it).

There are two features that I'm missing:

  1. I'm trying to get the peer IP when using "exec:binary". Would it be possible when I use --exec-args to support a built-in variable (ie: $IP) which would contain the peer IP ?

  2. Using signal instead of closing stdin when using "exec:binary". Would it be possible when I use "exec:binary" and the websocket is closed to send SIGHUP (for example) to the binary instead of closing its stdin ?

Regards.

vi commented 6 years ago

I'm trying to get the peer IP

In version 1.1.0, it's done using environment variables:

$ websocat --oneshot -eE -b ws-l:127.0.0.1:1234 sh-c:'env'&
[1] 7420
$ websocat -E -b ws://127.0.0.1:1234/qwerty | grep WEBSOCAT
WEBSOCAT_URI=/qwerty
WEBSOCAT_CLIENT=127.0.0.1:36070
[1]+  Done                    websocat --oneshot -eE -b ws-l:127.0.0.1:1234 sh-c:'env'

I've just recently developed this, it's not yet in the pre-built version. If needed I can make a pre-build for you to play with. and it's available in the 1.1 preview prebuilded files.


Using signal instead of closing stdin

Interesting idea. Currently you can make it not close stdin, but without any notifications about client disconnecting.

Examples:

With parallel connections support:

$ websocat -t ws-l:127.0.0.1:1234 reuse:sh-c:'stdbuf -oL nl'&
[1] 11670
$ websocat -E ws://127.0.0.1:1234/
Q
     1  Q
W
     2  W
E
     3  E
$ websocat -E ws://127.0.0.1:1234/
R
     4  R
T
websocat: WebSocketError: I/O failure
     5  T
Y
     6  Y
$ kill %1
[1]+  Terminated              websocat -t ws-l:127.0.0.1:1234 reuse:sh-c:'stdbuf -oL nl'

Without parallel connections support:

$ websocat -t autoreconnect:ws-l:127.0.0.1:1234 sh-c:'stdbuf -oL nl'&
[1] 12245
$ websocat -E ws://127.0.0.1:1234/
A
     1  A
B
     2  B
C
     3  C
 WARN 2018-07-13T12:30:17Z: websocat::reconnect_peer: 
$ websocat -E ws://127.0.0.1:1234/
D
     4  D
E
     5  E
F
     6  F
 WARN 2018-07-13T12:30:24Z: websocat::reconnect_peer: 
$ kill %1
[1]+  Terminated              websocat -t autoreconnect:ws-l:127.0.0.1:1234 sh-c:'stdbuf -oL nl'

There are quirks in both methods, especially with abruptly disconnecting clients or parallel connections. If you are building a reliable service you should test it thorougly.

I also plan to make a "fancy reuser" overlay to make it just deliver explicit connection and disconnection messages as JSON snippets and allow replies to specific connected clients by ID. It's not implemented yet.

dev31337 commented 6 years ago

Oh thanks for the 1.1 it is exactly what I needed.

Regarding the SIGHUP request, I knew that you could disable the stdin closing but as you said there would be no other way to know about the disconnection.

Let me tell you why I prefer SIGHUP, the main reason is that I'm restoring/porting old unix applications that were running on serial ports (with modems) and when the call was hung-up it was producing a SIGHUP.

I was able to use the stdin closing instead but the only issue with that is that the binary only discovers the disconnection when it is asking for input, not when it is doing something else.

This is why if you have some spare time don't hesitate to offer this option if you can because I think other people (using exec:binary) would also benefit from it :)

vi commented 6 years ago

What would SIGHUP mean if multiple clients are connected to a server websocket simultaneously?

vi commented 6 years ago

Do you have Rust toolchain to build commits and test new things in websocat or you rely on prebuilded? If the latter, which platform do you use?

vi commented 6 years ago

Implemented the SIGHUP:

$ cat > huphup.pl << \EOF
> #!/usr/bin/perl
> sub huphup {
>     print STDERR "HUP\n";
> }
> $SIG{'HUP'} = \&huphup;
> 
> my $v = "";
> while(1) {
>     my $r = sysread STDIN, $v, 65536;
>     syswrite STDOUT,$v if $r > 0;
>     #last if $r == 0;
> }
> EOF

$ chmod +x huphup.pl 

$ websocat --exec-sighup-on-zero-msg  --reuser-send-zero-msg-on-disconnect  -t ws-l:127.0.0.1:1234 reuse-raw:exec:./huphup.pl&
[1] 30931

$ websocat -E ws://127.0.0.1:1234
A
A
BB
BB
HUP

$ websocat -E ws://127.0.0.1:1234
123
123
qwerty
qwerty
HUP

$ 

Re-uploaded websocat_amd64-linux-static file with these two new flags.


Note that reuse-raw: means that if multiple clients are connected simultaneously then replies from the program are directed at random-ish client and SIGHUPs are generated for each disconnected client, not for the last one.

--reuser-send-zero-msg-on-disconnect currently does not affect reuse-broadcast:, but may be implemented for it as well (sending the zero message only when going from 1 connected client to 0 connected clients).

dev31337 commented 6 years ago

Sorry no I don't have the rust toolchain installed, I'm using ubuntu x64 and the static binary with nossl.

Thank you for doing it ! :)

I will try to answer your questions, but the idea was very simple, when websocat has its connection closed by one peer simply sends a SIGHUP to the binary that was running for that peer.

"What would SIGHUP mean if multiple clients are connected to a server websocket simultaneously?"

I think I just explained above, when a client disconnects, sends SIGUP to the binary that was running for that client.

Note that reuse-raw: means that if multiple clients are connected simultaneously then replies from the program are directed at random-ish client and SIGHUPs are generated for each disconnected client, not for the last one.

I'm not sure I understand this one, can you be more specific ? :)

There is one last thing I wanted to tell you, in my situation the binary changes during the connection (by using execl() to run others binaries) but the PID stays the same.

So if you send the signal to the PID (and not to the binary name) it will work right out of the box.

vi commented 6 years ago

to the binary that was running for that peer

For that peer? Means no reuser? Why do you need SIGHUP then? What does your application do when both stdin and stdout are closed? Does SIGPIPE happen? Have you tried -E (--exit-on-eof) option?

vi commented 6 years ago

Anyway, implemented --exec-sighup-on-stdin-close. Is it what you need?

https://github.com/vi/websocat/releases/download/v1.1-pre/websocat_amd64-linux-static

MD5 (websocat_amd64-linux-static) = 613653021a056bbd263a54803bb503a4
dev31337 commented 6 years ago

Thanks I will try it ! :)

vi commented 6 years ago

@dev31337,

websocat -e -t --no-fixups --no-line ws-l:0.0.0.0:port exec:/binary Invalid UTF-8 in --text mode.

Either your program ./binary sends malformed UTF-8 to output, or read(2)-ful chunks of data read from your program happen to split an UTF-8 character apart (e.g. first byte in one chunk, second byte in the next chunk).

You opted out from line-to-message conversion ((--no-line or --no-fixups) + lack of line2msg: overlay), so boundaries between messages are being set arbitrarily if data is flowing fast enough. That's OK for binary mode, but not so for text mode.

If you want to send multiline text messages, you can use zero byte as line separator with -0 option.


What about the SIGHUP. Does it work as you want?

vi commented 6 years ago

Note that in current version unfortunately server mode ws-l:0.0.0.0:port recommends usage of -E option, especially if ./binary is not periodically outputting some data on it's own.

There is (currently) no normal socket disconnection detection, so when client disconnects, it's socket may stay open and associated ./binary still running. If your scenario works when you set --exit-on-eof option then better leave it in.

dev31337 commented 6 years ago

Yes, I found the issue this is why I deleted the question, I was sending malformed UTF-8.

I don't understand -E, what does it do exactly ?

Currently I'm not using it but the stdin of my executed binary still gets closed (EOF) when the client disconnects.

vi commented 6 years ago

It drops the task, closes the socket and maybe stops the program (haven't checked) when client sends EOF (a disconnected socket or WebSocket Close message).

If your program closes stdout in response then it should be OK even without -E.

vi commented 6 years ago

Are there any reasons for this issue to stay open?