#/usr/local/bin/perl -s

$pat = 'S n C4 x8';
$inet = 2;
$echo = 7;
$smtp = 25;
$nntp = 119;

die "Usage:  $0 port \n" unless @ARGV;
$this = pack($pat,$inet,$ARGV[0], 0,0,0,0);
#$this = pack($pat,$inet,2345, 0,0,0,0);

socket(LISTENER,2,1,6) || die "Socket $!\n";
bind(LISTENER,$this) || die "Bind $!\n";
listen(LISTENER,5) || die "Listen $!\n";

$readbits = $writebits = 8 x "\0";
# always read from standard input
vec($readbits,0,1) = 1;

# and look for new connections
#
vec($readbits,fileno(LISTENER),1) = 1;

$listener = fileno(LISTENER);

$0 = $0;
#
# prototype file name
#
$sockp = 'clientaa';
while (1)
{
    $rbits = $readbits;
    $wbits = $writebits;
    grep(vec($wbits,$_,1) = 1, keys %bcastpending);
    ($nfound, $timeleft) = select($rbits, $wbits, undef, undef);
    if ($nfound > 0)
    {
	#
	# we got a hit of some sort
	# first see if anything to write
	if ($wbits =~ /[^\0]/)
	{
	    $bstr = unpack('b*',$wbits);
	    for($fd = index($bstr,'1'); $fd >= 0; $fd = index($bstr,'1',$fd+1))
	    {
		# we just ignore errors here
		#
		$sock = $filenames[$fd];
		send($sock,$bcastdata,0);
		delete $bcastpending{$fd};
	    }
	}
	if ($rbits =~ /[^\0]/)
	{
	    $bstr = unpack('b*',$rbits);
	    for($fd = index($bstr,'1'); $fd >= 0; $fd = index($bstr,'1',$fd+1))
	    {
		if ($fd == 0)
		{
		    # deal with stdin
		    $incount = sysread(STDIN,$bcastdata,1024);
		    if ($incount == 0)
		    {
			# lost our connection
			die "EOF from source\n";
		    }
		    elsif ($incount < 0)
		    {
			# error
			die "Error from source($!)\n" if ($! !~ /Interrupted/);
		    }
		    grep($bcastpending{$_} = 1, keys %active);
		}
		elsif ($fd == $listener)
		{
		    # deal with cloning new socket
		    $newsock = $sockp++;
		    if ($addr = accept($newsock,LISTENER))
		    {
			#
			# see if we like this host
			#
			($fam,$port,$inetaddr) = unpack('SSL',$addr);
			if ($verbose)
			{
			    $hostname = gethostbyaddr($addr, 2);
			    printf "Connection from $hostname %x %d\n", $inetaddr, $port;
			}
			# change inet address to match your site
			if ($inetaddr != 0x7f000001 && $inetaddr & 0xffff0000 != 0x83920000)
			{
			    #
			    # not a host we like, bounce it.
			    #
			    close ($newsock);
			    if ($verbose)
			    {
				$hostname = gethostbyaddr($addr, 2);
				printf "Connection refused from $hostname %x %d\n", $inetaddr, $port;
			    }
			}

			#
			# set bit vectors for later use
			#
			vec($readbits,fileno($newsock),1) = 1;
			$bcastpending{fileno($newsock)} = 1 if length $bcastdata;
			$active{fileno($newsock)} = 1;
			$filenames[fileno($newsock)] = $newsock;
		    }
		    else
		    {
			die "Error on accept $!\n";
		    }
		}
		else
		{
		    # read data from socket and toss, check for eof
		    $sock = $filenames[$fd];
		    $incount = read($sock,$waste,1024);
		    if ($incount == 0)
		    {
			# lost our connection
			#
			# reset bit vectors
			#
			vec($readbits,$fd,1) = 0;
			$filenames[$fd] = '';
			delete $bcastpending{$fd};
			delete $active{$fd};
		    }
		    elsif ($incount < 0)
		    {
			# error
			die "Error from socket($!)\n" if ($! !~ /Interrupted/);
		    }
		}
	    }
	}
    }
    elsif ($nfound < 0)
    {
	die "Error ($!) on select\n" unless $! =~ /Interrupted/;
    }
}
exit 0;
