Newer
Older
#!/usr/bin/perl
# Main OpenTrafficShaper program
# 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 3 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, see <http://www.gnu.org/licenses/>.
use strict;
use warnings;
# Set the dirs we look for library files in
use lib(
'/usr/local/lib/opentrafficshaper-1.0',
'/usr/lib/opentrafficshaper-1.0',
'/usr/lib64/opentrafficshaper-1.0',
'opentrafficshaper',
'awitpt/lib',
);
# Enable assertions
BEGIN {
package POE::Kernel;
use constant ASSERT_DEFAULT => 1;
}
# System stuff we need
use Config::IniFiles;
use Getopt::Long;
use Time::HiRes qw(time);
# Our own stuff
use opentrafficshaper::version;
use opentrafficshaper::logger;
use opentrafficshaper::plugins qw( plugin_register );
# Main config
my $globals;
# We just create the logger first, its only using STDERR here
my $logger = new opentrafficshaper::logger;
# Check if we must use a log file instead
if (defined($globals->{'config'}->{'log_file'})) {
$logger->open($globals->{'config'}->{'log_file'});
}
$logger->setLevel($globals->{'config'}->{'log_level'});
# Check if we need to go background
if (defined($globals->{'config'}->{'background'})) {
daemonize();
}
displayBanner();
start();
$logger->log(LOG_NOTICE,"[MAIN] Entering RUNNING state");
# Function to display banner
sub displayBanner
{
$logger->log(LOG_NOTICE,"[MAIN] OpenTrafficShaper v%s - Copyright (c) 2007-2014, AllWorldIT",VERSION);
# Function to parse our config and commandline
sub parseCfgCmdLine
{
# Set defaults
my $cfg;
$cfg->{'config_file'} = "/etc/opentrafficshaper.conf";
$cfg->{'background'} = "yes";
$cfg->{'pid_file'} = "/var/run/opentrafficshaper/opentrafficshaperd.pid";
$cfg->{'log_level'} = 2;
$cfg->{'log_file'} = "/var/log/opentrafficshaper/opentrafficshaperd.log";
# Parse command line params
my $cmdline;
%{$cmdline} = ();
GetOptions(
\%{$cmdline},
"help",
"config:s",
"debug",
"fg",
) or die "Error parsing commandline arguments";
# Check for some args
if ($cmdline->{'help'}) {
displayHelp();
exit 0;
}
if (defined($cmdline->{'config'}) && $cmdline->{'config'} ne "") {
$cfg->{'config_file'} = $cmdline->{'config'};
}
# Check config file exists
if (! -f $cfg->{'config_file'}) {
die("No configuration file '".$cfg->{'config_file'}."' found!");
}
# Use config file, ignore case
tie my %inifile, 'Config::IniFiles', (
-file => $cfg->{'config_file'},
-nocase => 1
) or die "Failed to open config file '".$cfg->{'config_file'}."': $!";
my $inifileHandle = tied( %inifile );
# Copy config
my %config = %inifile;
# Pull in params for the server
my @server_params = (
'log_level','log_file',
'pid_file',
'background',
$cfg->{$param} = $config{'system'}{$param} if (defined($config{'system'}{$param}));
}
# Override
if ($cmdline->{'debug'}) {
$cfg->{'log_level'} = 4;
$cfg->{'debug'} = 1;
}
# If we set on commandline for foreground, keep in foreground
if ($cmdline->{'fg'} || (defined($config{'system'}{'background'}) && $config{'system'}{'background'} eq "no" )) {
$cfg->{'background'} = undef;
$cfg->{'log_file'} = undef;
}
#
# System plugins
#
if (ref($config{'plugins'}{'load'}) eq "ARRAY") {
foreach my $plugin (@{$config{'plugins'}{'load'}}) {
$plugin =~ s/\s+//g;
# Skip comments
next if ($plugin =~ /^#/);
push(@{$cfg->{'plugin_list'}},$plugin);
}
} elsif (defined($config{'plugins'}{'load'})) {
my @pluginList = split(/\s+/,$config{'plugins'}{'load'});
foreach my $plugin (@pluginList) {
# Skip comments
next if ($plugin =~ /^#/);
push(@{$cfg->{'plugin_list'}},$plugin);
}
}
# We may have config file groups we want to remember for other plugins
foreach my $group ($inifileHandle->Groups()) {
# Loop with group members
foreach my $member ($inifileHandle->GroupMembers($group)) {
# Chop off group name and just get the member
my $cleanMember = substr($member,length($group)+1);
# Link the config...
$config{$group}->{$cleanMember} = $config{$member};
}
}
$globals->{'file.config'} = \%config;
$globals->{'config'} = $cfg;
}
# Display help
sub displayHelp {
print(STDERR<<EOF);
Usage: $0 [args]
--config=<file> Configuration file
--debug Put into debug mode
--fg Don't go into background
EOF
}
# Initialize things we need
sub init
{
# Certain things we need
$globals->{'users'} = { };
$globals->{'logger'} = $logger;
$globals->{'version'} = VERSION;
$logger->log(LOG_NOTICE,"[MAIN] Entering INITIALIZATION state");
# Setup master session
POE::Session->create(
inline_states => {
'_start' => \&main_session_start,
'_stop' => \&main_session_stop,
'main_SIGHUP' => \&main_signal_SIGHUP,
'main_SIGINT' => \&main_signal_SIGINT,
},
);
$logger->log(LOG_INFO,"[MAIN] Initializing plugins...");
# We need to set the plugins global variable
opentrafficshaper::plugins::init($globals);
# Core configuration manager
foreach my $pluginName (@{$globals->{'config'}->{'plugin_list'}}) {
plugin_register($pluginName,0);
# Function to start things up
sub start
{
$logger->log(LOG_NOTICE,"[MAIN] Entering STARTING state");
# Loop with plugins and call the start function for those that exist
foreach my $pluginName (keys %{$globals->{'plugins'}})
my $plugin = $globals->{'plugins'}->{$pluginName};
# Load the function up
my $callStart = $plugin->{'Start'};
if (defined($callStart)) {
$callStart->();
}
}
}
# Become daemon
sub daemonize {
chdir '/'
or die "Can't chdir to /: $!";
open STDIN, '/dev/null'
or die "Can't read /dev/null: $!";
or die "Can't open stdout log: $!";
or die "Can't fork: $!";
exit if $pid;
# Write out our PID if we have a file to do it
if (defined($globals->{'config'}->{'pid_file'})) {
if (open(FH,"> ".$globals->{'config'}->{'pid_file'})) {
print(FH $$);
close(FH);
} else {
$logger->log(LOG_WARN,"[MAIN] Unable to write PID to '%s': %s",$globals->{'config'}->{'pid_file'},$!);
setsid
or die "Can't start a new session: $!";
or die "Can't open stderr log: $!";
}
# Function to fire up our main session
sub main_session_start
{
my $kernel = $_[KERNEL];
$kernel->alias_set('main');
# Register signal handlers
$kernel->sig('HUP', 'main_SIGHUP');
$kernel->sig('INT', 'main_SIGINT');
}
# Function to dispose of anything as a final stage to shutting down
sub main_session_stop
{
$logger->log(LOG_DEBUG,"[MAIN] Shutdown");
# Function to handle SIGHUP
sub main_signal_SIGHUP
{
my ($kernel,$signal_name) = @_[KERNEL,ARG0];
$logger->log(LOG_NOTICE,"[MAIN] Got SIGHUP");
$kernel->sig_handled();
}
# Function to handle SIGINT
sub main_signal_SIGINT
{
my ($kernel, $signal_name) = @_[KERNEL, ARG0];
$logger->log(LOG_NOTICE,"[MAIN] Got SIGINT, shutting down...");
$kernel->signal($kernel,'handle_SIGINT');
}