Acme-Sort-Sleep
view release on metacpan or search on metacpan
local/lib/perl5/IO/Async/OS.pm view on Meta::CPAN
}
my $sock = eval {
IO::Socket->new(
Domain => $family,
Type => $socktype,
Proto => $proto,
);
};
return $sock if $sock;
# That failed. Most likely because the Domain was unrecognised. This
# usually happens if getaddrinfo returns an AF_INET6 address but we don't
# have a suitable class loaded. In this case we'll return a generic one.
# It won't be in the specific subclass but that's the best we can do. And
# it will still work as a generic socket.
return IO::Socket->new->socket( $family, $socktype, $proto );
}
=head2 socketpair
( $S1, $S2 ) = IO::Async::OS->socketpair( $family, $socktype, $proto )
An abstraction of the C<socketpair(2)> syscall, where any argument may be
missing (or given as C<undef>).
If C<$family> is not provided, a suitable value will be provided by the OS
(likely C<AF_UNIX> on POSIX-based platforms). If C<$socktype> is not provided,
then C<SOCK_STREAM> will be used.
Additionally, this method supports building connected C<SOCK_STREAM> or
C<SOCK_DGRAM> pairs in the C<AF_INET> family even if the underlying platform's
C<socketpair(2)> does not, by connecting two normal sockets together.
C<$family> and C<$socktype> may also be given symbolically as defined by
C<getfamilybyname> and C<getsocktypebyname>.
=cut
sub socketpair
{
my $self = shift;
my ( $family, $socktype, $proto ) = @_;
# PF_UNSPEC and undef are both false
$family = $self->getfamilybyname( $family ) || AF_UNIX;
# SOCK_STREAM is the most likely
$socktype = $self->getsocktypebyname( $socktype ) || SOCK_STREAM;
$proto ||= 0;
my ( $S1, $S2 ) = IO::Socket->new->socketpair( $family, $socktype, $proto );
return ( $S1, $S2 ) if defined $S1;
return unless $family == AF_INET and ( $socktype == SOCK_STREAM or $socktype == SOCK_DGRAM );
# Now lets emulate an AF_INET socketpair call
my $Stmp = IO::Async::OS->socket( $family, $socktype ) or return;
$Stmp->bind( pack_sockaddr_in( 0, INADDR_LOOPBACK ) ) or return;
$S1 = IO::Async::OS->socket( $family, $socktype ) or return;
if( $socktype == SOCK_STREAM ) {
$Stmp->listen( 1 ) or return;
$S1->connect( getsockname $Stmp ) or return;
$S2 = $Stmp->accept or return;
# There's a bug in IO::Socket here, in that $S2 's ->socktype won't
# yet be set. We can apply a horribly hacky fix here
# defined $S2->socktype and $S2->socktype == $socktype or
# ${*$S2}{io_socket_type} = $socktype;
# But for now we'll skip the test for it instead
}
else {
$S2 = $Stmp;
$S1->connect( getsockname $S2 ) or return;
$S2->connect( getsockname $S1 ) or return;
}
return ( $S1, $S2 );
}
=head2 pipepair
( $rd, $wr ) = IO::Async::OS->pipepair
An abstraction of the C<pipe(2)> syscall, which returns the two new handles.
=cut
sub pipepair
{
my $self = shift;
pipe( my ( $rd, $wr ) ) or return;
return ( $rd, $wr );
}
=head2 pipequad
( $rdA, $wrA, $rdB, $wrB ) = IO::Async::OS->pipequad
This method is intended for creating two pairs of filehandles that are linked
together, suitable for passing as the STDIN/STDOUT pair to a child process.
After this function returns, C<$rdA> and C<$wrA> will be a linked pair, as
will C<$rdB> and C<$wrB>.
On platforms that support C<socketpair(2)>, this implementation will be
preferred, in which case C<$rdA> and C<$wrB> will actually be the same
filehandle, as will C<$rdB> and C<$wrA>. This saves a file descriptor in the
parent process.
When creating a L<IO::Async::Stream> or subclass of it, the C<read_handle>
and C<write_handle> parameters should always be used.
my ( $childRd, $myWr, $myRd, $childWr ) = IO::Async::OS->pipequad;
IO::Async::OS->open_child(
stdin => $childRd,
local/lib/perl5/IO/Async/OS.pm view on Meta::CPAN
{
my $self = shift;
# Prefer socketpair
if( my ( $S1, $S2 ) = $self->socketpair ) {
return ( $S1, $S2, $S2, $S1 );
}
# Can't do that, fallback on pipes
my ( $rdA, $wrA ) = $self->pipepair or return;
my ( $rdB, $wrB ) = $self->pipepair or return;
return ( $rdA, $wrA, $rdB, $wrB );
}
=head2 signame2num
$signum = IO::Async::OS->signame2num( $signame )
This utility method converts a signal name (such as "TERM") into its system-
specific signal number. This may be useful to pass to C<POSIX::SigSet> or use
in other places which use numbers instead of symbolic names.
=cut
my %sig_num;
sub _init_signum
{
my $self = shift;
# Copypasta from Config.pm's documentation
our %Config;
require Config;
Config->import;
unless($Config{sig_name} && $Config{sig_num}) {
die "No signals found";
}
else {
my @names = split ' ', $Config{sig_name};
@sig_num{@names} = split ' ', $Config{sig_num};
}
}
sub signame2num
{
my $self = shift;
my ( $signame ) = @_;
%sig_num or $self->_init_signum;
return $sig_num{$signame};
}
=head2 extract_addrinfo
( $family, $socktype, $protocol, $addr ) = IO::Async::OS->extract_addrinfo( $ai )
Given an ARRAY or HASH reference value containing an addrinfo, returns a
family, socktype and protocol argument suitable for a C<socket> call and an
address suitable for C<connect> or C<bind>.
If given an ARRAY it should be in the following form:
[ $family, $socktype, $protocol, $addr ]
If given a HASH it should contain the following keys:
family socktype protocol addr
Each field in the result will be initialised to 0 (or empty string for the
address) if not defined in the C<$ai> value.
The family type may also be given as a symbolic string as defined by
C<getfamilybyname>.
The socktype may also be given as a symbolic string; C<stream>, C<dgram> or
C<raw>; this will be converted to the appropriate C<SOCK_*> constant.
Note that the C<addr> field, if provided, must be a packed socket address,
such as returned by C<pack_sockaddr_in> or C<pack_sockaddr_un>.
If the HASH form is used, rather than passing a packed socket address in the
C<addr> field, certain other hash keys may be used instead for convenience on
certain named families.
=over 4
=cut
use constant ADDRINFO_FAMILY => 0;
use constant ADDRINFO_SOCKTYPE => 1;
use constant ADDRINFO_PROTOCOL => 2;
use constant ADDRINFO_ADDR => 3;
sub extract_addrinfo
{
my $self = shift;
my ( $ai, $argname ) = @_;
$argname ||= "addr";
my @ai;
if( ref $ai eq "ARRAY" ) {
@ai = @$ai;
}
elsif( ref $ai eq "HASH" ) {
$ai = { %$ai }; # copy so we can delete from it
@ai = delete @{$ai}{qw( family socktype protocol addr )};
if( defined $ai[ADDRINFO_FAMILY] and !defined $ai[ADDRINFO_ADDR] ) {
my $family = $ai[ADDRINFO_FAMILY];
my $method = "_extract_addrinfo_$family";
my $code = $self->can( $method ) or croak "Cannot determine addr for extract_addrinfo on family='$family'";
$ai[ADDRINFO_ADDR] = $code->( $self, $ai );
keys %$ai and croak "Unrecognised '$family' addrinfo keys: " . join( ", ", keys %$ai );
}
}
( run in 0.633 second using v1.01-cache-2.11-cpan-2398b32b56e )