#!/usr/local/bin/perl
#
#  Copyright (c) 2004, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
#  All rights reserved.
#
#  Redistribution and use in source and binary forms, with or without
#  modification, are permitted provided that the following conditions are met:
#
#   * Redistributions of source code must retain the above copyright notice,
#	 this list of conditions and the following disclaimer.
#   * Redistributions in binary form must reproduce the above copyright notice,
#	 this list of conditions and the following disclaimer in the documentation
#	 and/or other materials provided with the distribution.
#   * Neither the name of SWITCH nor the names of its contributors may be
#	 used to endorse or promote products derived from this software without
#	 specific prior written permission.
#
#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
#  POSSIBILITY OF SUCH DAMAGE.
#
#  $Author: peter $
#
#  $Id: NfSenRC.pm 52 2006-03-24 10:38:43Z peter $
#
#  $LastChangedRevision: 52 $

package NfSenRC;

use strict;
use warnings;
use Log;

# public map for collector mappings - more may be added in future
our %CollectorMap = ( 
	'netflow'	=> 'nfcapd',
	'sflow'		=> 'sfcapd',
);

sub StartCollector {
	my $ident = shift;

	print " $ident";
	my $type		= exists $NfConf::sources{$ident}{'type'} ? $NfConf::sources{$ident}{'type'}: 'netflow';
	my $collector	= $CollectorMap{$type};
	my $port 		= $NfConf::sources{$ident}{'port'};
	my $uid			= $NfConf::USER;
	my $gid 		= $NfConf::WWWGROUP  ? "$NfConf::WWWGROUP"   : "";
	my $buffer_opts = $NfConf::BUFFLEN ? "-B $NfConf::BUFFLEN"   : "";
	my $profiledir	= "$NfConf::PROFILEDATADIR/live/$ident";
	my $pidfile	 	="$NfConf::VARDIR/run/$ident.pid";
	my $profiler 	= "'$NfConf::PREFIX/nfprofile -q -p $NfConf::PROFILEDATADIR -s $ident -r %d/%f'";

	my $args 		= "-w -D -I $ident -p $port -u $uid -g $gid $buffer_opts -l $profiledir -P $pidfile -x $profiler";
	#print "Run: $NfConf::PREFIX/nfcapd $args\n";

	system("$NfConf::PREFIX/$collector $args");
	my $exit_value  = $? >> 8;
	my $signal_num  = $? & 127;
	my $dumped_core = $? & 128;
	if ( $exit_value != 0 ) {
		print "$collector exec error: exit: $exit_value, signal: $signal_num, coredump: $dumped_core\n";
	}

} # End of StartCollector

sub StopCollector {
	my $ident = shift;

	print " $ident:";
	if ( -f "$NfConf::VARDIR/run/$ident.pid" ) {
		open PID, "$NfConf::VARDIR/run/$ident.pid" || 
			die "Can't read pid file '$NfConf::VARDIR/run/$ident.pid': $!\n";
		my $pid = <PID>;
		chomp $pid;
		close PID;
		print "[$pid]";
		if ( kill( 0, $pid) == 0  ) {
			print "[No such process]";
			unlink "$NfConf::VARDIR/run/$ident.pid";
		} else {
			kill 'TERM', $pid || warn "Can't signal nfcapd: $! ";
			my $timeout = 10;
			while ( $timeout && -f "$NfConf::VARDIR/run/$ident.pid") {
				print ".";
				sleep 1;
				$timeout--;
			}
		}
		if ( -f "$NfConf::VARDIR/run/$ident.pid") {
			print " Process [$pid] does not want to terminate!\n";
		}
	} else {
		print "[no pid file found!]";
	}

} # End of StartCollector

sub NfSen_start {

	# Check if NfSen is already running
	if ( -f "$NfConf::VARDIR/run/nfsend.pid" ) {
		open PID, "$NfConf::VARDIR/run/nfsend.pid" || 
			die "Can't read pid file '$NfConf::VARDIR/run/nfsend.pid': $!\n";
		my $pid = <PID>;
		chomp $pid;
		close PID;
		if ( kill( 0, $pid) == 1  ) {
			print "NfSen is already running!\n";
			return;
		} else {
			print "Unclean shutdown - run stop sequence first to clean up!\n";
			NfSen_stop();
		}
	}

	print "Starting nfcpad:";
	foreach my $source ( keys %NfConf::sources ) {
		StartCollector($source);
	}
	print ".\n";

	print "Starting nfsend";
	system "$NfConf::BINDIR/nfsend";
	my $exit_value  = $? >> 8;
	my $signal_num  = $? & 127;
	my $dumped_core = $? & 128;
	if ( $exit_value != 0 ) {
		print ": exec error: exit: $exit_value, signal: $signal_num, coredump: $dumped_core\n";
	}
	print ".\n";

} # End of NfSen_start

sub NfSen_stop {

	print "Shutdown nfcpad:";
	foreach my $source ( keys %NfConf::sources ) {
		StopCollector($source);
	}
	print ".\n";

	print "Shutdown nfsend:";
	if ( -f "$NfConf::VARDIR/run/nfsend.pid" ) {
		open PID, "$NfConf::VARDIR/run/nfsend.pid" || 
			die "Can't read pid file '$NfConf::VARDIR/run/nfsend.pid': $!\n";
		my $pid = <PID>;
		chomp $pid;
		close PID;
		print "[$pid]";
		if ( kill( 0, $pid) == 0  ) {
			print "[No such process]";
			unlink "$NfConf::VARDIR/run/nfsend.pid";
		} else {
			kill 'TERM', $pid || warn "Can't signal nfsend: $! ";
			my $timeout = 120;
			while ( $timeout && -f "$NfConf::VARDIR/run/nfsend.pid") {
				print ".";
				sleep 1;
				$timeout--;
			}
		}
		if ( -f "$NfConf::VARDIR/run/nfsend.pid") {
			print " Process [$pid] does not want to terminate!\n";
		}
	} else {
		print "[no pid file found!]";
	}
	print "\n";

} # End of NfSen_stop

sub NfSen_reload {

	if ( -f "$NfConf::VARDIR/run/nfsend.pid" ) {
		print "Restart nfsend:";
		open PID, "$NfConf::VARDIR/run/nfsend.pid" || 
			die "Can't read pid file '$NfConf::VARDIR/run/nfsend.pid': $!\n";
		my $pid = <PID>;
		chomp $pid;
		close PID;
		print "[$pid]\n";
		kill 'USR1', $pid || warn "Can't restart nfsend: $! ";
	} else {
		print STDERR "No pid file found for nfsend - please restart manually\n";
	}

} # End of NfSen_reload

1;
