ARCv2
view release on metacpan or search on metacpan
lib/Arc/Connection.pm view on Meta::CPAN
timeout => undef, # timeout for all connections (ARCv2 and command) in seconds
service => undef, # name of the server (for SASL)
};
}
sub _Init
{
my $this = shift;
return $this->_SetError("Initialization failed.") unless $this->SUPER::_Init(@_);
# timeout
# unless (defined $this->{timeout}) {
# $this->Log(LOG_SIDE,"Setting timeout to 30 secs since no time specified.");
# $this->{timeout} = 30;
# }
return $this->_SetError("No service name for SASL authentication specified.")
unless defined $this->{service};
return 1;
}
## initializes command connection. (protocol)
## Starts listen on the Command socket and sends the B<CMDPASV> command.
##out> true if everything went like expected, otherwise false.
##eg> $this->_CommandConnection();
sub _CommandConnection
{
my $this = shift;
my $consock = IO::Socket::INET->new(
Listen => 1,
Proto => 'tcp',
LocalAddr => $this->{_connection}->sockhost,
ReuseAddr => 1,
) || return $this->_SetError("Socket creation for CommandConnection failed.");
unless ($this->_SendCommand("CMDPASV",$consock->sockhost.':'.$consock->sockport)) {
return;
}
my $sel = new IO::Select($consock);
if (my @socks = $sel->can_read(10)) {
foreach my $sock (@socks) {
if ($sock == $consock) {
$this->{_cmdclientsock} = $consock->accept() || last;
return 1;
}
}
} else {
return $this->_SetError("No CommandConnection received (Client died?).");
}
}
## function for reading and writing on the command connection.
## This function is always used by the C<Arc::Connection::Server> to handle
## command data. When calling the C<ProcessCommand> from C<Arc::Connection::Client>
## this function is also used.
## Data is read from the local socket resp. pipe and is written encrypted
## to the network socket. The other side reads the data from network socket,
## decrypts it and writes it to its local socket. This function behaves differently on
## client and server sides, when the local or network socket is closed.
##in> *locfdin, *locfdout
##out> always true
##eg> $this->ReadWriteBinary(*STDIN,*STDOUT);
sub _ReadWriteBinary
{
my $this = shift;
my $locin = shift;
my $locout = shift;
my $client = ref ($this) eq "Arc::Connection::Client";
my $netsock = $this->{_cmdclientsock};
# $this->_Debug("ReadWriteBinary (C:",$client,") locin: ",$locin->fileno,", locout:",$locout->fileno,", net: ",$netsock->fileno);
my $sel = new IO::Select($netsock,$locin);
my $lwsel = new IO::Select($locout);
my $nwsel = new IO::Select($netsock);
my $buf;
my $stop = 0;
while (my @rs = $sel->can_read) {
foreach my $r (@rs) {
# Something is readable.
my $ret = $r->sysread($buf,4096);
# If no data received, this read socket is closed
# We don't want to listen to it anymore
unless ($ret) {
$sel->remove($r);
# If there is nothing to read anymore
# we will never write to the other socket again.
if ($r->fileno == $locin->fileno) {
$stop = 1 unless $client;
shutdown($netsock,1); # Close write connection
} elsif ($r->fileno == $netsock->fileno) {
# on client-side the netsock is closed only
# if the command on server side has ended.
# so game over
$stop = 1 if $client;
close($locout) unless $stop; # Local pipe is not needed anymore
}
last if $stop;
} else {
# select the appropriate write-"select"
my $tsel = $r->fileno == $locin->fileno ? $nwsel : $lwsel;
# encryption, decode or encode
$buf = $r->fileno == $locin->fileno ?
$this->{_sasl}->encode($buf) :
$this->{_sasl}->decode($buf);
# sometimes SASL replies NULL if something is missing
# this is normal behaviour, the next buf will complete it
next unless $buf;
# if nothing is writeable, gameover
last unless (my @ws = $tsel->can_write);
last unless ($ws[0]->syswrite($buf));
}
}
( run in 0.802 second using v1.01-cache-2.11-cpan-9581c071862 )