#!/usr/bin/perl 
# 
# Does basic round-robin like loadbalancing between some webservers 
# Questions? < poelwijk[at]mac.com >
#   
 
# Specify the list of webservers to balance between
@SERVERS = qw/webserver1.domain.ext webserver2.domain.ext webserver3.domain.ext/;
 
use IO::Socket;
$SIG{CHLD} = sub { wait() };
$ENV{'PATH'}='/bin:/usr/bin';
chomp($hostname = `/bin/hostname`);
 
# Listen on port 80
$sock = IO::Socket::INET->new(Listen  => 5,
                             LocalPort => 80,
                             LocalAddr => $hostname,
                             Reuse     => 1,
                             Proto    => 'tcp');
 
# First become "nobody"
$nobody  = (getpwnam('nobody'))[2]  || die "nobody does not exist!";
$nogroup = (getgrnam('nogroup'))[2] || die "can't grok nogroup";
($< ,$() = ($>,$)) = ($nobody,$nogroup); # lose root privileges
($\,$/) = ("\r\n","\r\n\r\n");          # CR/LF on output/input
 
# Go into server mode
close STDIN; close STDOUT; close STDERR;
 
# Prefork
fork() && fork() && fork() && fork() && exit 0;
 
# Accept connections on the specified port
while (my $s = $sock->accept()) {
    do { $s->close; next; } if fork();
    my $incomingrequest = < $s>;
    redirect($1,$s) if $incomingrequest=~/(?:GET|POST|HEAD|PUT)\s+(\S+)/;
    $s->flush;
    undef $s;
    exit 0;
}
 
sub redirect {
    my ($url,$s) = @_;
    my $redirecthost = $SERVERS[rand(@SERVERS)];
    print $s "HTTP/1.0 301 Moved Temporarily";
    print $s "Server: Your loadbalancing service/1.0";
    print $s "Location: http://${redirecthost}${url}";
    print $s "";
}
