ARCv2
view release on metacpan or search on metacpan
lib/Arc/Connection/Server.pm view on Meta::CPAN
package Arc::Connection::Server;
use strict;
use warnings;
use Carp;
use IO::Select;
use IO::Pipe;
use IO::Socket::INET;
use Arc qw(LOG_AUTH LOG_USER LOG_ERR LOG_CMD LOG_SIDE LOG_DEBUG);
use Arc::Connection;
use MIME::Base64;
@Arc::Connection::Server::ISA = qw(Arc::Connection);
sub members
{
my $this = shift;
return { %{$this->SUPER::members},
_realm => "", # Name of the SASL realm, if the user is from the default realm, this is empty
logfileprefix => "server",
sasl_cb_getsecret => "", # Callback for SASL (if PLAIN (or equal) mechanisms are used). See Authen::SASL(::Cyrus).
sasl_cb_checkpass => 0, # Callback for SASL (if PLAIN (or equal) mechanisms are used). See Authen::SASL(::Cyrus).
sasl_mechanisms => undef, # array of allowed SASL mechanisms
commands => undef, # hash of assignment between B<Command Name> and B<Command Class>. See L<Arc::Command>
};
}
sub _Init
{
my $this = shift;
return unless $this->SUPER::_Init(@_);
# sasl_mechanisms
return $this->_SetError("No SASL mechanisms given.")
unless defined $this->{sasl_mechanisms};
# commands
return $this->_SetError("No ARCv2 commands given. There is no reason the run ARCv2.")
unless defined $this->{commands};
}
## Callback function to canonicalize the username (SASL)
## see Authen::SASL(::Cyrus) for parameter list and how to use.
sub _CBCanonUser
{
my ($this,$type,$realm,$maxlen,$user) = @_;
return $user;
}
## send the available SASL mechanisms.
## Protocol command: AUTH <comma-seperated list of SASL mechansims>\r\n
##out> true when succesful, otherwise false
##eg> $this->_Auth();
sub _Auth
{
my $this = shift;
@{$this->{_expectedcmds}} = qw(QUIT AUTHENTICATE);
return $this->_SendCommand("AUTH",join (",",@{$this->{sasl_mechanisms}}));
}
## send an error msg to client (Server error).
## Protocol command: ERR <msg>\r\n
##out> true when succesful, otherwise false
##eg> $this->_Error("failure.");
sub _Error
{
my $this = shift;
return $this->_SendCommand("ERR",join("",@_));
}
## send a command error msg to client.
## Protocol command: CMDERR <msg>\r\n
##out> true when succesful, otherwise false
##eg> $this->_CmdError("failure.");
sub _CmdError
lib/Arc/Connection/Server.pm view on Meta::CPAN
$this->_CommandConnection();
# check that the connecting host is really the host we are expecting to be.
my ($peerport,$peeraddr) = sockaddr_in($this->{_cmdclientsock}->peername);
$peeraddr = inet_ntoa($peeraddr);
if ($peeraddr eq $this->{_connection}->peerhost) {
$this->Log(LOG_CMD,"Command connection established.");
$in->reader(); $out->writer(); $err->reader();
$out->autoflush(1);
$this->_ReadWriteBinary($in,$out);
$this->{_cmdclientsock}->close();
$this->Log(LOG_CMD,"Command done.");
while (<$err>) {
$this->_CmdError($_);
# $this->_Debug("command errors: $_");
}
close $in; close $out; close $err;
} else {
$this->_SetError("Unknown host wanted ".
"to use our command connection. ($peeraddr)");
}
wait();
} else {
$this->_SetError("Fork error.");
}
$SIG{CHLD} = $oldsigchld;
} else {
my $e = $@;
$this->Log(LOG_CMD,"$perlcmd: ",$e);
$this->_Error("Command $perlcmd not found or error: ".$e);
}
} else {
$this->Log(LOG_USER,"Command '$cmd' requested by user '".$this->{_username}.
"'",$para ? "with parameters '$para'" : "","was not found!");
$this->_Error("Command $cmd not found (Unknown Command).");
}
$this->_Done();
$SIG{__WARN__} = 'DEFAULT';
if ($this->{_error}) {
$this->_Debug("_RCMD ended with an error");
} else {
$this->_Debug("_RCMD ended ok");
}
return !$this->{_error};
}
sub _CheckCmd
{
my $this = shift;
my ($cmd, $perlcmd) = @_;
# Do nothing by default.
# This method is mearly here so a sub-class can override it.
return undef;
}
sub _SplitCmdArgs
{
my $this = shift;
my $para = shift;
return split(/\s+/,$para) if defined $para; # better splitting for array TODO
return ();
}
sub _RunCmd
{
my $this = shift;
my ($cmd, $perlcmd, $argref) = @_;
my $cmderr;
my $ret = eval {
my $object = new $perlcmd (
_commands => $this->{commands},
_username => $this->{_username},
_realm => $this->{_realm},
_mech => $this->{_saslmech},
_peeraddr => $this->{_connection}->peerhost,
_peerport => $this->{_connection}->peerport,
_peername => $this->{_connection}->peername,
_cmd => $cmd,
logfileprefix => "command",
);
$object->Execute(@{ $argref });
$cmderr = $object->IsError();
return 0;
};
$ret = 2 unless defined($ret);
$cmderr .= " ".$@ if $@;
return ($ret, $cmderr);
}
## does nothing, placeholder for QUIT\r\n command, sent by the client.
sub _RQUIT
{
my $this = shift;
return 1;
}
## Public function, gets the clientsocket (from Arc::Server) and handles it.
## Handles a connection (main loop).
##in> $clientsock (IO::Socket)
##out> true on success, otherwise false
##eg> $arc->HandleClient(sock);
sub HandleClient
{
my $this = shift;
return $this->_SetError("Client socket needed.") unless (@_ == 1);
my $client = shift;
( run in 3.280 seconds using v1.01-cache-2.11-cpan-140bd7fdf52 )