#!/usr/bin/perl -Tw
use strict;
use Socket;
use Carp;
use IO::Handle;
my $EOL = "\015\012";

sub logmsg { print "$0 $$: @_ at ", scalar localtime, "\n" }

my $port = shift || 2345;
my $proto = getprotobyname('tcp');

($port) = $port =~ /^(\d+)$/                        or die "invalid port";

socket(Server, PF_INET, SOCK_STREAM, $proto)        || die "socket: $!";
setsockopt(Server, SOL_SOCKET, SO_REUSEADDR, pack("l", 1))   || die "setsockopt: $!";
bind(Server, sockaddr_in($port, INADDR_ANY))        || die "bind: $!";
listen(Server,SOMAXCONN)                            || die "listen: $!";

logmsg "server started on port $port";

my $paddr;

$SIG{CHLD} = \&REAPER;

my $scans = 0;
my $errors = 0;
# our scan type .. 0 = correct EAN, 1 = invalid scan
my $type = 0;

for ( ; $paddr = accept(Client,Server); close Client) {
    my($port,$iaddr) = sockaddr_in($paddr);
    my $name = gethostbyaddr($iaddr,AF_INET);

    logmsg "connection from $name [", inet_ntoa($iaddr), "] at port $port";

    Client->autoflush(1);
    print Client "220 AGSP emulscan 1.0", $EOL;
    while (<Client>) {
        # remove line ending
        $_ =~ s/\r*\n*$//;
        if (/^SCAN$/i) {
            if ($type == 0) {
                print Client "250 scanned 9783468731228", $EOL;
                $scans++;
            } else {
                print Client "250 scanned 46572657492", $EOL;
                $scans++;
            }
            $_ = <Client>;
            # remove line ending
            $_ =~ s/\r*\n*$//;
            if (/^ACCEPTED$/i) {
                if ($type == 1) {
                    $errors++;
                    logmsg "invalid scan was accepted by client. $scans scans, $errors errors";
                }
                print Client "211 OK", $EOL;
            } elsif (/^REJECTED\s*(.*)$/i) {
                if ($type == 0) {
                    $errors++;
                    logmsg "valid scan was rejected by client, reason '$1'. $scans scans, $errors errors";
                }
                print Client "211 OK", $EOL;
            } elsif (/^QUIT$/i) {
                print Client "503 protocol sync error, bye", $EOL;
                $errors++;
                logmsg "client quit without answering scan. $scans scans, $errors errors";
                close(Client);
            } else {
                print Client "503 protocol sync error", $EOL;
                $errors++;
                logmsg "client didn't answer scan but sent '$_'. $scans scans, $errors errors";
            }
            # flip type
            if ($type == 0) {$type = 1;} else {$type = 0};
        } elsif (/^QUIT$/i) {
            print Client "221 bye", $EOL;
            logmsg "client quit. $scans scans, $errors errors";
            close(Client);
        } else {
            print Client "502 not implemented", $EOL;
            $errors++;
            logmsg "client sent unimplemented '$_'. $scans scans, $errors errors";
        }
    }
    logmsg "client gone, $scans scans, $errors errors";
    $scans = 0;
    $errors = 0;
}
