Version 2.. it had issues with zombie / defunct processes on Linux. This is significantly more stable, and I'm currently serving 300,000+ requests a day on something based off of this:
use HTTP::Daemon;
use HTTP::Status;
use CGI;
use POSIX;
my $totalChildren = 15;
my $childLifetime = 10;
my $logFile = "/tmp/daemon.log";
my %children;
my $children = 0;
&daemonize;
my $d = HTTP::Daemon->new( LocalPort => 1981, LocalAddr => '127.0.0.1', Reuse => 1, Timeout => 180 ) || die "Cannot create socket: $!\n";
warn ("master is ", $d->url);
&spawnChildren;
&keepTicking;
exit;
sub spawnChildren {
for (1..$totalChildren) {
&newChild();
}
}
sub keepTicking {
while ( 1 ) {
sleep;
for (my $i = $children; $i < $totalChildren; $i++ ) {
&newChild();
}
};
}
sub newChild {
my $pid;
my $sigset = POSIX::SigSet->new(SIGINT);
sigprocmask(SIG_BLOCK, $sigset) or die "Can't block SIGINT for fork: $!";
die "Cannot fork child: $!\n" unless defined ($pid = fork);
if ($pid) {
$children{$pid} = 1;
$children++;
warn "forked new child, we now have $children children";
return;
}
my $i;
while ($i < $childLifetime) {
$i++;
my $c = $d->accept or last;
$c->autoflush(1);
logMessage ("connect:". $c->peerhost . "\n");
my $r = $c->get_request(1) or last;
my $url = $r->url;
$url =~ s/^\///g;
if ($r->method ne 'GET') {
$c->send_error(RC_FORBIDDEN);
logMessage ($c->peerhost . " made weird request\n");
redo;
}
my $response = HTTP::Response->new(200);
logMessage ($c->peerhost . " " . $d->url . $url . "\n");
$response->content("<html><body>The daemon works! This child has served $i requests.</body></html>");
$response->header("Content-Type" => "text/html");
$c->send_response($response);
logMessage ("disconnect:" . $c->peerhost . " - ct[$i]\n");
$c->close;
}
warn "child terminated after $i requests";
exit;
}
sub REAPER {
my $stiff;
while (($stiff = waitpid(-1, &WNOHANG)) > 0) {
warn ("child $stiff terminated -- status $?");
$children--;
$children{$stiff};
}
$SIG{CHLD} = \&REAPER;
}
sub daemonize {
my $pid = fork;
defined ($pid) or die "Cannot start daemon: $!";
print "Parent daemon running.\n" if $pid;
exit if $pid;
POSIX::setsid();
close (STDOUT);
close (STDIN);
close (STDERR);
$SIG{__WARN__} = sub {
&logMessage ("NOTE! " . join(" ", @_));
};
$SIG{__DIE__} = sub {
&logMessage ("FATAL! " . join(" ", @_));
exit;
};
$SIG{HUP} = $SIG{INT} = $SIG{TERM} = sub {
my $sig = shift;
$SIG{$sig} = 'IGNORE';
kill 'INT' => keys %children;
die "killed by $sig\n";
exit;
};
$SIG{CHLD} = \&REAPER;
}
sub logMessage {
my $message = shift;
(my $sec, my $min, my $hour, my $mday, my $mon, my $year) = gmtime();
$mon++;
$mon = sprintf("%0.2d", $mon);
$mday = sprintf("%0.2d", $mday);
$hour = sprintf("%0.2d", $hour);
$min = sprintf("%0.2d", $min);
$sec = sprintf("%0.2d", $sec);
$year += 1900;
my $time = qq{$year/$mon/$mday $hour:$min:$sec};
open (FH, ">>" . $logFile);
print FH $time . " - " . $message;
close (FH);
}