IO-Handle-Record
view release on metacpan or search on metacpan
lib/IO/Handle/Record.pm view on Meta::CPAN
package IO::Handle::Record;
use 5.008008;
use strict;
use warnings;
use Storable;
use Class::Member::GLOB qw/record_opts
read_buffer expected expect_fds received_fds
end_of_input _received_fds
write_buffer fds_to_send written/;
use Errno qw/EAGAIN EINTR/;
use Carp;
my $have_inet6;
BEGIN {
eval {
require Socket6;
$have_inet6=1;
};
};
use Socket;
require XSLoader;
our $VERSION = '0.15';
XSLoader::load('IO::Handle::Record', $VERSION);
use constant {
HEADERLENGTH=>8, # 2 unsigned long
};
# this is called from the XS stuff in recvmsg
sub open_fd {
my ($fd, $flags)=@_;
use Fcntl qw/O_APPEND O_RDONLY O_WRONLY O_RDWR O_ACCMODE/;
use POSIX ();
use IO::Handle ();
if( ($flags & O_ACCMODE) == O_RDONLY ) {
$flags='<';
} elsif( ($flags & O_ACCMODE) == O_WRONLY ) {
if( $flags & O_APPEND ) {
$flags='>>';
} else {
$flags='>';
}
} elsif( ($flags & O_ACCMODE) == O_RDWR ) {
if( $flags & O_APPEND ) {
$flags='+>>';
} else {
$flags='+>';
}
} else {
POSIX::close($fd);
return undef;
}
my $obj=bless IO::Handle->new_from_fd($fd, $flags),
IO::Handle::Record::typeof($fd);
if( ref($obj)=~/Socket/ ) {
${*$obj}{io_socket_domain}=socket_family($fd);
${*$obj}{io_socket_type}=socket_type($fd);
if($obj->sockdomain==AF_INET or
($have_inet6 and $obj->sockdomain==&Socket6::AF_INET6) ) {
if($obj->socktype==SOCK_STREAM) {
${*$obj}{io_socket_proto}=&Socket::IPPROTO_TCP;
} elsif($obj->socktype==SOCK_DGRAM) {
${*$obj}{io_socket_proto}=&Socket::IPPROTO_UDP;
} elsif($obj->socktype==SOCK_RAW) {
${*$obj}{io_socket_proto}=&Socket::IPPROTO_ICMP;
}
}
}
return $obj;
}
sub read_record {
my $I=shift;
my $reader=(issock($I)
? sub { recvmsg( $_[0], $_[1], $_[2], (@_>3?$_[3]:0) ); }
: sub { sysread $_[0], $_[1], $_[2], (@_>3?$_[3]:()); });
unless( defined $I->expected ) {
undef $I->end_of_input;
undef $I->received_fds if( $I->can('received_fds') );
$I->read_buffer='' unless( defined $I->read_buffer );
my $buflen=length($I->read_buffer);
while( $buflen<HEADERLENGTH ) {
my $len=$reader->( $I, $I->read_buffer, HEADERLENGTH-$buflen, $buflen );
if( defined($len) && $len==0 ) { # EOF
undef $I->read_buffer;
$I->end_of_input=1;
return;
} elsif( !defined($len) && $!==EAGAIN ) {
return; # non blocking file handle
} elsif( !defined($len) && $!==EINTR ) {
next; # interrupted
} elsif( !$len ) { # ERROR
$len=length $I->read_buffer;
undef $I->read_buffer;
croak "IO::Handle::Record: sysread";
}
$buflen+=$len;
}
my $L=($I->record_opts && $I->record_opts->{local_encoding}) ? 'L' : 'N';
if( $I->can('expect_fds') ) {
($I->expected, $I->expect_fds)=unpack $L.'2', $I->read_buffer;
} else {
($I->expected)=unpack $L.'2', $I->read_buffer;
}
$I->read_buffer='';
}
my $wanted=$I->expected;
my $buflen=length($I->read_buffer);
while( $buflen<$wanted ) {
my $len=$reader->( $I, $I->read_buffer, $wanted-$buflen, $buflen );
if( defined $len and $len>0 ) {
$buflen+=$len;
} elsif( defined $len ) { # EOF
$len=length $I->read_buffer;
( run in 1.049 second using v1.01-cache-2.11-cpan-d8267643d1d )