<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;
our(@ISA, $VERSION);
use IO::Socket;
use Socket;
use Carp;
use Exporter;
use Errno;

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

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
		  );

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

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

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

  if(defined $proto  &amp;&amp; $proto =~ /\D/) {
    if(@proto = getprotobyname($proto)) {
      $proto = $proto[2] || undef;
    }
    else {
      $@ = "Bad protocol '$proto'";
      return;
    }
  }

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

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

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

    $proto = (getprotobyname($serv[3]))[2] || undef
	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).": ";
      $@ = join("", $_[0] =~ /^$title/ ? "" : $title, @_);
      close($sock)
	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 ||= (getprotobyname('tcp'))[2];

    my $pname = (getprotobynumber($proto))[0];
    $type = $arg-&gt;{Type} || $socket_type{lc $pname};

    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__

</pre></body></html>