/usr/lib/perl5/Coro/Socket.pm is in libcoro-perl 6.330-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 | =head1 NAME
Coro::Socket - non-blocking socket-I/O
=head1 SYNOPSIS
use Coro::Socket;
# listen on an ipv4 socket
my $socket = new Coro::Socket PeerHost => "localhost",
PeerPort => 'finger';
# listen on any other type of socket
my $socket = Coro::Socket->new_from_fh
(IO::Socket::UNIX->new
Local => "/tmp/socket",
Type => SOCK_STREAM,
);
=head1 DESCRIPTION
This module is an L<AnyEvent> user, you need to make sure that you use and
run a supported event loop.
This module implements socket-handles in a coroutine-compatible way,
that is, other coroutines can run while reads or writes block on the
handle. See L<Coro::Handle>, especially the note about prefering method
calls.
=head1 IPV6 WARNING
This module was written to imitate the L<IO::Socket::INET> API, and derive
from it. Since IO::Socket::INET does not support IPv6, this module does
neither.
Therefore it is not recommended to use Coro::Socket in new code. Instead,
use L<AnyEvent::Socket> and L<Coro::Handle>, e.g.:
use Coro;
use Coro::Handle;
use AnyEvent::Socket;
# use tcp_connect from AnyEvent::Socket
# and call Coro::Handle::unblock on it.
tcp_connect "www.google.com", 80, Coro::rouse_cb;
my $fh = unblock +(Coro::rouse_wait)[0];
# now we have a perfectly thread-safe socket handle in $fh
print $fh "GET / HTTP/1.0\015\012\015\012";
local $/;
print <$fh>;
Using C<AnyEvent::Socket::tcp_connect> gives you transparent IPv6,
multi-homing, SRV-record etc. support.
For listening sockets, use C<AnyEvent::Socket::tcp_server>.
=over 4
=cut
package Coro::Socket;
use common::sense;
use Errno ();
use Carp qw(croak);
use Socket;
use IO::Socket::INET ();
use Coro::Util ();
use base qw(Coro::Handle IO::Socket::INET);
our $VERSION = 6.33;
our (%_proto, %_port);
sub _proto($) {
$_proto{$_[0]} ||= do {
((getprotobyname $_[0])[2] || (getprotobynumber $_[0])[2])
or croak "unsupported protocol: $_[0]";
};
}
sub _port($$) {
$_port{$_[0],$_[1]} ||= do {
return $_[0] if $_[0] =~ /^\d+$/;
$_[0] =~ /([^(]+)\s*(?:\((\d+)\))?/x
or croak "unparsable port number: $_[0]";
((getservbyname $1, $_[1])[2]
|| (getservbyport $1, $_[1])[2]
|| $2)
or croak "unknown port: $_[0]";
};
}
sub _sa($$$) {
my ($host, $port, $proto) = @_;
$port or $host =~ s/:([^:]+)$// and $port = $1;
my $_proto = _proto($proto);
my $_port = _port($port, $proto);
my $_host = Coro::Util::inet_aton $host
or croak "$host: unable to resolve";
pack_sockaddr_in $_port, $_host
}
=item $fh = new Coro::Socket param => value, ...
Create a new non-blocking tcp handle and connect to the given host
and port. The parameter names and values are mostly the same as for
IO::Socket::INET (as ugly as I think they are).
The parameters officially supported currently are: C<ReuseAddr>,
C<LocalPort>, C<LocalHost>, C<PeerPort>, C<PeerHost>, C<Listen>, C<Timeout>,
C<SO_RCVBUF>, C<SO_SNDBUF>.
$fh = new Coro::Socket PeerHost => "localhost", PeerPort => 'finger';
=cut
sub _prepare_socket {
my ($self, $arg) = @_;
$self
}
sub new {
my ($class, %arg) = @_;
$arg{Proto} ||= 'tcp';
$arg{LocalHost} ||= delete $arg{LocalAddr};
$arg{PeerHost} ||= delete $arg{PeerAddr};
defined ($arg{Type}) or $arg{Type} = $arg{Proto} eq "tcp" ? SOCK_STREAM : SOCK_DGRAM;
socket my $fh, PF_INET, $arg{Type}, _proto ($arg{Proto})
or return;
my $self = bless Coro::Handle->new_from_fh (
$fh,
timeout => $arg{Timeout},
forward_class => $arg{forward_class},
partial => $arg{partial},
), $class
or return;
$self->configure (\%arg)
}
sub configure {
my ($self, $arg) = @_;
if ($arg->{ReuseAddr}) {
$self->setsockopt (SOL_SOCKET, SO_REUSEADDR, 1)
or croak "setsockopt(SO_REUSEADDR): $!";
}
if ($arg->{ReusePort}) {
$self->setsockopt (SOL_SOCKET, SO_REUSEPORT, 1)
or croak "setsockopt(SO_REUSEPORT): $!";
}
if ($arg->{Broadcast}) {
$self->setsockopt (SOL_SOCKET, SO_BROADCAST, 1)
or croak "setsockopt(SO_BROADCAST): $!";
}
if ($arg->{SO_RCVBUF}) {
$self->setsockopt (SOL_SOCKET, SO_RCVBUF, $arg->{SO_RCVBUF})
or croak "setsockopt(SO_RCVBUF): $!";
}
if ($arg->{SO_SNDBUF}) {
$self->setsockopt (SOL_SOCKET, SO_SNDBUF, $arg->{SO_SNDBUF})
or croak "setsockopt(SO_SNDBUF): $!";
}
if ($arg->{LocalPort} || $arg->{LocalHost}) {
my @sa = _sa($arg->{LocalHost} || "0.0.0.0", $arg->{LocalPort} || 0, $arg->{Proto});
$self->bind ($sa[0])
or croak "bind($arg->{LocalHost}:$arg->{LocalPort}): $!";
}
if ($arg->{PeerHost}) {
my @sa = _sa ($arg->{PeerHost}, $arg->{PeerPort}, $arg->{Proto});
for (@sa) {
$! = 0;
if ($self->connect ($_)) {
next unless writable $self;
$! = unpack "i", $self->getsockopt (SOL_SOCKET, SO_ERROR);
}
$! or last;
$!{ECONNREFUSED} or $!{ENETUNREACH} or $!{ETIMEDOUT} or $!{EHOSTUNREACH}
or return;
}
} elsif (exists $arg->{Listen}) {
$self->listen ($arg->{Listen})
or return;
}
$self
}
1;
=back
=head1 AUTHOR
Marc Lehmann <schmorp@schmorp.de>
http://home.schmorp.de/
=cut
|