<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;"># IO::Socket::INET.pm
#
# Copyright (c) 1997-8 Graham Barr &lt;gbarr@pobox.com&gt;. All rights reserved.
# This program is free software; you can redistribute it and/or
# modify it under the same terms as Perl itself.

package IO::Socket::INET;

use strict;
use IO::Socket;
use Socket;
use Carp;
use Exporter;
use Errno;

our @ISA = qw(IO::Socket);
our $VERSION = "1.52";

my $EINVAL = exists(&amp;Errno::EINVAL) ? Errno::EINVAL() : 1;

IO::Socket::INET-&gt;register_domain( AF_INET );

my %socket_type = ( tcp  =&gt; SOCK_STREAM,
		    udp  =&gt; SOCK_DGRAM,
		    icmp =&gt; SOCK_RAW
		  );
my %proto_number;
$proto_number{tcp}  = Socket::IPPROTO_TCP()  if defined &amp;Socket::IPPROTO_TCP;
$proto_number{udp}  = Socket::IPPROTO_UDP()  if defined &amp;Socket::IPPROTO_UDP;
$proto_number{icmp} = Socket::IPPROTO_ICMP() if defined &amp;Socket::IPPROTO_ICMP;
my %proto_name = reverse %proto_number;

sub new {
    my $class = shift;
    unshift(@_, "PeerAddr") if @_ == 1;
    return $class-&gt;SUPER::new(@_);
}

sub _cache_proto {
    my @proto = @_;
    for (map lc($_), $proto[0], split(' ', $proto[1])) {
	$proto_number{$_} = $proto[2];
    }
    $proto_name{$proto[2]} = $proto[0];
}

sub _get_proto_number {
    my $name = lc(shift);
    return undef unless defined $name;
    return $proto_number{$name} if exists $proto_number{$name};

    my @proto = eval { getprotobyname($name) };
    return undef unless @proto;
    _cache_proto(@proto);

    return $proto[2];
}

sub _get_proto_name {
    my $num = shift;
    return undef unless defined $num;
    return $proto_name{$num} if exists $proto_name{$num};

    my @proto = eval { getprotobynumber($num) };
    return undef unless @proto;
    _cache_proto(@proto);

    return $proto[0];
}

sub _sock_info {
  my($addr,$port,$proto) = @_;
  my $origport = $port;
  my @serv = ();

  $port = $1
	if(defined $addr &amp;&amp; $addr =~ s,:([\w\(\)/]+)$,,);

  if(defined $proto  &amp;&amp; $proto =~ /\D/) {
    my $num = _get_proto_number($proto);
    unless (defined $num) {
      $IO::Socket::errstr = $@ = "Bad protocol '$proto'";
      return;
    }
    $proto = $num;
  }

  if(defined $port) {
    my $defport = ($port =~ s,\((\d+)\)$,,) ? $1 : undef;
    my $pnum = ($port =~ m,^(\d+)$,)[0];

    @serv = getservbyname($port, _get_proto_name($proto) || "")
	if ($port =~ m,\D,);

    $port = $serv[2] || $defport || $pnum;
    unless (defined $port) {
	$IO::Socket::errstr = $@ = "Bad service '$origport'";
	return;
    }

    $proto = _get_proto_number($serv[3]) if @serv &amp;&amp; !$proto;
  }

 return ($addr || undef,
	 $port || undef,
	 $proto || undef
	);
}

sub _error {
    my $sock = shift;
    my $err = shift;
    {
      local($!);
      my $title = ref($sock).": ";
      $IO::Socket::errstr = $@ = join("", $_[0] =~ /^$title/ ? "" : $title, @_);
      $sock-&gt;close()
	if(defined fileno($sock));
    }
    $! = $err;
    return undef;
}

sub _get_addr {
    my($sock,$addr_str, $multi) = @_;
    my @addr;
    if ($multi &amp;&amp; $addr_str !~ /^\d+(?:\.\d+){3}$/) {
	(undef, undef, undef, undef, @addr) = gethostbyname($addr_str);
    } else {
	my $h = inet_aton($addr_str);
	push(@addr, $h) if defined $h;
    }
    @addr;
}

sub configure {
    my($sock,$arg) = @_;
    my($lport,$rport,$laddr,$raddr,$proto,$type);


    $arg-&gt;{LocalAddr} = $arg-&gt;{LocalHost}
	if exists $arg-&gt;{LocalHost} &amp;&amp; !exists $arg-&gt;{LocalAddr};

    ($laddr,$lport,$proto) = _sock_info($arg-&gt;{LocalAddr},
					$arg-&gt;{LocalPort},
					$arg-&gt;{Proto})
			or return _error($sock, $!, $@);

    $laddr = defined $laddr ? inet_aton($laddr)
			    : INADDR_ANY;

    return _error($sock, $EINVAL, "Bad hostname '",$arg-&gt;{LocalAddr},"'")
	unless(defined $laddr);

    $arg-&gt;{PeerAddr} = $arg-&gt;{PeerHost}
	if exists $arg-&gt;{PeerHost} &amp;&amp; !exists $arg-&gt;{PeerAddr};

    unless(exists $arg-&gt;{Listen}) {
	($raddr,$rport,$proto) = _sock_info($arg-&gt;{PeerAddr},
					    $arg-&gt;{PeerPort},
					    $proto)
			or return _error($sock, $!, $@);
    }

    $proto ||= _get_proto_number('tcp');

    $type = $arg-&gt;{Type} || $socket_type{lc _get_proto_name($proto)};

    my @raddr = ();

    if(defined $raddr) {
	@raddr = $sock-&gt;_get_addr($raddr, $arg-&gt;{MultiHomed});
	return _error($sock, $EINVAL, "Bad hostname '",$arg-&gt;{PeerAddr},"'")
	    unless @raddr;
    }

    while(1) {

	$sock-&gt;socket(AF_INET, $type, $proto) or
	    return _error($sock, $!, "$!");

        if (defined $arg-&gt;{Blocking}) {
	    defined $sock-&gt;blocking($arg-&gt;{Blocking})
		or return _error($sock, $!, "$!");
	}

	if ($arg-&gt;{Reuse} || $arg-&gt;{ReuseAddr}) {
	    $sock-&gt;sockopt(SO_REUSEADDR,1) or
		    return _error($sock, $!, "$!");
	}

	if ($arg-&gt;{ReusePort}) {
	    $sock-&gt;sockopt(SO_REUSEPORT,1) or
		    return _error($sock, $!, "$!");
	}

	if ($arg-&gt;{Broadcast}) {
		$sock-&gt;sockopt(SO_BROADCAST,1) or
		    return _error($sock, $!, "$!");
	}

	if($lport || ($laddr ne INADDR_ANY) || exists $arg-&gt;{Listen}) {
	    $sock-&gt;bind($lport || 0, $laddr) or
		    return _error($sock, $!, "$!");
	}

	if(exists $arg-&gt;{Listen}) {
	    $sock-&gt;listen($arg-&gt;{Listen} || 5) or
		return _error($sock, $!, "$!");
	    last;
	}

 	# don't try to connect unless we're given a PeerAddr
 	last unless exists($arg-&gt;{PeerAddr});
 
        $raddr = shift @raddr;

	return _error($sock, $EINVAL, 'Cannot determine remote port')
		unless($rport || $type == SOCK_DGRAM || $type == SOCK_RAW);

	last
	    unless($type == SOCK_STREAM || defined $raddr);

	return _error($sock, $EINVAL, "Bad hostname '",$arg-&gt;{PeerAddr},"'")
	    unless defined $raddr;

#        my $timeout = ${*$sock}{'io_socket_timeout'};
#        my $before = time() if $timeout;

	undef $@;
        if ($sock-&gt;connect(pack_sockaddr_in($rport, $raddr))) {
#            ${*$sock}{'io_socket_timeout'} = $timeout;
            return $sock;
        }

	return _error($sock, $!, $@ || "Timeout")
	    unless @raddr;

#	if ($timeout) {
#	    my $new_timeout = $timeout - (time() - $before);
#	    return _error($sock,
#                         (exists(&amp;Errno::ETIMEDOUT) ? Errno::ETIMEDOUT() : $EINVAL),
#                         "Timeout") if $new_timeout &lt;= 0;
#	    ${*$sock}{'io_socket_timeout'} = $new_timeout;
#        }

    }

    $sock;
}

sub connect {
    @_ == 2 || @_ == 3 or
       croak 'usage: $sock-&gt;connect(NAME) or $sock-&gt;connect(PORT, ADDR)';
    my $sock = shift;
    return $sock-&gt;SUPER::connect(@_ == 1 ? shift : pack_sockaddr_in(@_));
}

sub bind {
    @_ == 2 || @_ == 3 or
       croak 'usage: $sock-&gt;bind(NAME) or $sock-&gt;bind(PORT, ADDR)';
    my $sock = shift;
    return $sock-&gt;SUPER::bind(@_ == 1 ? shift : pack_sockaddr_in(@_))
}

sub sockaddr {
    @_ == 1 or croak 'usage: $sock-&gt;sockaddr()';
    my($sock) = @_;
    my $name = $sock-&gt;sockname;
    $name ? (sockaddr_in($name))[1] : undef;
}

sub sockport {
    @_ == 1 or croak 'usage: $sock-&gt;sockport()';
    my($sock) = @_;
    my $name = $sock-&gt;sockname;
    $name ? (sockaddr_in($name))[0] : undef;
}

sub sockhost {
    @_ == 1 or croak 'usage: $sock-&gt;sockhost()';
    my($sock) = @_;
    my $addr = $sock-&gt;sockaddr;
    $addr ? inet_ntoa($addr) : undef;
}

sub peeraddr {
    @_ == 1 or croak 'usage: $sock-&gt;peeraddr()';
    my($sock) = @_;
    my $name = $sock-&gt;peername;
    $name ? (sockaddr_in($name))[1] : undef;
}

sub peerport {
    @_ == 1 or croak 'usage: $sock-&gt;peerport()';
    my($sock) = @_;
    my $name = $sock-&gt;peername;
    $name ? (sockaddr_in($name))[0] : undef;
}

sub peerhost {
    @_ == 1 or croak 'usage: $sock-&gt;peerhost()';
    my($sock) = @_;
    my $addr = $sock-&gt;peeraddr;
    $addr ? inet_ntoa($addr) : undef;
}

1;

__END__

=head1 NAME

IO::Socket::INET - Object interface for AF_INET domain sockets

=head1 SYNOPSIS

    use IO::Socket::INET;

=head1 DESCRIPTION

C&lt;IO::Socket::INET&gt; provides an object interface to creating and using sockets
in the AF_INET domain. It is built upon the L&lt;IO::Socket&gt; interface and
inherits all the methods defined by L&lt;IO::Socket&gt;.

=head1 CONSTRUCTOR

=over 4

=item new ( [ARGS] )

Creates an C&lt;IO::Socket::INET&gt; object, which is a reference to a
newly created symbol (see the L&lt;Symbol&gt; package). C&lt;new&gt;
optionally takes arguments, these arguments are in key-value pairs.

In addition to the key-value pairs accepted by L&lt;IO::Socket&gt;,
C&lt;IO::Socket::INET&gt; provides.


 PeerAddr    Remote host address          &lt;hostname&gt;[:&lt;port&gt;]
 PeerHost    Synonym for PeerAddr
 PeerPort    Remote port or service       &lt;service&gt;[(&lt;no&gt;)] | &lt;no&gt;
 LocalAddr   Local host bind address      hostname[:port]
 LocalHost   Synonym for LocalAddr
 LocalPort   Local host bind port         &lt;service&gt;[(&lt;no&gt;)] | &lt;no&gt;
 Proto       Protocol name (or number)    "tcp" | "udp" | ...
 Type        Socket type              SOCK_STREAM | SOCK_DGRAM | ...
 Listen      Queue size for listen
 ReuseAddr   Set SO_REUSEADDR before binding
 Reuse       Set SO_REUSEADDR before binding (deprecated,
                                              prefer ReuseAddr)
 ReusePort   Set SO_REUSEPORT before binding
 Broadcast   Set SO_BROADCAST before binding
 Timeout     Timeout value for various operations
 MultiHomed  Try all addresses for multi-homed hosts
 Blocking    Determine if connection will be blocking mode

If C&lt;Listen&gt; is defined then a listen socket is created, else if the
socket type, which is derived from the protocol, is SOCK_STREAM then
connect() is called.  If the C&lt;Listen&gt; argument is given, but false,
the queue size will be set to 5.

Although it is not illegal, the use of C&lt;MultiHomed&gt; on a socket
which is in non-blocking mode is of little use. This is because the
first connect will never fail with a timeout as the connect call
will not block.

The C&lt;PeerAddr&gt; can be a hostname or the IP-address on the
"xx.xx.xx.xx" form.  The C&lt;PeerPort&gt; can be a number or a symbolic
service name.  The service name might be followed by a number in
parenthesis which is used if the service is not known by the system.
The C&lt;PeerPort&gt; specification can also be embedded in the C&lt;PeerAddr&gt;
by preceding it with a ":".

If C&lt;Proto&gt; is not given and you specify a symbolic C&lt;PeerPort&gt; port,
then the constructor will try to derive C&lt;Proto&gt; from the service
name.  As a last resort C&lt;Proto&gt; "tcp" is assumed.  The C&lt;Type&gt;
parameter will be deduced from C&lt;Proto&gt; if not specified.

If the constructor is only passed a single argument, it is assumed to
be a C&lt;PeerAddr&gt; specification.

If C&lt;Blocking&gt; is set to 0, the connection will be in nonblocking mode.
If not specified it defaults to 1 (blocking mode).

Examples:

   $sock = IO::Socket::INET-&gt;new(PeerAddr =&gt; 'www.perl.org',
                                 PeerPort =&gt; 'http(80)',
                                 Proto    =&gt; 'tcp');

   $sock = IO::Socket::INET-&gt;new(PeerAddr =&gt; 'localhost:smtp(25)');

   $sock = IO::Socket::INET-&gt;new(Listen    =&gt; 5,
                                 LocalAddr =&gt; 'localhost',
                                 LocalPort =&gt; 9000,
                                 Proto     =&gt; 'tcp');

   $sock = IO::Socket::INET-&gt;new('127.0.0.1:25');

   $sock = IO::Socket::INET-&gt;new(
                           PeerPort  =&gt; 9999,
                           PeerAddr  =&gt; inet_ntoa(INADDR_BROADCAST),
                           Proto     =&gt; 'udp',
                           LocalAddr =&gt; 'localhost',
                           Broadcast =&gt; 1 ) 
                       or die "Can't bind : $IO::Socket::errstr\n";

If the constructor fails it will return C&lt;undef&gt; and set the
C&lt;$IO::Socket::errstr&gt; package variable to contain an error message.

    $sock = IO::Socket::INET-&gt;new(...)
        or die "Cannot create socket - $IO::Socket::errstr\n";

For legacy reasons the error message is also set into the global C&lt;$@&gt;
variable, and you may still find older code which looks here instead.

    $sock = IO::Socket::INET-&gt;new(...)
        or die "Cannot create socket - $@\n";

=back

=head2 METHODS

=over 4

=item sockaddr ()

Return the address part of the sockaddr structure for the socket

=item sockport ()

Return the port number that the socket is using on the local host

=item sockhost ()

Return the address part of the sockaddr structure for the socket in a
text form xx.xx.xx.xx

=item peeraddr ()

Return the address part of the sockaddr structure for the socket on
the peer host

=item peerport ()

Return the port number for the socket on the peer host.

=item peerhost ()

Return the address part of the sockaddr structure for the socket on the
peer host in a text form xx.xx.xx.xx

=back

=head1 SEE ALSO

L&lt;Socket&gt;, L&lt;IO::Socket&gt;

=head1 AUTHOR

Graham Barr. Currently maintained by the Perl Porters.  Please report all
bugs at L&lt;https://github.com/Perl/perl5/issues&gt;.

=head1 COPYRIGHT

Copyright (c) 1996-8 Graham Barr &lt;gbarr@pobox.com&gt;. All rights reserved.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.

=cut
</pre></body></html>