HTTP::Daemon and ‘broken pipe’ errors

Posted:

I’m working on a game similar to Funeral Quest (an upgrade to which is due soon). It’s a turned-based web game based on UFOlogy (go with what you know, I say). I’ll have details on the game some. Naturally, the game is written in Perl.

The game includes a single-threaded web server implemented with Gisle Aas’ HTTP::Daemon Class. It’s single-threaded because I want to allow users to run the server on Winders, should they choose to and I couldn’t figure out how to use threads or ithreads (am I supposed to have access to ithreads?) on win32.

For simple tests, getting a file or a small web page, HTTP::Daemon works fine. The problem started when it attempted to serve a web page with 15 images on it. When the server tried to server the third file (an image), I’d get a ‘broken pipe’ error my server would halt. As I worked to isolate the problem, I found that the error was coming from this simple loop in HTTP::Daemon::ClientConn::send_file:

    while ($n = sysread($file, $buf, 8*1024)) {
        last if !$n;
        $cnt += $n;
    print $self $buf;
    }

As I step through this code in the debugger, I found that after the second iteration $self (a kind of IO::Socket::INET object) would choke. Bummer. I tried changing from print to syswrite, but that didn’t change the behavoir at all.

I turned to Google.

Digging around, I found this post from 1997:

Gisle Aas (gisle@aas.no)
26 Nov 1997 11:39:19 +0100 

Previous message: Gisle Aas: "Re: libwww-per-5.16" 
In reply to: Joerg Kammerer: "Broken Pipe" 

------------------------------------------------------------------

Joerg Kammerer  writes:

] Hope for a Tip...

Add:

   $SIG{'PIPE'} = 'IGNORE';

to your script.

Sure enough, that seems to do the trick. An early hack I thought of that sort of worked was:

$SIG{WARN} = sub { exec "/usr/bin/perl $0" };

This restarts the server on a broken PIPE error. Unfortunately, the file that choke the server wouldn’t get sent.

It would be super if Gisle added this little gotcha to his HTTP::Daemon man page. If not, I’m sure others will find this journal page when they Google for a solution, as I did.

Guru advice is welcomed. Any thoughts on why the server connection chokes? It looks like some kind of I/O buffer is getting full. Because I can safely ignore the signal, I’m guessing that the I/O that trigger the signal gets cleared and more traffic is accepted on that socket. Is this some kind of race condition?

Also, should I abandon the fantasy of expecting perl 5.6.1 threading to work reliably on both Linux and Windows?

You guys are the best…

[Original use.perl.org post and comments.]