#!/usr/bin/perl

use IO::Socket::INET;
use IO::Select;
use strict;

unless (-e $ARGV[0]) {
	print "\nUsage: $0 <ip file>\n\n";
	exit();
}

my $debug = 0;
my $timeout = 30;
my $hardout = 90;

our $proxy_check_url = 'http://www.google.co.jp/';
our $proxy_check_text = '<title>Google</title>';

my $sock_select = IO::Select->new();
my $file_select = IO::Select->new();

open(my $in, $ARGV[0]);
$file_select->add($in);

my %socks;
my %hosts;

sub process_reply {
	my $host = $_[0];
	my $data = $hosts{$host}{'data'};
	delete($hosts{$host});

	if ($debug) { print "process_reply: $host\n"; }

	if ($data =~ /$proxy_check_text/) {
		open(my $out, '>>good.txt');
		print $out "$host\n";
		close($out);

		print "$host\n";
	}
}

while (1) {
	foreach my $fh ($sock_select->can_write(0)) {
		my $host = $socks{$fh};

		unless ($hosts{$host}{'sent'} == 1) {
			if ($debug) { print "sending request to $host\n"; }
			print $fh "GET ".$proxy_check_url." HTTP/1.0\r\n\r\n";
			$hosts{$host}{'sent'} = 1;
			$hosts{$host}{'time'} = time();
		}
	}

	foreach my $fh ($sock_select->can_read(0.1)) {
		my $host = $socks{$fh};

		unless ($host) {
			if ($debug) { print "can_read: got a socket, but can't find an entry in \%socks (".$fh->peeraddr().":".$fh->peerport().")\n"; }
			$sock_select->remove($fh);
			close($fh);
			next;
		}

		unless ($fh->connected) {
			if ($debug) { print "can_read: got a dead socket (".$socks{$fh}.")\n"; }
			$sock_select->remove($fh);
			close($fh);
			next;
		}

		if ($debug) { print "can_read: $host is readable\n"; }

		my $buf = '';

		if (read($fh, $buf, 1024)) {
			if ($debug > 1) { print "read: $host: $buf\n"; } elsif ($debug) { print "read: $host\n"; }
			$hosts{$host}{'data'} .= $buf;
			$hosts{$host}{'time'} = time();
		} else {
			$sock_select->remove($fh);
			delete($socks{$fh});
			close($fh);

			process_reply($host);
		}
	}

	foreach my $fh (keys %socks) {
		my $host = $socks{$fh};

		if (($hosts{$host}{'time'} + $timeout) < time()) {
			if ($debug) { print "timeout (read): $host\n"; }
			$sock_select->remove($fh);
			delete($socks{$fh});
			delete($hosts{$host});
		}

		if (($hosts{$host}{'start'} + $hardout) < time()) {
			if ($debug) { print "timeout (hard): $host\n"; }
			$sock_select->remove($fh);
			delete($socks{$fh});
			delete($hosts{$host});
		}
	}

	while ((scalar(keys %socks) < 250) && ($file_select->can_read(0)) && (my $line = <$in>)) {
		chomp($line);
		my ($host, $port) = split(/:/, $line, 2);
		my $sock;
		if ($debug) { print "Opening connection to $host:$port\n"; }
		if ($sock = IO::Socket::INET->new(PeerAddr => $host, PeerPort => $port, Blocking => 0)) {
			$sock_select->add($sock);
			$socks{$sock} = "$host:$port";
			$hosts{"$host:$port"}{'data'} = '';
			$hosts{"$host:$port"}{'sent'} = 0;
			$hosts{"$host:$port"}{'time'} = time();
			$hosts{"$host:$port"}{'start'} = time();
		}
	}

	if (scalar(keys %socks) < 1) { exit(); }
}

