Project

General

Profile

[Solved] echo.pl (for mod_wstunnel) example

Added by andrey_filippov about 2 months ago

I was trying to implement the minimal example from mod_wstunnel page, but our system running lighttpd does not have Socket Perl module and I do not understand this powerful language. Can you help to "translate" this 7-liner echo.pl to PHP or Python so I can try mod_wstunnel in our camera?

Andrey Filippov
Elphel


Replies (15)

RE: echo.pl (for mod_wstunnel) in PHP or Python - Added by gstrauss about 2 months ago

Most minimal systems have Perl. And if your system has PHP, then your system is not minimal, IMO.

The sample echo script:
  • ignores SIGPIPE
  • accept()s a connection on the listening socket (in this example, lighttpd provides listening socket on script stdin)
  • reads line and write line (line-by-line for simplicity; could have been written fully unbuffered)
    - writing line should be to output (stdout) with line-buffered discipline or non-blocking discipline.
    If block-buffer discipline (often the default for stdout), write line and flush output.

If you try to write this in PHP or Python and show your effort, then I'll help you to finish it if you have trouble.

RE: echo.pl (for mod_wstunnel) in PHP or Python - Added by andrey_filippov about 2 months ago

I was referring to the mod_wstunnel minimal example, not the minimal system. The system does have Perl, just no Socket module. Yes, I understood that lighttpd communicates with the backend script over script's stdin/stdout, I just have problem - how to bind socket or accept connection from STDIN and send to STDOUT in either of these 2 languages (so far I only used sockets in C). Will look harder.

And, BTW, thanks for lighttpd - we are using it for almost as long as lighttpd exists (we first inherited it with Axis camera GNU/Linux distribution), it was powering cameras used in Google Books and first high-resolution GSV.

RE: echo.pl (for mod_wstunnel) in PHP or Python - Added by gstrauss about 2 months ago

Glad that lighttpd works well for you.

Delete the use Socket; line and the Perl script should still work.

BTW, it would take me less time to write echo.pl in C than to look up how to do it in other languages.
...It would probably be a good exercise to do in Python (for you or for me).

RE: echo.pl (for mod_wstunnel) in PHP or Python - Added by andrey_filippov about 2 months ago

Thank you, the script does not complain w/o Socket (nothing bad in lighttpd.error.log, script is running), so the problem is somewhere else (same result that I was able to get with my Python and PHP attempts.

Andrey

root@elphel393:/tmp# lighttpd -v
lighttpd/1.4.53 (ssl) - a light and fast webserver

root@elphel393:/tmp# cat /var/log/lighttpd.error.log 
...
2021-07-22 22:47:03: (../../lighttpd-1.4.53/src/server.c.1464) server started (lighttpd/1.4.53) 

root@elphel393:/tmp# ps -w
  PID USER       VSZ STAT COMMAND
...
 3619 root      4864 S    /usr/sbin/lighttpd -D -f /etc/lighttpd.conf
 3624 root      4040 S    {echo.pl} /usr/bin/perl -Tw /www/pages/echo.pl
...

/etc/lighttpd.conf :
...
server.modules              = (
                                "mod_access",
                                "mod_fastcgi",
                                "mod_cgi",
                                "mod_wstunnel",
                                "mod_accesslog" )
server.document-root        = "/www/pages" 
server.errorlog             = "/www/logs/lighttpd.error.log" 
server.port                = 80
wstunnel.server = ( "" => (
                            (
                                "socket" => "/tmp/wstunnel.socket",
                                "bin-path" => "/www/pages/echo.pl",
                                "max-procs" => 1,
                                "debug" => 5
                            )
                          )
                  )
...

http://192.168.0.41/wstunnel_count.html                  
    <!DOCTYPE html>
    <!-- modified from example in https://github.com/joewalnes/websocketd README.md -->
    <pre id="log"></pre>
    <script>
      // helper function: log message to screen
      var logelt = document.getElementById('log');
      function log(msg) { logelt.textContent += msg + '\n'; }
      // helper function: send websocket msg with count (1 .. 5)
      var ll = 0;
      function send_msg() { if (++ll <= 5) { log('SEND: '+ll); ws.send(ll+'\n'); } }
      // setup websocket with callbacks
      log('STARTING\n');
      var ws = new WebSocket('ws://localhost:80/');
      log('CREATED\n');
      ws.onopen = function()         { log('CONNECT\n'); send_msg(); };
      ws.onclose = function()        { log('DISCONNECT'); };
      ws.onmessage = function(event) { log('RECV: ' + event.data); send_msg(); };
    </script>

Output:    

STARTING

CREATED

DISCONNECT

RE: echo.pl (for mod_wstunnel) in PHP or Python - Added by gstrauss about 2 months ago

Are you sure that mod_wstunnel is handling the request and not somewhere else in your config with mod_fastcgi or mod_cgi?

I should probably carve out an exception for count.html in the lighttpd.conf in the example, and should probably make the URL in count.html more unique, as in "ws://localhost:80/wstunnel/"

RE: echo.pl (for mod_wstunnel) in PHP or Python - Added by gstrauss about 2 months ago

I updated the examples on mod_wstunnel

If you are having trouble with your config, then please try to use the minimalistic example *.conf files (which I have tested) before trying to integrate it into your existing config.

RE: echo.pl (for mod_wstunnel) in PHP or Python - Added by andrey_filippov about 2 months ago

You are probably right. I'l check it. And put wstunnel.server = ( "wstunnel" => (..., correct?

RE: echo.pl (for mod_wstunnel) in PHP or Python - Added by gstrauss about 2 months ago

See the updated example.
If you use wstunnel.server = ( "/wstunnel/" => ( ..., then you have to update count.html to match,
i.e. "var ws = new WebSocket('ws://localhost:80/wstunnel/');"

RE: echo.pl (for mod_wstunnel) in PHP or Python - Added by andrey_filippov about 2 months ago

Yes, i updated both conf and html, but so far no luck. It still may be some my stupid error. I'll try with minimal conf. BTW is it possible to bind to the socket specified in the lighttpd.conf instead of STDIN/STDOUT?

RE: echo.pl (for mod_wstunnel) in PHP or Python - Added by gstrauss about 2 months ago

BTW is it possible to bind to the socket specified in the lighttpd.conf instead of STDIN/STDOUT?

That is what happens in lighttpd. lighttpd bind()s to the socket specified in lighttpd.conf and sets that listening fd to STDIN_FILENO (0) for the process that lighttpd starts with "bin-path". If you do not want lighttpd to bind(), then do not set "bin-path". Then, you take responsibility for starting and stopping and running your backend application, including bind() and listen() to the address to which you tell lighttpd to connect(), using "host" and "port", or "socket". For example, when using PHP-FPM, you let the PHP-FPM service manage the backend application, and you tell lighttpd to where to connect(), and you do not set "bin-path" when using PHP-FPM.

RE: echo.pl (for mod_wstunnel) in PHP or Python - Added by andrey_filippov about 2 months ago

Trying to implement example exactly, I found I do not have mod_proxy compiled, so I'll do that.

Possibility to use wstunnel without bin-path can be ideal for me - I want two sockets for a single server application. One client will be a smartphone with a cardboard stereo adapter like (https://arvr.google.com/cardboard/), the other client - another smartphone held in hands to use as a remote control, and the system itself - our experimental prototype (https://blog.elphel.com/?video=lwir_calibration&time=270).

RE: echo.pl (for mod_wstunnel) in PHP or Python - Added by andrey_filippov about 2 months ago

#lighttpd-proxy.conf
server.document-root = "/tmp"  # not used in this example
#server.bind = "127.0.0.1"  # had to comment out as I used http server on a local computer, not in the camera
server.port = 8080

server.modules += ("mod_proxy")
proxy.server = ( "/" => (( "host" => "127.0.0.1", "port" => "8081" )))
proxy.header = ( "upgrade" => "enable" )

#lighttpd-wstunnel.conf
server.document-root = "/tmp"  # not used in this example
server.bind = "127.0.0.1" 
server.port = 8081
mimetype.assign = (".txt" => "text/plain", ".html" => "text/html" )

server.modules += ("mod_wstunnel")
wstunnel.server = (
  "/ws/" => (
    (
      "socket" => "/tmp/wstunnel.socket",
      "bin-path" => "/www/pages/echo.pl",
      "max-procs" => 1
    )
  )
) 

cat /www/pages/echo.pl
#!/usr/bin/perl -Tw
$SIG{PIPE} = 'IGNORE';
for (my $FH; accept($FH, STDIN); close $FH) {
    select($FH); $|=1; # $FH->autoflush;
    print $FH $_ while (<$FH>);
}

root@elphel393:/www/pages# ps -w | grep "echo\|light" 
 3964 root      4284 S    lighttpd -D -f /etc/lighttpd-wstunnel.conf
 3965 root      4040 S    {echo.pl} /usr/bin/perl -Tw /www/pages/echo.pl
 3967 root      4280 S    lighttpd -D -f /etc/lighttpd-proxy.conf

 drwxrwxrwt 6 root root 120 Jul 21 22:09 ..
-rw------- 1 root root   0 Jul 21 22:09 .python-history
-rw-r--r-- 1 root root  14 Jul 23 01:37 core_temp
-rw-r--r-- 1 root root  73 Jul 23 01:37 core_temp_params
-rw-r--r-- 1 root root 170 Jul 22 18:21 ws.log
-rw-r--r-- 1 root root 111 Jul 22 23:46 ws_php.log
srwxr-xr-x 1 root root   0 Jul 23 01:37 wstunnel.socket-0

#count.html running on a local machine, lighttpd (only 2 instances) - on 192.168.0.41
<!DOCTYPE html>
<!-- modified from example in https://github.com/joewalnes/websocketd README.md -->
<pre id="log"></pre>
<script>
  // helper function: log message to screen
  var logelt = document.getElementById('log');
  function log(msg) { logelt.textContent += msg + '\n'; }
  // helper function: send websocket msg with count (1 .. 5)
  var ll = 0;
  function send_msg() { if (++ll <= 5) { log('SEND: '+ll); ws.send(ll+'\n'); } }
  // setup websocket with callbacks
  var ws = new WebSocket('ws://localhost:8080/ws/');
  ws.onopen = function()         { log('CONNECT\n'); send_msg(); };
  ws.onclose = function()        { log('DISCONNECT'); };
  ws.onmessage = function(event) { log('RECV: ' + event.data); send_msg(); };
</script>

I just collected all relevant data as it did not work. First with 3-rd lighttpd instance for http server (and my original conf w/o wstunnel), then moved web page to a host computer, and then, after commenting out 'server.bind = "127.0.0.1"' in lighttpd-proxy.conf as I used other system, finally got:

CONNECT

SEND: 1
RECV: 1

SEND: 2
RECV: 2

SEND: 3
RECV: 3

SEND: 4
RECV: 4

SEND: 5
RECV: 5

Thanks!

RE: [Solved] echo.pl (for mod_wstunnel) example - Added by andrey_filippov about 2 months ago

Just to admit where my stupid error was (as usually, very far from where I was looking). The counter.html was hosted on the same system, where all the lighttpd instances, backend, but not on my computer. Knowing that the websocket server is on the same system as webserver, I missed wrong for me "localhost" in counter.html .

Replacing

var ws = new WebSocket('ws://localhost:8080/ws/');

with
var ws = new WebSocket('ws://'+location.hostname+':8080/ws/');

fixed all my problems. It may be applicable to others too (and still it does not break the original example).

Andrey

RE: [Solved] echo.pl (for mod_wstunnel) example - Added by gstrauss about 2 months ago

FYI: It would break if the instructions were followed to a tee and the URL loaded in the browser was file:///dev/shm/count.html, but the file: part seems to have gotten lots from my post.

In any case, it might be better to use your var ws = new WebSocket('ws://'+location.hostname+':8080/ws/'); and modify the instruction to host count.html on the same lighttpd server.

Thanks for the suggestion.

RE: [Solved] echo.pl (for mod_wstunnel) example - Added by andrey_filippov about 2 months ago

Just to thank you again for the great program - after fixing my error, everything worked with my original lighttpd.conf and I also tried without "bin-path" as you suggested. Wrote a PHP program listening to 2 different wstunnel sockets and replying to both using socket_select. Everything worked as expected.

    (1-15/15)