Question

Is there a way to have HTTP::Daemon somehow detect when the client has disconnected (for instance because of a timeout) and thereafter kill itself?

Right now, this is how I wrote my server:

my $response;
try {
    local $SIG{ALRM} = sub { die __TIMEOUT__ };
    alarm 180;
    &process_query;
    alarm 0;
    $response = new HTTP::Response(200);
}
catch {
    if ( $_ eq __TIMEOUT__ ) {
        $response = new HTTP::Response(504);
    }
    else {
        $response = new HTTP::Response(500);
    }
};
$client->send_response($response);

This just assumes that the client will have given up after 180 seconds, which may or may not be true. I would like to go on processing as long as the client keeps waiting for a response, but not longer.

Was it helpful?

Solution

Usually it will not check the file descriptor as long as you are processing data (single threaded), so it will not detect the problem. I see the following options:

  • Check from time to time inside process_query if the $client socket is readable using IO::Select or similar. Readable can be that the client closed the connection or that it send more data, e.g. HTTP pipelining. You can try to check with recv and MSG_PEEK if there are data or eof (e.g. client shutdown), but you will not be able to detect if the are more data followed by eof, because you first have to read the data before you get the eof.
  • If you are on UNIX you can use a rarely used feature: with fcntl($client,F_SETOWN,$$) you can make the kernel send you a SIGIO signal if there is a new event on the $client socket. But the last time I've used this Perl did not handle it correctly and I had to work around it by explicitly calling the fcntl-syscall: syscall(SYS_fcntl,fileno($client),F_SETOWN,$$);. Once you set this up you can handle the IO signal like you do with ALRM right now.

In any case: an eof from the client means only, that the client will no longer write (end of request). It might still be willing to read your data (one-sided shutdown). You only get to know if the client closed for read to once you send data and get a SIGPIPE. There is no way around it, this is how TCP with BSD sockets work.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top