#!/usr/bin/perl -I .

#########################################################################################
# Copyright (C) 2011 Leon Ward 
# openfpc-queued.pl - Part of the OpenFPC - (Full Packet Capture) project
#
# Contact: leon@rm-rf.co.uk
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#########################################################################################

use strict;
use warnings;
use threads;
use threads::shared;
use Thread::Queue;
use IO::Socket;
use Getopt::Long;
use POSIX qw(setsid);		# Required for daemon mode
use Data::Dumper;
use File::Temp(qw(tempdir));
use OFPC::Config;
use OFPC::Common;
use OFPC::Parse;
use OFPC::Request;
use OFPC::CXDB;

=head1 NAME
	openfpc-queued - Queue and process extract requests from local and remote PCAP storage devices.
	Leon Ward - 2010
=head1 VERSION 

0.5
=cut

my $help;
my %route: shared =();
my $configfile=0;

=head 2 showhelp
	Show a simple help message.
=cut

sub showhelp{
	print <<EOF

  * openfpc-queued version $openfpcver *
    Part of the OpenFPC project.
     
    Leon Ward 2010

   --daemon  or -d		Daemon mode
   --config  or -c <file>	Config file  
   --help    or -h		Show help
   --verbose or -v		Verbose logging
   --debug  	 		Show debug data
  
EOF
}

=head2 pipeHandler
	Deal with clients that disappear rather than have perl die.
=cut

sub pipeHandler{
    my $sig = shift @_;
    print "SIGPIPE -> Bad client went away! $sig \n\n" if ($verbose);
}

########### Start Here  ############
$SIG{PIPE} = \&pipeHandler;
$SIG{"TERM"}  = sub { closedown("TERM") };
$SIG{"KILL"}  = sub { closedown("KILL") };

GetOptions (
	'c|conf=s' => \$configfile,
	'd|daemon' => \$daemon,
	'h|help' => \$help,
	'debug' => \$debug,
	'v|verbose' => \$verbose,
	'vdebug' => \$vdebug,
        );

if ($debug) { 
	wlog("DEBUG Enabled\n");
}

if ($vdebug) {
	$debug=1;
	wlog("VDEBUG Enabled\n");
}

if ($help) { 
	showhelp();
	exit;
}

OFPC::Common::initlog or die("Problem initilizating log subsystem");
OFPC::Config::readconfig("$configfile") or die("Problem processing config file $configfile");

wlog("START: *********** OpenFPC $openfpcver **********");
wlog("START: **    http://www.openfpc.org    **");

if ($config{'PROXY'}) {
        wlog("START: Starting OFPC Node \"$config{'NODENAME'}\" as an OpenFPC Proxy");
	OFPC::Common::readroutes;
} else {
        wlog("START: Starting OFPC Node \"$config{'NODENAME'}\" as an OpenFPC Node");
}

# Print verbose config info if debug is enabled
if ($debug) {
	wlog("DEBUG: Node Description: $config{'DESCRIPTION'}");
	wlog("DEBUG: Enabled : $config{'OFPC_ENABLED'}");
	wlog("DEBUG: local savedir : $config{'SAVEDIR'}");
	wlog("DEBUG: Buffer Path : $config{'BUFFER_PATH'}");
	wlog("DEBUG: mergecap : $config{'MERGECAP'}");
	wlog("DEBUG: tcpdump : $config{'TCPDUMP'}");
	wlog("DEBUG: Keep files : $config{'KEEPFILES'}");
}

# Start listener
wlog("START: Starting listener on TCP:$config{'OFPC_PORT'}\n");
my $listenSocket = IO::Socket::INET->new(
                                LocalPort => $config{'OFPC_PORT'},
                                Proto => 'tcp',
                                Listen => '10',
                                Reuse => 1,
                                );

unless ($listenSocket) { 
	wlog("ERROR: Problem creating socke on $config{'OFPC_PORT'}"); 
	exit 1;
}
$listenSocket->autoflush(1);

if ($daemon) {
	chdir '/' or die "Can't chdir to /: $!";
	umask 0;
	open STDIN, '/dev/null'   or die "Can't read /dev/null: $!";
	open (STDOUT, "> $config{'LOGFILE'}") or die "Can't open Log for STDOUT  $config{'LOGFILE'}: $!\n";
	defined(my $pid = fork)   or die "Can't fork: $!";
	if ($pid) {
		open (PID, "> $config{'PIDPATH'}/openfpc-queued-$config{'NODENAME'}.pid") or die "Unable write to pid file $config{'PIDPATH'}/openfpc-queued-$config{'NODENAME'}.pid: $!\n";
      		print PID $pid, "\n";
      		close (PID);
		exit 0;
	}
	# Redirect STDERR Last to catch any error in the fork() process.
	open (STDERR, "> $config{'LOGFILE'}") or die "Can't open Log for STDERR $config{'LOGFILE'}: $!\n";
	setsid or die "Can't start a new session: $!";
}


# Create a couple of separate threads.
threads->create("OFPC::Common::runq");
threads->create("OFPC::Common::backgroundtasks");

while (my $sock = $listenSocket->accept) {
	# set client socket to non blocking
	my $nonblocking = 1;
	ioctl($sock, 0x8004667e, \\$nonblocking);
	$sock->autoflush(1);
	my $client_ip=$sock->peerhost;
	wlog("COMMS: Accepted new connection from $client_ip") ;

	# start new thread to process the request from this socket
	threads->create("OFPC::Common::comms", $sock);
}
