#
# Trend Micro FileScan API via Trophie
#

if ($trophie_sockname) {
    do_log(2,"Using Trophie");
    if ($child_task_count == 1) {
	socket(\*trophie_sock, AF_UNIX, SOCK_STREAM, 0)
	    or die "Can't create socket for Trophie: $!";
	connect(\*trophie_sock, pack_sockaddr_un $trophie_sockname)
	    or die "Can't connect to Trophie: $!";
    }
    my($chkdir) = "$TEMPDIR/parts/\n";

    $SIG{PIPE} = 'IGNORE';  # 'send' to broken pipe throws a signal
    my($retries) = 0;
    for (;;) {  # gracefully handle cases when Trophie child times out
	while (!defined(syswrite(\*trophie_sock, $chkdir, length($chkdir)))) {
	    my($err) = "$!"; my($errn) = 0+$!;
	    $retries++;
	    if ($errn != EPIPE && $errn != ENOTCONN) {
		die "syswrite to Trophie socket failed: $err";
	    } else {
		if ($retries > 2) { die "Too many retries to talk to Trophie" }
		if ($err =~ /^Broken pipe/i) {  # slow down a runaway loop
		    sleep(10 * ($retries-1))  if $retries > 1;
		}
		do_log( ($retries>1?0:1),
			"Re-connecting to Trophie, attempt #$retries");
		close(\*trophie_sock);  # and ignore status
		socket(\*trophie_sock, AF_UNIX, SOCK_STREAM, 0)
		    or die "Can't create socket for Trophie: $!";
		connect(\*trophie_sock, pack_sockaddr_un $trophie_sockname)
		    or die "Can't connect to Trophie: $!";
	    }
	}
	defined(sysread(\*trophie_sock, $output, 256))
	    or die "sysread from Trophie socket failed: $!";
	last  if $output ne '';
	do_log( ($retries>1?0:1),
	       "Failed to get response from Trophie, retrying ($retries)");
	sleep 10;
    }
    # LF-terminated, older Trophie filled the buffer with nulls;
    $output =~ s/[\000\r\n]+$//;
    # older Trophie didn't append colon and error text if $stat == -1
    if ($output !~ /^ ([-+]? \d*) (?: : (.*?) )? $/x) {
	do_log(0,"Virus scanner failure: can't parse Trophie output: <$output>");
    } else {
	my($stat,$rest) = ($1,$2);
	$rest = $1  if $rest =~ /^'(.*?)'$/;
	do_log(2,"Result from Trophie: $stat" . ($rest eq '' ? '' : ":$rest") );
	if ($stat == 1) {
	    @virusname = $rest;
	    $scanner_errors = 0;  # no errors, a virus was found
	    return 1;
	} elsif ($stat == 0) {
	    $scanner_errors = 0;  # no errors, no viruses
	} elsif ($stat == -1) {
	    do_log(0,"Virus scanner failure: Trophie - $stat:$rest");
	} else {
	    do_log(0,"Virus scanner failure: Trophie - OOOPS: <$output>");
	}
    }
}
