#!/usr/bin/perl use strict; use IO::Socket qw( getaddrinfo getnameinfo IN6ADDR_ANY SOCK_STREAM AI_PASSIVE NI_NUMERICHOST NI_NUMERICSERV SO_REUSEADDR SOMAXCONN ); use Carp; use IO::Select; my $myself = "$0 "; sub logmsg { print "$myself $$: @_ at ", scalar localtime, "\n" } my $host = shift || IN6ADDR_ANY; my $port = shift || 2345; my $proto = getprotobyname('tcp'); my $select = &acceptSelector($host,$port); logmsg "server started on port $port"; my %address_list; while(my @ready = $select->can_read()) { for my $socket ( @ready ) { my $paddr = accept(my $client, $socket); next if (! $paddr) ; my ($err,$addr,$port) = getnameinfo($paddr,NI_NUMERICHOST|NI_NUMERICSERV); my ($err,$name,$m) = getnameinfo($paddr,NI_NUMERICSERV); $address_list{$addr} = $name; my $user = <$client>; $user=~ s/[\r\n]//g; logmsg "connection from $user \@ $name [", $addr, "] at port $port"; print $client "Hello there, $name, it's now ", scalar localtime, "\n"; foreach my $k (keys %address_list) { print $client "\t$k = $address_list{$k}\n"; } close($client); } } sub acceptSelector { my ($host0,$port0) = @_; my $select = IO::Select->new(); my ($err,@res) = getaddrinfo($host0, $port0,{socktype=>SOCK_STREAM, flags=>AI_PASSIVE}); my @socket; my (@host); for my $res (@res) { my ($host, $port) = getnameinfo($res->{addr},NI_NUMERICHOST | NI_NUMERICSERV); print STDERR "Trying to bind to $host : $port... "; my $fd = new IO::Socket; $fd->socket($res->{family}, $res->{socktype}, $res->{protocol}) || next; $fd->sockopt(SO_REUSEADDR, 1) || die "setsockopt : $!"; if ($fd->bind($res->{addr})) { # sockaddr_in($port, INADDR_ANY) $fd->listen(SOMAXCONN) || die "listen: $! "; $select->add($fd); print STDERR "connected.\n"; } else { print STDERR "failed.\n"; $fd->close; } } if ($select->count == 0) { die "connect attempt failed\n"; } return $select; }