shell bypass 403
#!/usr/bin/perl -w
# vim: ts=2 sw=2 expandtab
# Tests basic select operations.
use strict;
use lib qw(./mylib ../mylib);
sub POE::Kernel::ASSERT_DEFAULT () { 1 }
BEGIN {
package
POE::Kernel;
use constant TRACE_DEFAULT => exists($INC{'Devel/Cover.pm'});
}
use Test::More tests => 17;
use POE qw(Pipe::OneWay Pipe::TwoWay);
### Test parameters.
my $pair_count = 5;
my $chat_count = 5;
# What to do here? Create ten master sessions that create socket
# pairs. Each master session spawns a slave session and gives it the
# other end of the pair. The master and slave chat a while, then the
# slave exits (odd pairs) or the master exits (even pairs).
# Everything should shut down cleanly.
# We'll use send and recv with small enough packets to avoid worrying
# about combining broken datagrams.
### Master session.
sub master_start {
my ($kernel, $heap ) = @_[KERNEL, HEAP, ARG0];
my ($master_read, $master_write, $slave_read, $slave_write) =
POE::Pipe::TwoWay->new();
ok( defined($master_read), "master: created two-way pipe for testing" );
# Listen on the uplink_read side.
$kernel->select_read($master_read, 'input');
# Give the other side to a newly spawned session.
POE::Session->create(
inline_states => {
_start => \&slave_start,
_stop => \&slave_stop,
input => \&slave_got_input,
resume => \&slave_resume_read,
output => \&slave_put_output,
},
args => [ $slave_read, $slave_write ],
);
# Save some values for later.
$heap->{write} = $master_write;
$heap->{test_count} = 0;
$heap->{queue} = [ ];
# Start the write thing.
$kernel->select_write($master_write, 'output');
}
sub master_stop {
my ($kernel, $heap) = @_[KERNEL, HEAP];
# Determine if we were successful.
ok(
$heap->{test_count} == $chat_count,
"master: expected number of messages"
);
}
sub master_got_input {
my ($kernel, $heap, $handle) = @_[KERNEL, HEAP, ARG0];
my $received = sysread($handle, my $buffer = '', 4);
unless ($received == 4) {
$kernel->select_read($handle);
$kernel->select_write($heap->{write});
return;
}
# The other session requested a quit. Shut down gracefully.
if ($buffer eq 'quit') {
$kernel->select_read($handle);
$kernel->select_write($heap->{write});
return;
}
# The other session sent a ping. Count it, and send a pong.
if ($buffer eq 'ping') {
$heap->{test_count}++;
push @{$heap->{queue}}, 'pong';
$kernel->select_resume_write($heap->{write});
}
}
sub master_put_output {
my ($kernel, $heap, $handle) = @_[KERNEL, HEAP, ARG0];
# If there is a message queued, write it.
if (@{$heap->{queue}}) {
my $message = shift @{$heap->{queue}};
die $! unless (
syswrite($handle, $message, length($message)) == length($message)
);
}
# Otherwise pause the write select.
else {
$kernel->select_pause_write($handle);
}
}
### Slave session.
sub slave_start {
my ($kernel, $heap, $read_handle, $write_handle, $test_index) =
@_[KERNEL, HEAP, ARG0, ARG1, ARG2];
# Select on our read handle.
$kernel->select_read($read_handle, 'input');
# Remember some things.
$heap->{read} = $read_handle;
$heap->{write} = $write_handle;
$heap->{test_index} = $test_index;
$heap->{queue} = [ ];
# Say hello to the master session.
push @{$heap->{queue}}, 'ping';
$kernel->select_write($write_handle, 'output');
}
sub slave_stop {
my ($kernel, $heap) = @_[KERNEL, HEAP];
# Determine if we were successful.
ok(
$heap->{test_count} == $chat_count,
"slave: expected number of messages"
);
}
# Resume reading after a brief delay.
sub slave_resume_read {
$_[KERNEL]->select_resume_read( $_[HEAP]->{read} );
$_[KERNEL]->delay( error_resuming => undef );
$_[HEAP]->{resume_count}++;
}
sub slave_got_input {
my ($kernel, $heap, $handle) = @_[KERNEL, HEAP, ARG0];
my $received = sysread($handle, my $buffer = '', 4);
unless ($received == 4) {
$kernel->select_read($handle);
$kernel->select_write($heap->{write});
return;
}
# The other session sent a pong.
if ($buffer eq 'pong') {
$heap->{test_count}++;
# Send another ping if we're not done.
if ($heap->{test_count} < $chat_count) {
push @{$heap->{queue}}, 'ping';
$kernel->select_resume_write($heap->{write});
# Pause reading. Gets resumed after a delay.
$kernel->select_pause_read( $heap->{read} );
$kernel->delay( resume => 0.5 );
}
# Otherwise we're done. Send a quit, and quit ourselves.
else {
push @{$heap->{queue}}, 'quit';
$kernel->select_read($handle);
$kernel->select_resume_write($heap->{write});
}
}
}
sub slave_put_output {
my ($kernel, $heap, $handle) = @_[KERNEL, HEAP, ARG0];
# If there is a message queued, write it.
if (@{$heap->{queue}}) {
my $message = shift @{$heap->{queue}};
die $! unless (
syswrite($handle, $message, length($message)) == length($message)
);
# Kludge. We requested quit, so go ahead and quit.
$kernel->select_write($handle) if $message eq 'quit';
}
# Otherwise pause the write select.
else {
$kernel->select_pause_write($handle);
}
}
### Main loop.
# Spawn a group of master sessions.
for (my $index = 0; $index < $pair_count; $index++) {
POE::Session->create(
inline_states => {
_start => \&master_start,
_stop => \&master_stop,
_child => sub { },
input => \&master_got_input,
output => \&master_put_output,
},
args => [ $index ],
);
}
# Spawn a quick and dirty session to test a new bug found in
# _internal_select.
POE::Session->create(
inline_states => {
_start => sub {
my $conduit;
$conduit = "inet" if $^O eq "MSWin32";
my ($r, $w) = POE::Pipe::OneWay->new($conduit);
my $kernel = $_[KERNEL];
$kernel->select_read($r, "input");
$kernel->select_write($r, "output");
$kernel->select_write($r);
$kernel->select_write($r, "output");
$kernel->select($r);
},
_stop => sub { },
},
);
# Now run them until they're done.
POE::Kernel->run();
# Try a re-entrant version.
POE::Session->create(
inline_states => {
_start => sub {
$_[HEAP]->{count} = 0;
$_[KERNEL]->yield("increment");
},
increment => sub {
my ($kernel, $heap) = @_[KERNEL, HEAP];
if ($heap->{count} < 10) {
$kernel->yield("increment");
$heap->{count}++;
}
},
_stop => sub {
ok( $_[HEAP]->{count} == 10, "re-entered event loop ran" );
},
}
);
# Verify that the main loop can run yet again.
POE::Kernel->run();
pass("second event loop run exited normally");
1;