Coro

 view release on metacpan or  search on metacpan

Coro/Socket.pm  view on Meta::CPAN

=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.514;

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, ...



( run in 1.452 second using v1.01-cache-2.11-cpan-39bf76dae61 )