Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Double Click of Death on Perl Web Server

by Anonymous Monk
on Sep 30, 2018 at 03:08 UTC ( [id://1223306]=perlquestion: print w/replies, xml ) Need Help??

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I can't reproduce this problem with code. Please accept my humble question in the hope that someone knows similar problems.

What could cause an IO::Socket::INET (1.39) web server to die by double-clicking links on pages it serves?

I tweaked all server settings and written a few more (forking and non) that don't have the problem. But this one big HTTP/1.0 server runs for days until it gets a double click (but only sometimes) and dies silently. I wrote it from scratch so the code is familiar and all but I can't get it to even raise an error.

Thank you

  • Comment on Double Click of Death on Perl Web Server

Replies are listed 'Best First'.
Re: Double Click of Death on Perl Web Server
by atcroft (Abbot) on Sep 30, 2018 at 05:08 UTC

    Based on what you are describing, my first thought is that perhaps the "double-click" you describe may result in multiple requests in a short (<=30-40 hundredths of a second) interval. This could be examined by performing and examining a packet capture while re-creating the event. If that is the case, then I would consider if a resource conflict is occurring, in which case I might consider if additional "instrumentation" can be added while investigating the problem (either to the code, or possibly even to the modules involved).

    By the way, what configuration options are you providing when creating the listening socket? (Perhaps knowing this might help someone else provide a useful thought for a next step in your troubleshooting.)

    Hope that helps.

      Resource conflict? What resource causes death?
Re: Double Click of Death on Perl Web Server
by haj (Vicar) on Sep 30, 2018 at 08:23 UTC

    Is there any message with the die?

    Short of details, I've just another wild guess: If your browser receives a second click event while the first one isn't processed completely - maybe the client aborts the first request in a way the server doesn't expect? Inspect the error handling in case your server can't send the response (because the client closed the connection) or received an incomplete request (because the "click" caused either a lengthy POST request or some local JavaScript action which was aborted by the browser).

Re: Double Click of Death on Perl Web Server
by Anonymous Monk on Sep 30, 2018 at 08:16 UTC

    A quick idea which might be the solution, but also might be totally wrong:

    By default on Linux, your process can get killed by SIGPIPE if trying to write to a socket that had been closed by the remote peer:

    When writing onto a connection-oriented socket that has been shut down (by the local or the remote end) SIGPIPE is sent to the writing process and EPIPE is returned. The signal is not sent when the write call specified the MSG_NOSIGNAL flag.
    Double-clicking a link may mean that the first connection gets closed and a new connection re-established. Does it get better if you set $SIG{PIPE} = 'IGNORE';?

Re: Double Click of Death on Perl Web Server
by cavac (Parson) on Oct 02, 2018 at 06:59 UTC

    Just a side note, not really related to your problem: You might want to consider switching to IO::Socket::IP. Should be pretty much a plug in replacement, but will enable you to run dual stack (IPv4, IPv6) whenever you need it.

    "For me, programming in Perl is like my cooking. The result may not always taste nice, but it's quick, painless and it get's food on the table."
      You might want to consider switching to IO::Socket::IP. Should be pretty much a plug in replacement, but will enable you to run dual stack (IPv4, IPv6) whenever you need it.

      Thank you for that nugget of wisdom. It's good to know if IP6 is needed. Replacing IO::Socket::INET with IO:Socket::IP only requires a slight change to the settings:

      
      IO::Socket::INET 
      
         Reuse => 1,
      
      Becomes:
      
      IO::Socket::IP
      
         ReuseAddr => 1,
         ReusePort => 1,
      
      
      OTOH IO::Socket::INET buys 14 years of backwards compatability:
      
      corelist IO::Socket::INET
      IO::Socket::INET was first released with perl v5.6.0 (2000-Mar-22)
      
      corelist IO::Socket::IP
      IO::Socket::IP was first released with perl v5.19.8  (2014-Jan-20)
      
      
        OTOH IO::Socket::INET buys 14 years of backwards compatability:

        Don't be so sure. Just because it buys you 14 years of being in core doesn't mean that much. The current version of IO::Socket::IP has full test passes on perls as old as 5.8.1, so you are only buying something like three and a half years of extra backwards compatibility. Contrast that with how much forwards compatibility you would be buying with IO::Socket::IP in terms of transparent IPv6 support.

        OTOH IO::Socket::INET buys 14 years of backwards compatability

        I'm aware of that. But frankly, any system too old to run at least Perl 5.20 with IO::Socket::IP and IPv6 (at least have support for it) is probably a major security disaster waiting to happen. For one thing, it probably still uses SSLv1 or no encryption at all.

        I know there are always legitimate business reasons to run such old systems, but these days they they become overshadowed by the risk involved. Just thinking of Facebook here. Because they didn't patch a data leak when they first noticed the possibility, they might have to pay the EU a penalty of over a billion Euros. And thats just the government side, civil lawsuits may follow. That was a somewhat recent security issue, i somewhat doubt government would be more lenient if you run code that has issues for which patches are out for over a decade...

        "For me, programming in Perl is like my cooking. The result may not always taste nice, but it's quick, painless and it get's food on the table."
        Thanks for pointing out the limitations of IO::Socket::INET vs IO::Socket::IP. I have experience writing secure web applications. These modules are also used in desktop applications to provide the controller for Perl models viewed in a web browser. In such cases network encryption is irrelevant and compatability and portability are the ultimate goals.

        I like to use Perl::MinimumVersion to see how far back my code can be pushed without breaking. :-)

Re: Double Click of Death on Perl Web Server
by Anonymous Monk on Sep 30, 2018 at 13:06 UTC
    Thank you atcroft, haj and anon for the useful clues. Sorry I forgot there is an error message, with diagnostics enabled, that's not ambiguous and agrees with your suggestions:
    
    Can't close(IO::Socket::INET=GLOB(0x7fbc9ab6e300)) filehandle: 'Broken pipe'
    
    
    I tried a few things that didn't help (like $SIG{PIPE} = 'IGNORE') but this eval on close does the trick:
    
    while (my $client = $server->accept) {
      ...
    }
    eval { close $client } # autodie in use
    
    
    The Perl Cookbook says to use "shutdown" (0,1,2) instead of "close" but I get this:
    
    Can't shutdown('IO::Socket::INET=GLOB(0x7fd3857a5e40)', '0'): Socket is not connected
    
    
    What is the correct way to handle this condition (besides eval hack)?

    Thanks again

      # autodie in use

      Why ?
      It seems to me that death on failure is not something you want here.

      Cheers,
      Rob
        > # autodie in use
        > Why ?
        > It seems to me that death on failure is not something you want here.

        THIS WAS THE PROBLEM! I have some autodie homework to do, but just putting "no autodie" in a block with "close $client" stops double-clicks killing the server.

        Thank you Rob!

      If you are actually doing this "while" condition

      while (my $client = $server->accept) {

      and the process gets a signal (say SIGCHLD), the accept will return false, with error EINTR (interrupted system call) and your "while" loop will exit.

      I've seen this bug in several other's programs and it can cause the intermittent failure you are seeing.

      Try something like

      while(1) { if( my $client = $server->accept) { #accept code...
      Glad that you've solved it, but your example has another issue:
      while (my $client = $server->accept) { ... } eval { close $client } # autodie in use

      This eval doesn't do any good. Outside of the while loop the lexical variable $client isn't declared, so you are trying to close an undefined value, then throw away the error. Both use warnings; and use strict; should complain about that. I guess you want to disconnect within the loop?

        Apologies for the typo:
        
        my $server = IO::Socket::INET->new(...);
        
        while (my $client = $server->accept) {
          while (<$client>) {
            ...
          }
          ...
          close $client;               # server dies
          eval { close $client }       # does not die
          shutdown $client, 2;         # dies
          eval { shutdown $client, 2 } # does not die
        }
        close $server;
        
Re: Double Click of Death on Perl Web Server
by Anonymous Monk on Sep 30, 2018 at 04:58 UTC
Re: Double Click of Death on Perl Web Server
by ikegami (Patriarch) on Oct 02, 2018 at 03:05 UTC

    With what error code did it die? What message is in your error log? Provided above

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others chilling in the Monastery: (6)
As of 2024-04-18 16:08 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found