use Coro;
use Coro::Semaphore;
use Coro::Event;
use Coro::Socket;
no utf8;
use bytes;
# at least on my machine, this thingy serves files
# quite a bit faster than apache, ;)
# and quite a bit slower than thttpd :(
$SIG{PIPE} = 'IGNORE';
sub slog {
my $level = shift;
my $format = shift;
printf "---: $format\n", @_;
}
my $connections = new Coro::Semaphore $MAX_CONNECTS;
my @newcons;
my @pool;
# one "execution thread"
sub handler {
while () {
my $new = pop @newcons;
if ($new) {
eval {
conn->new(@$new)->handle;
};
slog 1, "$@" if $@ && !ref $@;
$connections->up;
} else {
last if @pool >= $MAX_POOL;
push @pool, $Coro::current;
schedule;
}
}
}
my $http_port = new Coro::Socket
LocalAddr => $SERVER_HOST,
LocalPort => $SERVER_PORT,
ReuseAddr => 1,
Listen => 50,
or die "unable to start server";
push @listen_sockets, $http_port;
# the "main thread"
async {
slog 1, "accepting connections";
while () {
$connections->down;
push @newcons, [$http_port->accept];
#slog 3, "accepted @$connections ".scalar(@pool);
$::NOW = time;
if (@pool) {
(pop @pool)->ready;
} else {
async \&handler;
}
}
};
package conn;
use Socket;
use HTTP::Date;
use Convert::Scalar 'weaken';
use Linux::AIO;
Linux::AIO::min_parallel $::AIO_PARALLEL;
Event->io(fd => Linux::AIO::poll_fileno,
poll => 'r', async => 1,
cb => \&Linux::AIO::poll_cb);
my $scheduler = Event->idle(
max => 0, min => 0, prio => 4, parked => 1,
cb => \&Coro::schedule);
our %conn; # $conn{ip}{fh} => connobj
our %blocked;
our %mimetype;
sub read_mimetypes {
local *M;
if (open M, "
You have been blocked because you opened too many connections. You
may retry at$time.
Until then, each new access will renew the block. You might want to have a look at the FAQ.