diff options
author | crees <crees@FreeBSD.org> | 2012-02-07 02:31:40 +0800 |
---|---|---|
committer | crees <crees@FreeBSD.org> | 2012-02-07 02:31:40 +0800 |
commit | 701a48117490b75a14f5b29ff6eae2c933eb98a3 (patch) | |
tree | 1405a22bd37e4a90060cecaea26cb01e5e437ffe /net | |
parent | 6c0b8ecefdd700ddeb7b5e0a3c9a0e7669ef0239 (diff) | |
download | freebsd-ports-gnome-701a48117490b75a14f5b29ff6eae2c933eb98a3.tar.gz freebsd-ports-gnome-701a48117490b75a14f5b29ff6eae2c933eb98a3.tar.zst freebsd-ports-gnome-701a48117490b75a14f5b29ff6eae2c933eb98a3.zip |
Add OPTION for ipv6 support from Debian
Suggested by: Niclas Zeising (zeising@daemonic.se)
Diffstat (limited to 'net')
-rw-r--r-- | net/p5-Net-Server/Makefile | 8 | ||||
-rw-r--r-- | net/p5-Net-Server/files/extra-patch-ipv6-support | 1384 |
2 files changed, 1392 insertions, 0 deletions
diff --git a/net/p5-Net-Server/Makefile b/net/p5-Net-Server/Makefile index 6f36eccf0e84..1649ab88ab1c 100644 --- a/net/p5-Net-Server/Makefile +++ b/net/p5-Net-Server/Makefile @@ -18,6 +18,8 @@ RUN_DEPENDS= ${SITE_PERL}/IO/Multiplex.pm:${PORTSDIR}/devel/p5-IO-Multiplex PERL_CONFIGURE= yes +OPTIONS= IPV6 "Enable ipv6 support patch from Debian" off + MAN3= Net::Server.3 \ Net::Server::Daemonize.3\ Net::Server::Fork.3 \ @@ -36,4 +38,10 @@ MAN3= Net::Server.3 \ Net::Server::SIG.3\ Net::Server::Single.3 +.include <bsd.port.options.mk> + +.if defined(WITH_IPV6) +EXTRA_PATCHES= ${FILESDIR}/extra-patch-ipv6-support +.endif + .include <bsd.port.mk> diff --git a/net/p5-Net-Server/files/extra-patch-ipv6-support b/net/p5-Net-Server/files/extra-patch-ipv6-support new file mode 100644 index 000000000000..277fa013a609 --- /dev/null +++ b/net/p5-Net-Server/files/extra-patch-ipv6-support @@ -0,0 +1,1384 @@ +--- Net-Server-0.99/lib/Net/Server/Proto/UDP.pm 2008-02-08 03:40:33.000000000 +0100 ++++ Net-Server-0.99/lib/Net/Server/Proto/UDP.pm 2010-10-05 15:41:16.000000000 +0200 +@@ -35,9 +35,4 @@ + my $class = ref($type) || $type || __PACKAGE__; + +- my $sock = $class->SUPER::object( @_ ); +- +- $sock->NS_proto('UDP'); +- +- ### set a few more parameters + my($default_host,$port,$server) = @_; + my $prop = $server->{server}; +@@ -62,33 +57,42 @@ + && $prop->{udp_broadcast}; + +- $sock->NS_recv_len( $prop->{udp_recv_len} ); +- $sock->NS_recv_flags( $prop->{udp_recv_flags} ); ++ my @sockets_list = $class->SUPER::object( @_ ); + +- return $sock; ++ foreach my $sock ( @sockets_list ){ ++ $sock->NS_proto('UDP'); ++ $sock->NS_recv_len( $prop->{udp_recv_len} ); ++ $sock->NS_recv_flags( $prop->{udp_recv_flags} ); ++ } ++ ++ ### returns any number of sockets, ++ ### one for each protocol family (PF_INET or PF_INET6) and each bind address ++ return !wantarray ? $sockets_list[0] : @sockets_list; + } + + +-### connect the first time ++### bind the first time + ### doesn't support the listen or the reuse option + sub connect { +- my $sock = shift; +- my $server = shift; +- my $prop = $server->{server}; +- +- my $host = $sock->NS_host; +- my $port = $sock->NS_port; ++ my $sock = shift; ++ my $server = shift; ++ my $prop = $server->{server}; ++ ++ my $host = $sock->NS_host; ++ my $port = $sock->NS_port; ++ my $pfamily = $sock->NS_family || 0; + +- my %args = (); ++ my %args; + $args{LocalPort} = $port; # what port to bind on + $args{Proto} = 'udp'; # what procol to use + $args{LocalAddr} = $host if $host !~ /\*/; # what local address (* is all) ++ $args{Domain} = $pfamily if $Net::Server::Proto::TCP::have_inet6 && $pfamily; + $args{Reuse} = 1; # allow us to rebind the port on a restart + $args{Broadcast} = 1 if $prop->{udp_broadcast}; + +- ### connect to the sock ++ ### bind to the sock + $sock->SUPER::configure(\%args) +- or $server->fatal("Can't connect to UDP port $port on $host [$!]"); ++ or $server->fatal("Can't bind to UDP port $port on $host [$!]"); + +- $server->fatal("Back sock [$!]!".caller()) ++ $server->fatal("Bad sock [$!]!".caller()) + unless $sock; + +--- Net-Server-0.99/lib/Net/Server/Proto.pm 2010-05-05 06:13:22.000000000 +0200 ++++ Net-Server-0.99/lib/Net/Server/Proto.pm 2010-10-05 17:56:38.000000000 +0200 +@@ -69,5 +69,6 @@ + + +- ### return an object of that procol class ++ ### returns any number of objects (socket), ++ ### one for each protocol family (PF_INET or PF_INET6) and each bind address + return $proto_class->object($default_host,$port,$server); + +@@ -84,5 +85,5 @@ + =head1 SYNOPSIS + +- # Net::Server::Proto and its accompianying modules are not ++ # Net::Server::Proto and its accompanying modules are not + # intended to be used outside the scope of Net::Server. + +@@ -103,5 +104,5 @@ + + ### Net::Server::Proto will attempt to interface with +- ### sub modules named simillar to Net::Server::Proto::TCP ++ ### sub modules named similar to Net::Server::Proto::TCP + ### Individual sub modules will be loaded by + ### Net::Server::Proto as they are needed. +@@ -225,8 +226,22 @@ + The port is the most important argument passed to the sub + module classes and to Net::Server::Proto itself. For tcp, +-udp, and ssl style ports, the form is generally +-host:port/protocol, host|port|protocol, host/port, or port. +-For unix the form is generally socket_file|type|unix or +-socket_file. ++udp, and ssl style ports, the form is generally host:port/protocol ++or [host]:port/protocol, host|port|protocol, host/port, or port. ++If I<host> is a numerical IPv6 address it must be enclosed in square ++brackets to avoid ambiguity in parsing a port number, e.g.: "[::1]:80". ++For unix sockets the form is generally socket_file|type|unix or socket_file. ++ ++A socket protocol family PF_INET or PF_INET6 is derived from a specified ++address family of the binding address. A PF_INET socket can only accept ++IPv4 connections. A PF_INET6 socket accepts IPv6 connections, but may also ++accept IPv4 connections, depending on OS and its settings. For example, ++on FreeBSD systems setting a sysctl net.inet6.ip6.v6only to 0 will allow ++IPv4 connections to a PF_INET6 socket. ++ ++The Net::Server::Proto::object method returns a list of objects corresponding ++to created sockets. For Unix and INET sockets the list typically contains ++just one element, but may return multiple objects when multiple protocol ++families are allowed or when a host name resolves to multiple local ++binding addresses. + + You can see what Net::Server::Proto parsed out by looking at +--- Net-Server-0.99/lib/Net/Server.pm 2010-07-09 16:55:31.000000000 +0200 ++++ Net-Server-0.99/lib/Net/Server.pm 2010-10-05 19:52:16.000000000 +0200 +@@ -26,5 +26,5 @@ + use strict; + use vars qw($VERSION); +-use Socket qw(inet_aton inet_ntoa AF_INET AF_UNIX SOCK_DGRAM SOCK_STREAM); ++use Socket qw(AF_INET AF_UNIX SOCK_DGRAM SOCK_STREAM); + use IO::Socket (); + use IO::Select (); +@@ -356,6 +356,12 @@ + push @{ $prop->{host} }, (($prop->{host}->[-1]) x (@{ $prop->{port} } - @{ $prop->{host}})); # augment hosts with as many as port + foreach my $host (@{ $prop->{host} }) { +- $host = '*' if ! defined $host || ! length $host;; +- $host = ($host =~ /^([\w\.\-\*\/]+)$/) ? $1 : $self->fatal("Unsecure host \"$host\""); ++ local $1; ++ if (!defined $host || $host eq '' || $host eq '*') { ++ $host = '*'; ++ } elsif ($host =~ /^\[([\w\/.:-]+)\]$/ || $host =~ /^([\w\/.:-]+)$/) { ++ $host = $1; ++ } else { ++ $self->fatal("Unsecure host \"$host\""); ++ } + } + +@@ -377,10 +383,12 @@ + my $host = $prop->{host}->[$i]; + my $proto = $prop->{proto}->[$i]; +- if ($port ne 0 && $bound{"$host/$port/$proto"}++) { ++ if ($port ne "0" && $bound{"$host/$port/$proto"}++) { + $self->log(2, "Duplicate configuration (".(uc $proto)." port $port on host $host - skipping"); + next; + } +- my $obj = $self->proto_object($host, $port, $proto) || next; +- push @{ $prop->{sock} }, $obj; ++ my @obj_list = $self->proto_object($host, $port, $proto); ++ for my $obj (@obj_list) { ++ push @{ $prop->{sock} }, $obj if $obj; ++ } + } + if (! @{ $prop->{sock} }) { +@@ -397,5 +405,7 @@ + } + +-### method for invoking procol specific bindings ++### method for invoking procol specific bindings; ++### returns any number of sockets, ++### one for each protocol family (PF_INET or PF_INET6) and each bind address + sub proto_object { + my $self = shift; +@@ -440,6 +450,8 @@ + } + +- ### if more than one port we'll need to select on it +- if( @{ $prop->{port} } > 1 || $prop->{multi_port} ){ ++ ### if more than one socket we'll need to select on it; ++ ### note there may be more than one socket per port, ++ ### one for each protocol family (PF_INET and PF_INET6) ++ if( @{ $prop->{sock} } > 1 || $prop->{multi_port} ){ + $prop->{multi_port} = 1; + $prop->{select} = IO::Select->new(); +@@ -748,5 +760,7 @@ + return; + } elsif ($self->isa('Net::Server::INET')) { +- $prop->{sockaddr} = $ENV{'REMOTE_HOST'} || '0.0.0.0'; ++ # since we do not know a socket protocol family, we are unable ++ # to choose between '0.0.0.0' and '::' as an unspecified address ++ $prop->{sockaddr} = $ENV{'REMOTE_HOST'} || '0.0.0.0'; # or is is a '::' ? + $prop->{peeraddr} = '0.0.0.0'; + $prop->{sockhost} = $prop->{peerhost} = 'inetd.server'; +@@ -756,12 +770,12 @@ + + ### read information about this connection +- my $sockname = getsockname( $sock ); ++ my $sockname = $sock->sockname; + if( $sockname ){ +- ($prop->{sockport}, $prop->{sockaddr}) +- = Socket::unpack_sockaddr_in( $sockname ); +- $prop->{sockaddr} = inet_ntoa( $prop->{sockaddr} ); +- ++ $prop->{sockaddr} = $sock->sockhost; ++ $prop->{sockport} = $sock->sockport; + }else{ + ### does this only happen from command line? ++ # since we do not know a socket protocol family, we are unable ++ # to choose between '0.0.0.0' and '::' as an unspecified address + $prop->{sockaddr} = $ENV{'REMOTE_HOST'} || '0.0.0.0'; + $prop->{sockhost} = 'inet.test'; +@@ -773,16 +787,24 @@ + if( $prop->{udp_true} ){ + $proto_type = 'UDP'; +- ($prop->{peerport} ,$prop->{peeraddr}) +- = Socket::sockaddr_in( $prop->{udp_peer} ); +- }elsif( $prop->{peername} = getpeername( $sock ) ){ +- ($prop->{peerport}, $prop->{peeraddr}) +- = Socket::unpack_sockaddr_in( $prop->{peername} ); +- } +- +- if( $prop->{peername} || $prop->{udp_true} ){ +- $prop->{peeraddr} = inet_ntoa( $prop->{peeraddr} ); +- +- if( defined $prop->{reverse_lookups} ){ +- $prop->{peerhost} = gethostbyaddr( inet_aton($prop->{peeraddr}), AF_INET ); ++ if ($sock->sockdomain == AF_INET) { ($prop->{peerport}, $prop->{peeraddrn}) = Socket::sockaddr_in($prop->{udp_peer}); ++ } else { ($prop->{peerport}, $prop->{peeraddrn}) = Socket6::sockaddr_in6($prop->{udp_peer}); ++ } ++ $prop->{peeraddr} = Socket6->UNIVERSAL::can('inet_ntop') ++ ? Socket6::inet_ntop($sock->sockdomain, $prop->{peeraddrn}) ++ : Socket::inet_ntoa( $prop->{peeraddrn} ); ++ }elsif( $prop->{peername} = $sock->peername ){ ++ $prop->{peeraddrn} = $sock->peeraddr; # binary ++ $prop->{peeraddr} = $sock->peerhost; # ascii ++ $prop->{peerport} = $sock->peerport; ++ } ++ ++ if( $prop->{peeraddrn} ){ ++ if( !defined $prop->{reverse_lookups} ){ ++ # no reverse DNS resolving ++ }elsif( Socket6->UNIVERSAL::can('getnameinfo') ){ ++ my @res = Socket6::getnameinfo( $prop->{peeraddrn}, 0 ); ++ $prop->{peerhost} = $res[0] if @res > 1; ++ }else{ ++ $prop->{peerhost} = gethostbyaddr( $prop->{peeraddrn}, AF_INET ); + } + $prop->{peerhost} = '' unless defined $prop->{peerhost}; +@@ -790,4 +812,6 @@ + }else{ + ### does this only happen from command line? ++ # since we do not know a socket protocol family, we are unable ++ # to choose between '0.0.0.0' and '::' as an unspecified address + $prop->{peeraddr} = '0.0.0.0'; + $prop->{peerhost} = 'inet.test'; +@@ -796,6 +820,6 @@ + + $self->log(3,$self->log_time +- ." CONNECT $proto_type Peer: \"$prop->{peeraddr}:$prop->{peerport}\"" +- ." Local: \"$prop->{sockaddr}:$prop->{sockport}\"\n"); ++ ." CONNECT $proto_type Peer: \"[$prop->{peeraddr}]:$prop->{peerport}\"" ++ ." Local: \"[$prop->{sockaddr}]:$prop->{sockport}\"\n"); + + } +@@ -1141,9 +1165,11 @@ + foreach my $sock ( @{ $prop->{sock} } ){ + +- ### duplicate the sock ++ ### duplicate the socket descriptor + my $fd = POSIX::dup($sock->fileno) + or $self->fatal("Can't dup socket [$!]"); + +- ### hold on to the socket copy until exec ++ ### hold on to the socket copy until exec; ++ ### just temporary: any socket domain will do, ++ ### forked process will decide to use IO::Socket::INET6 if necessary + $prop->{_HUP}->[$i] = IO::Socket::INET->new; + $prop->{_HUP}->[$i]->fdopen($fd, 'w') +@@ -1153,5 +1179,5 @@ + $prop->{_HUP}->[$i]->fcntl( Fcntl::F_SETFD(), my $flags = "" ); + +- ### save host,port,proto, and file descriptor ++ ### save file descriptor and host|port|proto|family + push @fd, $fd .'|'. $sock->hup_string; + +--- Net-Server-0.99/lib/Net/Server.pod 2010-07-08 21:22:42.000000000 +0200 ++++ Net-Server-0.99/lib/Net/Server.pod 2010-10-05 19:32:28.000000000 +0200 +@@ -556,19 +556,46 @@ + bound at server startup. May be of the form + C<host:port/proto>, C<host:port>, C<port/proto>, or C<port>, +-where I<host> represents a hostname residing on the local +-box, where I<port> represents either the number of the port +-(eg. "80") or the service designation (eg. "http"), and +-where I<proto> represents the protocol to be used. See +-L<Net::Server::Proto>. If you are working with unix sockets, +-you may also specify C<socket_file|unix> or +-C<socket_file|type|unix> where type is SOCK_DGRAM or +-SOCK_STREAM. If the protocol is not specified, I<proto> will ++where I<host> represents a hostname residing on the local box, ++where I<port> represents either the number of the port (eg. "80") ++or the service designation (eg. "http"), and where I<proto> ++represents the protocol to be used. See L<Net::Server::Proto>. ++ ++An explicit I<host> given in a port specification overrides ++a default binding address (a C<host> setting, see below). ++The I<host> part may be enclosed in square brackets, but when it is ++a numerical IPv6 address it B<must> be enclosed in square brackets ++to avoid ambiguity in parsing a port number, e.g.: "[::1]:80". ++ ++If you are working with unix sockets, you may also specify ++C<socket_file|unix> or C<socket_file|type|unix> where type is SOCK_DGRAM ++or SOCK_STREAM. If the protocol is not specified, I<proto> will + default to the C<proto> specified in the arguments. If C<proto> is not + specified there it will default to "tcp". If I<host> is not + specified, I<host> will default to C<host> specified in the +-arguments. If C<host> is not specified there it will +-default to "*". Default port is 20203. Configuration passed +-to new or run may be either a scalar containing a single port +-number or an arrayref of ports. ++arguments. If C<host> is not specified there it will default to "*". ++Default port is 20203. Configuration passed to new or run may be either ++a scalar containing a single port number or an arrayref of ports. ++ ++On an IPv6-enabled host where a module IO::Socket::INET6 is installed ++the "*" implies two listening sockets, one for each of the protocols ++(PF_INET and PF_INET6) and is equivalent to specifying two ports, bound ++to an 'unspecified' address of each address family ("0.0.0.0" and "::"). ++If listening on an INET6 socket is not desired despite IO::Socket::INET6 ++module being available, please supply the 'unspecifed' INET (IPv4) address ++'0.0.0.0' as a I<host>, either in the C<port> or in the C<host> argument. ++ ++An INET socket can only accept IPv4 connections. An INET6 socket accepts ++IPv6 connections, but may also accept IPv4 connections depending on ++OS and its settings. For example, on FreeBSD systems setting a sysctl ++net.inet6.ip6.v6only to 0 will allow IPv4 connections to an INET6 socket. ++If this is the case, specifying "::" as a binding address instead of a "*" ++might be desired to reduce the number of sockets needed. Note that a ++textual representation of a peer's IPv4 address as connected to an INET6 ++socket will typically be in a form of an IPv4-mapped IPv6 addresses, ++e.g. "::FFFF:127.0.0.1" . ++ ++Restricting binding to a loopback interface on systems where an INET6 ++socket does not accept IPv4 connections requires creating two sockets, ++one bound to address "127.0.0.1" and the other bound to address "::1". + + On systems that support it, a port value of 0 may be used to ask +@@ -583,5 +610,7 @@ + Local host or addr upon which to bind port. If a value of '*' is + given, the server will bind that port on all available addresses +-on the box. See L<Net::Server::Proto>. See L<IO::Socket>. Configuration ++on the box. The C<host> argument provides a default local host ++address if the C<port> argument omits a host specification. ++See L<Net::Server::Proto>. See L<IO::Socket>. Configuration + passed to new or run may be either a scalar containing a single + host or an arrayref of hosts - if the hosts array is shorter than +--- Net-Server-0.99/lib/Net/Server/Proto/SSLEAY.pm.orig 2010-07-09 09:44:48.000000000 -0700 ++++ Net-Server-0.99/lib/Net/Server/Proto/SSLEAY.pm 2011-08-01 11:08:19.183613424 -0700 +@@ -22,156 +22,254 @@ + package Net::Server::Proto::SSLEAY; + + use strict; +-use vars qw($VERSION $AUTOLOAD @ISA); +-use IO::Socket::INET; ++use vars qw($VERSION $AUTOLOAD @ISA $have_inet6); + use Fcntl (); + use Errno (); + use Socket (); ++use IO::Socket; + + BEGIN { +- eval { require Net::SSLeay }; +- $@ && warn "Module Net::SSLeay is required for SSLeay."; +- # Net::SSLeay gets mad if we call these multiple times - the question is - who will call them multiple times? +- for my $sub (qw(load_error_strings SSLeay_add_ssl_algorithms ENGINE_load_builtin_engines ENGINE_register_all_complete randomize)) { +- Net::SSLeay->can($sub)->(); +- } ++ eval { ++ require Socket6; import Socket6; ++ require IO::Socket::INET6; ++ @ISA = qw(IO::Socket::INET6); ++ $have_inet6 = 1; ++ } or do { ++ require IO::Socket::INET; ++ @ISA = qw(IO::Socket::INET); ++ }; ++ eval { require Net::SSLeay }; ++ $@ && warn "Module Net::SSLeay is required for SSLeay."; ++ # Net::SSLeay gets mad if we call these multiple times - the question is - who will call them multiple times? ++ for my $sub (qw(load_error_strings SSLeay_add_ssl_algorithms ENGINE_load_builtin_engines ENGINE_register_all_complete randomize)) { ++ Net::SSLeay->can($sub)->(); ++ } + } + + $VERSION = $Net::Server::VERSION; # done until separated +-@ISA = qw(IO::Socket::INET); ++ ++# additional protocol specific arguments ++my @ssl_args = qw( ++ SSL_use_cert ++ SSL_verify_mode ++ SSL_key_file ++ SSL_cert_file ++ SSL_ca_path ++ SSL_ca_file ++ SSL_cipher_list ++ SSL_passwd_cb ++ SSL_max_getline_length ++ SSL_error_callback ++); + + sub object { +- my $type = shift; +- my $class = ref($type) || $type || __PACKAGE__; ++ my $type = shift; ++ my $class = ref($type) || $type || __PACKAGE__; + +- my ($default_host,$port,$server) = @_; +- my $prop = $server->{'server'}; +- my $host; +- +- if ($port =~ m/^([\w\.\-\*\/]+):(\w+)$/) { # allow for things like "domain.com:80" +- ($host, $port) = ($1, $2); +- } +- elsif ($port =~ /^(\w+)$/) { # allow for things like "80" +- ($host, $port) = ($default_host, $1); +- } +- else { +- $server->fatal("Undeterminate port \"$port\" under ".__PACKAGE__); +- } +- +- # read any additional protocol specific arguments +- my @ssl_args = qw( +- SSL_server +- SSL_use_cert +- SSL_verify_mode +- SSL_key_file +- SSL_cert_file +- SSL_ca_path +- SSL_ca_file +- SSL_cipher_list +- SSL_passwd_cb +- SSL_error_callback +- SSL_max_getline_length +- ); +- my %args; +- $args{$_} = \$prop->{$_} for @ssl_args; +- $server->configure(\%args); +- +- my $sock = $class->new; +- $sock->NS_host($host); +- $sock->NS_port($port); +- $sock->NS_proto('SSLEAY'); ++ my ($default_host,$port,$server) = @_; ++ my $host; ++ my $prop = $server->{'server'}; ++ ++ local($1,$2); ++ ### allow for things like "[::1]:80" or "[host.example.com]:80" ++ if( $port =~ m/^\[([^\]]*)\]:(\w+)$/ ){ ++ ($host,$port) = ($1,$2); ++ ++ ### allow for things like "host.example.com:80" ++ }elsif( $port =~ m/^([\w\.\-\*\/]+):(\w+)$/ ){ ++ ($host,$port) = ($1,$2); ++ ++ ### allow for things like "80" or "http" ++ }elsif( $port =~ /^(\w+)$/ ){ ++ ($host,$port) = ($default_host,$1); ++ ++ ### don't know that style of port ++ }else{ ++ $server->fatal("Undeterminate port \"$port\" under ".__PACKAGE__); ++ } ++ ++ ### collect bind addresses along with their address family for all hosts ++ my @bind_tuples; ++ if( $host =~ /^\d{1,3}(?:\.\d{1,3}){3}\z/ ){ ++ push(@bind_tuples, [AF_INET,$host,$port]); ++ }elsif( $host =~ /:/ ){ ++ die "No IO::Socket::INET6, cannot bind to [$host]:$port" if !$have_inet6; ++ push(@bind_tuples, [AF_INET6,$host,$port]); ++ }elsif( !$have_inet6 ){ ++ push(@bind_tuples, [AF_INET,$host,$port]); ++ }elsif( $have_inet6 && $host =~ /\*/ ){ ++ push(@bind_tuples, [AF_INET6,$host,$port], [AF_INET,$host,$port]); ++ }else{ # we do have IO::Socket::INET6, it handles inet6 as well as inet ++ # obtain a list of IP addresses for $host, resolve port name ++ my @res1 = getaddrinfo($host, $port, AF_UNSPEC, SOCK_STREAM, 0, ++ AI_PASSIVE|AI_ADDRCONFIG); ++ die "Unresolvable [$host]:$port: $res1[0]" if @res1 < 5; ++ while (@res1 >= 5) { ++ my($afam, $socktype, $proto, $saddr, $canonname); ++ ($afam, $socktype, $proto, $saddr, $canonname, @res1) = @res1; ++ my @res2 = getnameinfo($saddr, NI_NUMERICHOST | NI_NUMERICSERV); ++ die "getnameinfo failed on [$host]:$port: $res2[0]" if @res2 < 2; ++ my($hostip,$portnum) = @res2; ++ $server->log(4,"Resolved [$host]:$port -> [$hostip]:$portnum, AF $afam"); ++ push(@bind_tuples, [$afam,$hostip,$portnum]); ++ } ++ } ++ ++ my @sockets_list; ++ ### create a socket for each specified bind address and family ++ foreach my $tuple ( @bind_tuples ){ ++ my $afamily; # address family (AF_* constants) ++ my $pfamily; # socket protocol family (PF_* constants) ++ ($afamily,$host,$port) = @$tuple; ++ my $sock; ++ if( $have_inet6 ){ ++ # Using IO::Socket::INET6 to handle both the IPv4 and IPv6. ++ # Constants PF_INET/PF_INET6 (protocol family) usually happen to have ++ # the same value as AF_INET/AF_INET6 (address family) constants. ++ # Still, better safe than sorry: ++ if ( $afamily == AF_INET ) { ++ $pfamily = PF_INET; ++ } elsif ( $afamily == AF_INET6 ) { ++ $pfamily = PF_INET6; ++ } else { ++ $pfamily = $afamily; ++ } ++ $server->log(3,"Using IO::Socket::INET6 for [$host]:$port, PF $pfamily"); ++ $sock = IO::Socket::INET6->new(Domain => $pfamily); # inet or inet6 ++ }else{ ++ $pfamily = PF_INET; ++ $server->log(3,"Using IO::Socket::INET for [$host]:$port, PF $pfamily"); ++ $sock = IO::Socket::INET->new(); # inet socket (IPv4 only) ++ } ++ ++ if ($sock) { ++ bless $sock, $class; ++ ++ $sock->NS_host($host); ++ $sock->NS_port($port); ++ $sock->NS_proto('SSLEAY'); ++ $sock->NS_family($pfamily); # socket protocol family + +- for my $key (@ssl_args) { ++ for my $key (@ssl_args) { + my $val = defined($prop->{$key}) ? $prop->{$key} : $server->can($key) ? $server->$key($host, $port, 'SSLEAY') : undef; + $sock->$key($val); ++ } ++ push @sockets_list, $sock; + } ++ } + +- return $sock; ++ ### returns any number of sockets, ++ ### one for each protocol family (PF_INET or PF_INET6) and each bind address ++ return !wantarray ? $sockets_list[0] : @sockets_list; + } + + sub log_connect { +- my $sock = shift; +- my $server = shift; +- my $host = $sock->NS_host; +- my $port = $sock->NS_port; +- my $proto = $sock->NS_proto; +- $server->log(2,"Binding to $proto port $port on host $host\n"); ++ my $sock = shift; ++ my $server = shift; ++ my $host = $sock->NS_host; ++ my $port = $sock->NS_port; ++ my $proto = $sock->NS_proto; ++ my $pfamily = $sock->NS_family || 0; ++ $server->log(2,"Binding to $proto port $port on host $host, PF $pfamily\n"); + } + + ###----------------------------------------------------------------### + +-sub connect { # connect the first time +- my $sock = shift; +- my $server = shift; +- my $prop = $server->{'server'}; +- +- my $host = $sock->NS_host; +- my $port = $sock->NS_port; +- +- my %args; +- $args{'LocalPort'} = $port; +- $args{'Proto'} = 'tcp'; +- $args{'LocalAddr'} = $host if $host !~ /\*/; # * is all +- $args{'Listen'} = $prop->{'listen'}; +- $args{'Reuse'} = 1; +- +- $sock->SUPER::configure(\%args) || $server->fatal("Can't connect to SSL port $port on $host [$!]"); +- $server->fatal("Bad sock [$!]!".caller()) if ! $sock; +- +- if ($port == 0 && ($port = $sock->sockport)) { +- $sock->NS_port($port); +- $server->log(2,"Bound to auto-assigned port $port"); +- } +- +- $sock->bind_SSL($server); +-} +- +-sub reconnect { # connect on a sig -HUP +- my ($sock, $fd, $server) = @_; +- my $resp = $sock->fdopen( $fd, 'w' ) || $server->fatal("Error opening to file descriptor ($fd) [$!]"); +- $sock->bind_SSL($server); +- return $resp; ++### bind the first time ++sub connect { ++ my $sock = shift; ++ my $server = shift; ++ my $prop = $server->{server}; ++ ++ my $host = $sock->NS_host; ++ my $port = $sock->NS_port; ++ my $pfamily = $sock->NS_family || 0; ++ ++ my %args; ++ $args{LocalPort} = $port; ++ $args{Proto} = 'tcp'; ++ $args{LocalAddr} = $host if $host !~ /\*/; # * is all ++ $args{Domain} = $pfamily if $have_inet6 && $pfamily; ++ $args{Listen} = $prop->{listen}; ++ $args{Reuse} = 1; ++ ++ $sock->SUPER::configure(\%args) ++ or $server->fatal("Can't bind to SSL port $port on $host [$!]"); ++ $server->fatal("Bad sock [$!]!".caller()) if !$sock; ++ ++ my $actual_port = $sock->sockport; ++ # $port may be a service name, compare as strings ++ if( $actual_port && (!defined $port || $actual_port ne $port) ){ ++ $sock->NS_port($actual_port); ++ if( $port =~ /^0*\z/ ){ ++ $server->log(2,"Bound to auto-assigned port $actual_port"); ++ }else{ ++ $server->log(3,"Bound to service \"$port\", port number $actual_port"); ++ } ++ } ++ ++ $sock->bind_SSL($server); ++} ++ ++### reassociate sockets with inherited file descriptors on a sig -HUP ++sub reconnect { ++ my ($sock, $fd, $server) = @_; ++ ++ my $host = $sock->NS_host; ++ my $port = $sock->NS_port; ++ my $proto = $sock->NS_proto; ++ my $pfamily = $sock->NS_family || 0; ++ ++ $server->log(3,"Reassociating file descriptor $fd ". ++ "with socket $proto on [$host]:port, PF $pfamily\n"); ++ my $resp = $sock->fdopen( $fd, 'w' ) ++ or $server->fatal("Error opening to file descriptor ($fd) [$!]"); ++ $sock->bind_SSL($server); ++ return $resp; + } + + sub bind_SSL { +- my ($sock, $server) = @_; +- my $ctx = Net::SSLeay::CTX_new(); $sock->SSLeay_check_fatal("SSLeay bind_SSL CTX_new"); ++ my ($sock, $server) = @_; ++ my $ctx = Net::SSLeay::CTX_new(); $sock->SSLeay_check_fatal("SSLeay bind_SSL CTX_new"); + +- Net::SSLeay::CTX_set_options($ctx, Net::SSLeay::OP_ALL()); $sock->SSLeay_check_fatal("SSLeay bind_SSL CTX_set_options"); ++ Net::SSLeay::CTX_set_options($ctx, Net::SSLeay::OP_ALL()); $sock->SSLeay_check_fatal("SSLeay bind_SSL CTX_set_options"); + +- # 0x1: SSL_MODE_ENABLE_PARTIAL_WRITE +- # 0x10: SSL_MODE_RELEASE_BUFFERS (ignored before OpenSSL v1.0.0) +- Net::SSLeay::CTX_set_mode($ctx, 0x11); $sock->SSLeay_check_fatal("SSLeay bind_SSL CTX_set_mode"); +- +- # Load certificate. This will prompt for a password if necessary. +- my $file_key = $sock->SSL_key_file || die "SSLeay missing SSL_key_file.\n"; +- my $file_cert = $sock->SSL_cert_file || die "SSLeay missing SSL_cert_file.\n"; +- Net::SSLeay::CTX_use_RSAPrivateKey_file($ctx, $file_key, Net::SSLeay::FILETYPE_PEM()); $sock->SSLeay_check_fatal("SSLeay bind_SSL CTX_use_RSAPrivateKey_file"); +- Net::SSLeay::CTX_use_certificate_file( $ctx, $file_cert, Net::SSLeay::FILETYPE_PEM()); $sock->SSLeay_check_fatal("SSLeay bind_SSL CTX_use_certificate_file"); +- $sock->SSLeay_context($ctx); ++ # 0x1: SSL_MODE_ENABLE_PARTIAL_WRITE ++ # 0x10: SSL_MODE_RELEASE_BUFFERS (ignored before OpenSSL v1.0.0) ++ Net::SSLeay::CTX_set_mode($ctx, 0x11); $sock->SSLeay_check_fatal("SSLeay bind_SSL CTX_set_mode"); ++ ++ # Load certificate. This will prompt for a password if necessary. ++ my $file_key = $sock->SSL_key_file || die "SSLeay missing SSL_key_file.\n"; ++ my $file_cert = $sock->SSL_cert_file || die "SSLeay missing SSL_cert_file.\n"; ++ Net::SSLeay::CTX_use_RSAPrivateKey_file($ctx, $file_key, Net::SSLeay::FILETYPE_PEM()); $sock->SSLeay_check_fatal("SSLeay bind_SSL CTX_use_RSAPrivateKey_file"); ++ Net::SSLeay::CTX_use_certificate_file( $ctx, $file_cert, Net::SSLeay::FILETYPE_PEM()); $sock->SSLeay_check_fatal("SSLeay bind_SSL CTX_use_certificate_file"); ++ $sock->SSLeay_context($ctx); + } + + sub close { +- my $sock = shift; +- if ($sock->SSLeay_is_client) { +- Net::SSLeay::free($sock->SSLeay); +- } else { +- Net::SSLeay::CTX_free($sock->SSLeay_context); +- } +- $sock->SSLeay_check_fatal("SSLeay close free"); +- return $sock->SUPER::close(@_); ++ my $sock = shift; ++ if ($sock->SSLeay_is_client) { ++ Net::SSLeay::free($sock->SSLeay); ++ } else { ++ Net::SSLeay::CTX_free($sock->SSLeay_context); ++ } ++ $sock->SSLeay_check_fatal("SSLeay close free"); ++ return $sock->SUPER::close(@_); + } + + sub accept { +- my $sock = shift; +- my $client = $sock->SUPER::accept; +- if (defined $client) { +- $client->NS_proto($sock->NS_proto); +- $client->SSLeay_context($sock->SSLeay_context); +- $client->SSLeay_is_client(1); +- } ++ my $sock = shift; ++ my $client = $sock->SUPER::accept; ++ if (defined $client) { ++ $client->NS_proto( $sock->NS_proto ); ++ $client->NS_family( $sock->NS_family ); ++ $client->NS_host( $sock->NS_host ); ++ $client->NS_port( $sock->NS_port ); ++ $client->SSLeay_context( $sock->SSLeay_context ); ++ $client->SSLeay_is_client(1); ++ } + +- return $client; ++ return $client; + } + + sub SSLeay { +@@ -280,6 +378,17 @@ + return length $read; + } + ++sub sysread { ++ my ($client, $buf, $size, $offset) = @_; ++ warn "sysread is not supported by Net::Server::Proto::SSLEAY"; ++ # not quite right, usable only for testing: ++ my ($ok, $read) = $client->read_until($size, $/, 1); ++ substr($_[1], $offset || 0, defined($buf) ? length($buf) : 0, $read); ++ # should return the number of bytes actually read, 0 at end of file, or ++ # undef if there was an error (in the latter case $! should also be set) ++ return length $read; ++} ++ + sub getline { + my $client = shift; + my ($ok, $line) = $client->read_until($client->SSL_max_getline_length, $/); +@@ -330,20 +439,24 @@ + $client->print($buf); + } + +-sub sysread { die "sysread is not supported by Net::Server::Proto::SSLEAY" } + sub syswrite { die "syswrite is not supported by Net::Server::Proto::SSLEAY" } + + ###----------------------------------------------------------------### + + sub hup_string { + my $sock = shift; +- return join "|", map{$sock->$_()} qw(NS_host NS_port NS_proto); ++ return join("|", ++ $sock->NS_host, ++ $sock->NS_port, ++ $sock->NS_proto, ++ !$have_inet6 || !$sock->NS_family ? () : $sock->NS_family, ++ ); + } + + sub show { + my $sock = shift; + my $t = "Ref = \"" .ref($sock) . "\"\n"; +- foreach my $prop ( qw(NS_proto NS_port NS_host SSLeay_context SSLeay_is_client) ){ ++ foreach my $prop ( qw(NS_proto NS_port NS_host NS_family SSLeay_context SSLeay_is_client) ){ + $t .= " $prop = \"" .$sock->$prop()."\"\n"; + } + return $t; +@@ -353,7 +466,7 @@ + my $sock = shift; + my $prop = $AUTOLOAD =~ /::([^:]+)$/ ? $1 : die "Missing property in AUTOLOAD."; + die "Unknown method or property [$prop]" +- if $prop !~ /^(NS_proto|NS_port|NS_host|SSLeay_context|SSLeay_is_client|SSL_\w+)$/; ++ if $prop !~ /^(NS_proto|NS_port|NS_host|NS_family|SSLeay_context|SSLeay_is_client|SSL_\w+)$/; + + no strict 'refs'; + *{__PACKAGE__."::${prop}"} = sub { +--- Net-Server-0.99/lib/Net/Server/Proto/SSL.pm.orig 2010-05-04 20:13:03.000000000 -0700 ++++ Net-Server-0.99/lib/Net/Server/Proto/SSL.pm 2011-08-01 11:08:50.503627241 -0700 +@@ -22,14 +22,47 @@ + package Net::Server::Proto::SSL; + + use strict; +-use vars qw($VERSION $AUTOLOAD @ISA); +-use Net::Server::Proto::TCP (); +-eval { require IO::Socket::SSL; }; +-$@ && warn "Module IO::Socket::SSL is required for SSL."; ++use vars qw($VERSION $AUTOLOAD @ISA $have_inet6 $io_socket_module); ++use IO::Socket; ++ ++BEGIN { ++ eval { ++ require Socket6; import Socket6; ++ require IO::Socket::INET6; ++ $io_socket_module = 'IO::Socket::INET6'; ++ $have_inet6 = 1; ++ } or do { ++ require IO::Socket::INET; ++ $io_socket_module = 'IO::Socket::INET'; ++ }; ++ @ISA = ( $io_socket_module ); ++} ++ ++eval { ++ require IO::Socket::SSL; import IO::Socket::SSL; ++ # we could add IO::Socket::SSL to a local copy of @ISA just before calling ++ # start_SSL and do away with the $io_socket_module trick later, but this ++ # causes perl 5.12.2 to crash, so do it the way it likes it ++ unshift(@ISA, qw(IO::Socket::SSL)); 1; ++} or do { ++ warn "Module IO::Socket::SSL is required for SSL: $@"; ++}; + + $VERSION = $Net::Server::VERSION; # done until separated +-@ISA = qw(IO::Socket::SSL); + ++# additional protocol specific arguments ++my @ssl_args = qw( ++ SSL_use_cert ++ SSL_verify_mode ++ SSL_key_file ++ SSL_cert_file ++ SSL_ca_path ++ SSL_ca_file ++ SSL_cipher_list ++ SSL_passwd_cb ++ SSL_max_getline_length ++ SSL_error_callback ++); + + sub object { + my $type = shift; +@@ -39,11 +72,16 @@ + my $prop = $server->{server}; + my $host; + +- ### allow for things like "domain.com:80" +- if( $port =~ m/^([\w\.\-\*\/]+):(\w+)$/ ){ ++ local($1,$2); ++ ### allow for things like "[::1]:80" or "[host.example.com]:80" ++ if( $port =~ m/^\[([^\]]*)\]:(\w+)$/ ){ + ($host,$port) = ($1,$2); + +- ### allow for things like "80" ++ ### allow for things like "host.example.com:80" ++ }elsif( $port =~ m/^([\w\.\-\*\/]+):(\w+)$/ ){ ++ ($host,$port) = ($1,$2); ++ ++ ### allow for things like "80" or "http" + }elsif( $port =~ /^(\w+)$/ ){ + ($host,$port) = ($default_host,$1); + +@@ -52,98 +90,167 @@ + $server->fatal("Undeterminate port \"$port\" under ".__PACKAGE__); + } + +- # read any additional protocol specific arguments +- my @ssl_args = qw( +- SSL_server +- SSL_use_cert +- SSL_verify_mode +- SSL_key_file +- SSL_cert_file +- SSL_ca_path +- SSL_ca_file +- SSL_cipher_list +- SSL_passwd_cb +- SSL_max_getline_length +- ); +- my %args; +- $args{$_} = \$prop->{$_} for @ssl_args; +- $server->configure(\%args); +- +- my $sock = $class->new; +- $sock->NS_host($host); +- $sock->NS_port($port); +- $sock->NS_proto('SSL'); ++ ### collect bind addresses along with their address family for all hosts ++ my @bind_tuples; ++ if( $host =~ /^\d{1,3}(?:\.\d{1,3}){3}\z/ ){ ++ push(@bind_tuples, [AF_INET,$host,$port]); ++ }elsif( $host =~ /:/ ){ ++ die "No IO::Socket::INET6, cannot bind to [$host]:$port" if !$have_inet6; ++ push(@bind_tuples, [AF_INET6,$host,$port]); ++ }elsif( !$have_inet6 ){ ++ push(@bind_tuples, [AF_INET,$host,$port]); ++ }elsif( $have_inet6 && $host =~ /\*/ ){ ++ push(@bind_tuples, [AF_INET6,$host,$port], [AF_INET,$host,$port]); ++ }else{ # we do have IO::Socket::INET6, it handles inet6 as well as inet ++ # obtain a list of IP addresses for $host, resolve port name ++ my @res1 = getaddrinfo($host, $port, AF_UNSPEC, SOCK_STREAM, 0, ++ AI_PASSIVE|AI_ADDRCONFIG); ++ die "Unresolvable [$host]:$port: $res1[0]" if @res1 < 5; ++ while (@res1 >= 5) { ++ my($afam, $socktype, $proto, $saddr, $canonname); ++ ($afam, $socktype, $proto, $saddr, $canonname, @res1) = @res1; ++ my @res2 = getnameinfo($saddr, NI_NUMERICHOST | NI_NUMERICSERV); ++ die "getnameinfo failed on [$host]:$port: $res2[0]" if @res2 < 2; ++ my($hostip,$portnum) = @res2; ++ $server->log(4,"Resolved [$host]:$port -> [$hostip]:$portnum, AF $afam"); ++ push(@bind_tuples, [$afam,$hostip,$portnum]); ++ } ++ } + +- for my $key (@ssl_args) { +- my $val = defined($prop->{$key}) ? $prop->{$key} : $server->can($key) ? $server->$key($host, $port, 'SSL') : undef; +- $sock->$key($val); ++ my @sockets_list; ++ ### create a socket for each specified bind address and family ++ foreach my $tuple ( @bind_tuples ){ ++ my $afamily; # address family (AF_* constants) ++ my $pfamily; # socket protocol family (PF_* constants) ++ ($afamily,$host,$port) = @$tuple; ++ my $sock; ++ if( $have_inet6 ){ ++ # Using IO::Socket::INET6 to handle both the IPv4 and IPv6. ++ # Constants PF_INET/PF_INET6 (protocol family) usually happen to have ++ # the same value as AF_INET/AF_INET6 (address family) constants. ++ # Still, better safe than sorry: ++ if ( $afamily == AF_INET ) { ++ $pfamily = PF_INET; ++ } elsif ( $afamily == AF_INET6 ) { ++ $pfamily = PF_INET6; ++ } else { ++ $pfamily = $afamily; ++ } ++ $server->log(3,"Using IO::Socket::INET6 for [$host]:$port, PF $pfamily"); ++ $sock = IO::Socket::INET6->new(Domain => $pfamily); # inet or inet6 ++ }else{ ++ $pfamily = PF_INET; ++ $server->log(3,"Using IO::Socket::INET for [$host]:$port, PF $pfamily"); ++ $sock = IO::Socket::INET->new(); # inet socket (IPv4 only) ++ } ++ ++ if ($sock) { ++ ### create the handle under this package ++ bless $sock, $class; ++ ++ $sock->NS_host($host); ++ $sock->NS_port($port); ++ $sock->NS_proto('SSL'); ++ $sock->NS_family($pfamily); # socket protocol family ++ ++ for my $key (@ssl_args) { ++ my $val = defined($prop->{$key}) ? $prop->{$key} : $server->can($key) ? $server->$key($host, $port, 'SSL') : undef; ++ $sock->$key($val); ++ } ++ push @sockets_list, $sock; ++ } + } + +- return $sock; ++ ### returns any number of sockets, ++ ### one for each protocol family (PF_INET or PF_INET6) and each bind address ++ return !wantarray ? $sockets_list[0] : @sockets_list; + } + + sub log_connect { + my $sock = shift; +- my $server = shift; +- my $host = $sock->NS_host; +- my $port = $sock->NS_port; +- my $proto = $sock->NS_proto; +- $server->log(2,"Binding to $proto port $port on host $host\n"); ++ my $server = shift; ++ my $host = $sock->NS_host; ++ my $port = $sock->NS_port; ++ my $proto = $sock->NS_proto; ++ my $pfamily = $sock->NS_family || 0; ++ $server->log(2,"Binding to $proto port $port on host $host, PF $pfamily\n"); + } + +-### connect the first time ++### bind the first time + sub connect { +- my $sock = shift; +- my $server = shift; +- my $prop = $server->{server}; +- +- my $host = $sock->NS_host; +- my $port = $sock->NS_port; +- +- my %args = (); +- $args{LocalPort} = $port; # what port to bind on +- $args{Proto} = 'tcp'; # what procol to use +- $args{LocalAddr} = $host if $host !~ /\*/; # what local address (* is all) +- $args{Listen} = $prop->{listen}; # how many connections for kernel to queue +- $args{Reuse} = 1; # allow us to rebind the port on a restart +- +- ### add in any ssl specific properties +- foreach ( keys %$prop ){ +- next unless /^SSL_/; +- $args{$_} = $prop->{$_}; +- } +- +- ### connect to the sock +- $sock->SUPER::configure(\%args) +- or $server->fatal("Can't connect to SSL port $port on $host [$!]"); +- +- $server->fatal("Back sock [$!]!".caller()) +- unless $sock; ++ my $sock = shift; ++ my $server = shift; ++ my $prop = $server->{server}; ++ ++ my $host = $sock->NS_host; ++ my $port = $sock->NS_port; ++ my $pfamily = $sock->NS_family || 0; + ++ my %args; ++ $args{LocalPort} = $port; ++ $args{Proto} = 'tcp'; ++ $args{LocalAddr} = $host if $host !~ /\*/; # * is all ++ $args{Domain} = $pfamily if $have_inet6 && $pfamily; ++ $args{Listen} = $prop->{listen}; ++ $args{Reuse} = 1; ++ ++ ### bind to the sock using the underlying IO Socket module ++ { local @ISA = ( $io_socket_module ); ++ $sock->SUPER::configure(\%args) ++ or $server->fatal("Can't bind to SSL port $port on $host [$!]"); ++ $server->fatal("Bad sock [$!]!".caller()) if !$sock; ++ } + } + + ### connect on a sig -HUP + sub reconnect { +- my $sock = shift; +- my $fd = shift; +- my $server = shift; +- +- $sock->fdopen( $fd, 'w' ) +- or $server->fatal("Error opening to file descriptor ($fd) [$!]"); ++ my ($sock, $fd, $server) = @_; + ++ my $host = $sock->NS_host; ++ my $port = $sock->NS_port; ++ my $proto = $sock->NS_proto; ++ my $pfamily = $sock->NS_family || 0; ++ ++ $server->log(3,"Reassociating file descriptor $fd ". ++ "with socket $proto on [$host]:port, PF $pfamily\n"); ++ ++ ### fdopen cannot be used on a IO::Socket::SSL object!!! ++ ### use fdopen() from the underlying IO Socket package ++ { local @ISA = ( $io_socket_module ); ++ $sock->fdopen( $fd, 'w' ) ++ or $server->fatal("Error opening to file descriptor ($fd) [$!]"); ++ } + } + + ### allow for endowing the child + sub accept { + my $sock = shift; +- my $client = $sock->SUPER::accept(); ++ my $client; + +- ### pass items on +- if( defined($client) ){ +- bless $client, ref($sock); +- $client->NS_proto( $sock->NS_proto ); ++ ### fdopen (in reconnect) cannot be used on an IO::Socket::SSL object, ++ ### which is why we accept first and upgrade to SSL later ++ ++ ### accept() with the underlying IO Socket package, upgrade to SSL later ++ { local @ISA = ( $io_socket_module ); ++ $client = $sock->SUPER::accept(); + } + ++ if( defined $client ){ ++ $client->NS_proto( $sock->NS_proto ); ++ $client->NS_family( $sock->NS_family ); ++ $client->NS_host( $sock->NS_host ); ++ $client->NS_port( $sock->NS_port ); ++ ++ ### must bless the upgraded SSL object into our package ++ ### to be able to reference its NS_* properties later ++ __PACKAGE__->start_SSL($client, ++ SSL_error_trap => sub { my($sock,$msg) = @_; ++ die "Error upgrading socket to SSL: $msg" }, ++ SSL_server => 1, ++ map { defined $sock->$_() ? ($_,$sock->$_()) : () } @ssl_args, ++ ) or die "Upgrading socket to SSL failed: ".IO::Socket::SSL::errstr(); ++ ++ } + return $client; + } + +@@ -157,6 +264,7 @@ + $sock->NS_host, + $sock->NS_port, + $sock->NS_proto, ++ !$have_inet6 || !$sock->NS_family ? () : $sock->NS_family, + ); + } + +@@ -164,7 +272,7 @@ + sub show { + my $sock = shift; + my $t = "Ref = \"" .ref($sock) . "\"\n"; +- foreach my $prop ( qw(NS_proto NS_port NS_host) ){ ++ foreach my $prop ( qw(NS_proto NS_port NS_host NS_family) ){ + $t .= " $prop = \"" .$sock->$prop()."\"\n"; + } + return $t; +@@ -179,7 +287,7 @@ + die "No property called."; + } + +- if( $prop =~ /^(NS_proto|NS_port|NS_host)$/ ){ ++ if( $prop =~ /^(NS_proto|NS_port|NS_host|NS_family|SSL_\w+)$/ ){ + no strict 'refs'; + * { __PACKAGE__ ."::". $prop } = sub { + my $sock = shift; +@@ -215,8 +323,8 @@ + =head1 DESCRIPTION + + This original SSL module was experimental. It has been superceeded by +-Net::Server::Proto::SSLEAY If anybody has any successes or ideas for +-improvment under SSL, please email <paul@seamons.com>. ++Net::Server::Proto::SSLEAY. If anybody has any successes or ideas for ++improvement under SSL, please email <paul@seamons.com>. + + Protocol module for Net::Server. This module implements a + secure socket layer over tcp (also known as SSL). +--- Net-Server-0.99/lib/Net/Server/Proto/TCP.pm.orig 2011-08-01 10:24:36.463625993 -0700 ++++ Net-Server-0.99/lib/Net/Server/Proto/TCP.pm 2011-08-01 11:08:27.283623011 -0700 +@@ -22,11 +22,22 @@ + package Net::Server::Proto::TCP; + + use strict; +-use vars qw($VERSION $AUTOLOAD @ISA); +-use IO::Socket (); ++use vars qw($VERSION $AUTOLOAD @ISA $have_inet6); ++use IO::Socket; ++ ++BEGIN { ++ eval { ++ require Socket6; import Socket6; ++ require IO::Socket::INET6; ++ @ISA = qw(IO::Socket::INET6); ++ $have_inet6 = 1; ++ } or do { ++ require IO::Socket::INET; ++ @ISA = qw(IO::Socket::INET); ++ }; ++} + + $VERSION = $Net::Server::VERSION; # done until separated +-@ISA = qw(IO::Socket::INET); + + sub object { + my $type = shift; +@@ -35,11 +46,16 @@ + my ($default_host,$port,$server) = @_; + my $host; + +- ### allow for things like "domain.com:80" +- if( $port =~ m/^([\w\.\-\*\/]+):(\w+)$/ ){ ++ local($1,$2); ++ ### allow for things like "[::1]:80" or "[host.example.com]:80" ++ if( $port =~ m/^\[([^\]]*)\]:(\w+)$/ ){ + ($host,$port) = ($1,$2); + +- ### allow for things like "80" ++ ### allow for things like "host.example.com:80" ++ }elsif( $port =~ m/^([\w\.\-\*\/]+):(\w+)$/ ){ ++ ($host,$port) = ($1,$2); ++ ++ ### allow for things like "80" or "http" + }elsif( $port =~ /^(\w+)$/ ){ + ($host,$port) = ($default_host,$1); + +@@ -48,65 +64,137 @@ + $server->fatal("Undeterminate port \"$port\" under ".__PACKAGE__); + } + +- ### create the handle under this package +- my $sock = $class->SUPER::new(); ++ ### collect bind addresses along with their address family for all hosts ++ my @bind_tuples; ++ if( $host =~ /^\d{1,3}(?:\.\d{1,3}){3}\z/ ){ ++ push(@bind_tuples, [AF_INET,$host,$port]); ++ }elsif( $host =~ /:/ ){ ++ die "No IO::Socket::INET6, cannot bind to [$host]:$port" if !$have_inet6; ++ push(@bind_tuples, [AF_INET6,$host,$port]); ++ }elsif( !$have_inet6 ){ ++ push(@bind_tuples, [AF_INET,$host,$port]); ++ }elsif( $have_inet6 && $host =~ /\*/ ){ ++ push(@bind_tuples, [AF_INET6,$host,$port], [AF_INET,$host,$port]); ++ }else{ # we do have IO::Socket::INET6, it handles inet6 as well as inet ++ # obtain a list of IP addresses for $host, resolve port name ++ my @res1 = getaddrinfo($host, $port, AF_UNSPEC, SOCK_STREAM, 0, ++ AI_PASSIVE|AI_ADDRCONFIG); ++ die "Unresolvable [$host]:$port: $res1[0]" if @res1 < 5; ++ while (@res1 >= 5) { ++ my($afam, $socktype, $proto, $saddr, $canonname); ++ ($afam, $socktype, $proto, $saddr, $canonname, @res1) = @res1; ++ my @res2 = getnameinfo($saddr, NI_NUMERICHOST | NI_NUMERICSERV); ++ die "getnameinfo failed on [$host]:$port: $res2[0]" if @res2 < 2; ++ my($hostip,$portnum) = @res2; ++ $server->log(4,"Resolved [$host]:$port -> [$hostip]:$portnum, AF $afam"); ++ push(@bind_tuples, [$afam,$hostip,$portnum]); ++ } ++ } + +- ### store some properties +- $sock->NS_host($host); +- $sock->NS_port($port); +- $sock->NS_proto('TCP'); ++ my @sockets_list; ++ ### create a socket for each specified bind address and family ++ foreach my $tuple ( @bind_tuples ){ ++ my $afamily; # address family (AF_* constants) ++ my $pfamily; # socket protocol family (PF_* constants) ++ ($afamily,$host,$port) = @$tuple; ++ my $sock; ++ if( $have_inet6 ){ ++ # Using IO::Socket::INET6 to handle both the IPv4 and IPv6. ++ # Constants PF_INET/PF_INET6 (protocol family) usually happen to have ++ # the same value as AF_INET/AF_INET6 (address family) constants. ++ # Still, better safe than sorry: ++ if ( $afamily == AF_INET ) { ++ $pfamily = PF_INET; ++ } elsif ( $afamily == AF_INET6 ) { ++ $pfamily = PF_INET6; ++ } else { ++ $pfamily = $afamily; ++ } ++ $server->log(3,"Using IO::Socket::INET6 for [$host]:$port, PF $pfamily"); ++ $sock = IO::Socket::INET6->new(Domain => $pfamily); # inet or inet6 ++ }else{ ++ $pfamily = PF_INET; ++ $server->log(3,"Using IO::Socket::INET for [$host]:$port, PF $pfamily"); ++ $sock = IO::Socket::INET->new(); # inet socket (IPv4 only) ++ } + +- return $sock; ++ if ($sock) { ++ ### create the handle under this package ++ bless $sock, $class; ++ ++ ### store some properties ++ $sock->NS_host($host); ++ $sock->NS_port($port); ++ $sock->NS_proto('TCP'); ++ $sock->NS_family($pfamily); # socket protocol family ++ push @sockets_list, $sock; ++ } ++ } ++ ++ ### returns any number of sockets, ++ ### one for each protocol family (PF_INET or PF_INET6) and each bind address ++ return !wantarray ? $sockets_list[0] : @sockets_list; + } + + sub log_connect { + my $sock = shift; +- my $server = shift; +- my $host = $sock->NS_host; +- my $port = $sock->NS_port; +- my $proto = $sock->NS_proto; +- $server->log(2,"Binding to $proto port $port on host $host\n"); ++ my $server = shift; ++ my $host = $sock->NS_host; ++ my $port = $sock->NS_port; ++ my $proto = $sock->NS_proto; ++ my $pfamily = $sock->NS_family || 0; ++ $server->log(2,"Binding to $proto port $port on host $host, PF $pfamily\n"); + } + +-### connect the first time ++### bind the first time + sub connect { +- my $sock = shift; +- my $server = shift; +- my $prop = $server->{server}; ++ my $sock = shift; ++ my $server = shift; ++ my $prop = $server->{server}; ++ ++ my $host = $sock->NS_host; ++ my $port = $sock->NS_port; ++ my $pfamily = $sock->NS_family || 0; + +- my $host = $sock->NS_host; +- my $port = $sock->NS_port; +- +- my %args = (); ++ my %args; + $args{LocalPort} = $port; # what port to bind on + $args{Proto} = 'tcp'; # what procol to use + $args{LocalAddr} = $host if $host !~ /\*/; # what local address (* is all) ++ $args{Domain} = $pfamily if $have_inet6 && $pfamily; + $args{Listen} = $prop->{listen}; # how many connections for kernel to queue + $args{Reuse} = 1; # allow us to rebind the port on a restart + +- ### connect to the sock ++ ### bind the sock + $sock->SUPER::configure(\%args) +- or $server->fatal("Can't connect to TCP port $port on $host [$!]"); ++ or $server->fatal("Can't bind to TCP port $port on $host [$!]"); ++ $server->fatal("Bad sock [$!]!".caller()) if !$sock; + +- if ($port == 0 && ($port = $sock->sockport)) { +- $sock->NS_port($port); +- $server->log(2,"Bound to auto-assigned port $port"); ++ my $actual_port = $sock->sockport; ++ # $port may be a service name, compare as strings ++ if( $actual_port && (!defined $port || $actual_port ne $port) ){ ++ $sock->NS_port($actual_port); ++ if( $port =~ /^0*\z/ ){ ++ $server->log(2,"Bound to auto-assigned port $actual_port"); ++ }else{ ++ $server->log(3,"Bound to service \"$port\", port number $actual_port"); ++ } + } + +- $server->fatal("Back sock [$!]!".caller()) +- unless $sock; +- + } + +-### connect on a sig -HUP ++### reassociate sockets with inherited file descriptors on a sig -HUP + sub reconnect { +- my $sock = shift; +- my $fd = shift; +- my $server = shift; ++ my ($sock, $fd, $server) = @_; + ++ my $host = $sock->NS_host; ++ my $port = $sock->NS_port; ++ my $proto = $sock->NS_proto; ++ my $pfamily = $sock->NS_family || 0; ++ ++ $server->log(3,"Reassociating file descriptor $fd ". ++ "with socket $proto on [$host]:port, PF $pfamily\n"); + $sock->fdopen( $fd, 'w' ) + or $server->fatal("Error opening to file descriptor ($fd) [$!]"); +- + } + + ### allow for endowing the child +@@ -115,8 +203,11 @@ + my $client = $sock->SUPER::accept(); + + ### pass items on +- if( defined($client) ){ ++ if( defined $client ){ + $client->NS_proto( $sock->NS_proto ); ++ $client->NS_family( $sock->NS_family ); ++ $client->NS_host( $sock->NS_host ); ++ $client->NS_port( $sock->NS_port ); + } + + return $client; +@@ -156,6 +247,7 @@ + $sock->NS_host, + $sock->NS_port, + $sock->NS_proto, ++ !$have_inet6 || !$sock->NS_family ? () : $sock->NS_family, + ); + } + +@@ -163,7 +255,7 @@ + sub show { + my $sock = shift; + my $t = "Ref = \"" .ref($sock) . "\"\n"; +- foreach my $prop ( qw(NS_proto NS_port NS_host) ){ ++ foreach my $prop ( qw(NS_proto NS_port NS_host NS_family) ){ + $t .= " $prop = \"" .$sock->$prop()."\"\n"; + } + return $t; +@@ -178,7 +270,7 @@ + die "No property called."; + } + +- if( $prop =~ /^(NS_proto|NS_port|NS_host|NS_recv_len|NS_recv_flags)$/ ){ ++ if( $prop =~ /^(NS_proto|NS_port|NS_host|NS_family|NS_recv_len|NS_recv_flags)$/ ){ + no strict 'refs'; + * { __PACKAGE__ ."::". $prop } = sub { + my $sock = shift; |