DTA-CAB
view release on metacpan or search on metacpan
CAB/Socket.pm view on Meta::CPAN
my $flags0 = $s->flags;
if (!($flags0 & O_NONBLOCK)) {
fcntl($s->{fh}, F_SETFL, $flags0 | O_NONBLOCK)
or $s->logconfess("canwrite(): could not set O_NOBLOCK on socket: $!");
}
my $wbits = fhbits($s->{fh});
my $nfound = select(undef, $wbits, undef, $timeout);
if (!($flags0 & O_NONBLOCK)) {
fcntl($s->{fh}, F_SETFL, $flags0)
or $s->logconfess("canwrite(): could not reset socket flags: $!");
}
return $nfound;
}
## $s = $s->waitr()
## + waits indefinitely for input; wrapper for $s->canread(undef)
sub waitr {
return $_[0]->canread(undef) ? $_[0] : undef;
}
## $bool = $s->waitw()
## + wrapper for $s->canwrite(undef)
sub waitw {
return $_[0]->canwrite(undef) ? $_[0] : undef;
}
##==============================================================================
## Server Methods
## $class = $CLASS_OR_OBJECT->clientClass()
## + default client class, used by newClient()
sub clientClass {
return ref($_[0]) || $_[0];
}
## $client = $CLASS_OR_OBJECT->newClient(%args)
## + wrapper for clients, called by $s->accept()
## + default just calls $CLASS_OR_OBJECT->clientClass->new(%args)
sub newClient {
my $that = shift;
return $that->clientClass->new(@_);
}
## $cli_or_undef = $s->accept()
## $cli_or_undef = $s->accept($timeout_secs)
## + accept incoming client connections with optional timeout
## + if a client connection is available, it will be returned with $s->newClient(fh=>$fh)
## + otherwise, if no connection is available, undef will be returned
sub accept {
my $s = shift;
my $timeout = @_ ? shift : $s->{timeout};
if (!defined($timeout) || $s->canread($timeout)) {
my $cfh = $s->{fh}->accept();
return undef if (!defined($cfh));
return $s->newClient(fh=>$cfh);
}
return undef;
}
## $rc = $qs->handleClient($cli)
## $rc = $qs->handleClient($cli, %callbacks)
## + handle a single client request
## + each client request is a STRING message (command)
## - request arguments (if required) are sent as separate messages following the command request
## - server response (if any) depends on command sent
## + this method parses client request command $cmd and dispatches to
## - the function $callbacks{lc($cmd)}->($qs,$cli,\$cmd), if defined
## - the method $qs->can("handle_".lc($cmd))->($qs,$cli,\$cmd), if available
## - the function $callbacks{DEFAULT}->($qs,$cli,\$cmd), if defined
## - the method $qs->can("handle_DEFAULT")->($qs,$cli,\$cmd)
## + returns whatever the handler subroutine does
sub handleClient {
my ($qs,$cli,%callbacks) = @_;
my $creq = $cli->get();
$qs->vlog($qs->{logRequest}, "client request: $$creq");
if (!ref($creq) || ref($creq) ne 'SCALAR' || ref($$creq)) {
$qs->logconfess("could not parse client request");
}
my $cmd = lc($$creq);
my ($sub);
if (defined($sub=$callbacks{$cmd})) {
return $sub->($qs,$cli,$creq);
}
elsif (defined($sub=$qs->can("handle_${cmd}"))) {
return $sub->($qs,$cli,$creq);
}
elsif (defined($sub=$callbacks{DEFAULT})) {
return $sub->($qs,$cli,$creq);
}
elsif (defined($sub=$qs->can("handle_DEFAULT"))) {
return $sub->($qs,$cli,$creq);
}
##-- should never get here
$qs->logconfess("could not dispatch client request $$creq");
return undef;
}
##--------------------------------------------------------------
## Server Methods: Request Handling
## undef = $qs->handle_DEFAULT($cli,\$cmd)
## + default implementation just logcluck()s and returns undef
sub handle_DEFAULT {
$_[0]->logcluck("cannot handle client client request ${$_[2]}");
return undef;
}
##==============================================================================
## Protocol
## + all socket messages are of the form pack('NN/a*', $flags, $message_data)
## + $flags is a bitmask of DTA::CAB::Socket flags ($sf_* constants)
## + length element (second 'N' of pack format) is always 0 for serialized references
## + $message_data is one of the following:
## - if ($flags & $sf_ref) -> a reference written with nstore_fd(); will be decoded
## - elsif ($flags & $sf_u8) -> a UTF-8 encoded string; will be decoded
## - elsif ($flags & $sf_undef) -> a literal undef value
## - elsif ($flags & $sf_eoq) -> undef as end-of-queue marker
##--------------------------------------------------------------
## Protocol: Constants
our $sf_eoq = 0x1;
our $sf_undef = 0x2;
our $sf_u8 = 0x4;
our $sf_ref = 0x8;
##--------------------------------------------------------------
## Protocol: Write
## $s = $s->put_header($flags,$len)
## + write a message header to the socket
sub put_header {
$_[0]->vtrace("put_header", @_[1..$#_]);
syswrite($_[0]{fh}, pack('NN', @_[1,2]), 8)==8
or $_[0]->logconfess("put_header(): could not write message header to socket: $!");
return $_[0];
}
## $s = $s->put_data(\$data, $len)
## $s = $s->put_data( $data, $len)
## + write some raw data bytes to the socket (header should already have been sent)
sub put_data {
$_[0]->vtrace("put_data", @_[1..$#_]);
return if (!defined($_[0]));
use bytes;
my $ref = ref($_[1]) ? $_[1] : \$_[1];
my $len = defined($_[2]) ? $_[2] : length($$ref);
if ($len > 0) {
( run in 1.511 second using v1.01-cache-2.11-cpan-437f7b0c052 )