#!/bin/sh
eval 'if [ -x /usr/local/cpanel/3rdparty/bin/perl ]; then exec /usr/local/cpanel/3rdparty/bin/perl -x -- $0 ${1+"$@"}; else exec /usr/bin/perl -x $0 ${1+"$@"}; fi;'
if 0;

#!/usr/bin/perl
#
# This script is part of the http://cpgs.cpanel.net/ addon.

BEGIN {
    unshift(@INC, '/usr/local/cpanel','/var/cpanel/cpgs');
};

use strict;
use cPGSLib;
use Cpanel::GameServer;

my %processes;
my %loaded_games;
my %live;
my $dbg         = 0;
my $runningcnt  = 0;
my $loaded_cnt  = 0;
my $done        = 0;
my $logfile     = '/var/log/cpgs_limits.log';
my @text;

if(-d '/var/cpanel/cpgs/games') {
    if(opendir(my $games_dir,'/var/cpanel/cpgs/games')) {
        my @supported_games = readdir($games_dir);
        foreach my $file(@supported_games) {
            if(-f "/var/cpanel/cpgs/games/$file/$file\.pm") {
                eval "use ${file}::${file}";
                if($@) {
                    msglog("Could not load module from \"/var/cpanel/cpgs/games/$file/$file\.pm\" : $@");
                } else {
                    if ( ref( "cPGS::${file}"->can('register_self') ) ) {
                        (undef,$loaded_games{'$file'}{'pkg'},$loaded_games{$file}{'name'}, $loaded_games{$file}{'version'}, $loaded_games{$file}{'descr'}) = "cPGS::$file"->register_self;
                        $loaded_cnt++;
                    }
                }
            }
        }
    }
}

# find max clients allowed
if( open( my $cfg_fh,'<','/var/cpanel/gameserv.cfg') ) {
    while(<$cfg_fh>) {
        if(m/(.*)\_maxclients\|(\d+)/) {
            $live{$1}{'maxc'} = $2;
        } elsif(m/(.*)\_monmaxc\|(.*)/) {
            $live{$1}{'monmaxc'} = $2;
        } elsif(m/(.*)\_monsname\|(.*)/) {
            $live{$1}{'monsname'} = $2;
        }
    }
} else {
    msglog("Could not read from /var/cpanel/gameserv.cfg : $!");
    exit;
}

if( open( my $cfg_fh,'<','/var/cpanel/gameserv_rem.cfg') ) {
    while(<$cfg_fh>) {
        if(m/(.*)\_servip\|(.+)/) {
            $live{$1}{'remip'} = $2;
        }
    }
} else {
    msglog("Could not read from /var/cpanel/gameserv_rem.cfg : $!");
    exit;
}


if( open( my $cfg_fh,'<','/var/cpanel/gameserv_ports.cfg') ) {
    while(<$cfg_fh>) {
        if(m/(.*)\|(.*)/) {
            $live{$1}{'ports'} = $2;
        }
    }
} else {
    msglog("Could not read from /var/cpanel/gameserv_ports.cfg : $!");
    exit;
}

if( open( my $cfg_fh,'<','/var/cpanel/gameserv_ips.cfg') ) {
    while(<$cfg_fh>) {
        if(m/(.*)\|(.*)/) {
            $live{$1}{'ips'} = $2;
        }
    }
} else {
    msglog("Could not read from /var/cpanel/gameserv_ips.cfg : $!");
    exit;
}



foreach my $bit(keys %live) {
    if(! $live{$bit}{'maxc'} || ! $live{$bit}{'ports'} || ! $live{$bit}{'ips'} || ! $live{$bit}{'remip'} ) {
        # print "\n$bit is not fully configured, skipping\n";
    } else {
        if($dbg > 1) {
            print "\n$bit maxc   = $live{$bit}{'maxc'}\n";
            print "$bit ports  = $live{$bit}{'ports'}\n";
            print "$bit ips    = $live{$bit}{'ips'}\n";
            print "$bit remip  = $live{$bit}{'remip'}\n";
        }
        my $maxc = $live{$bit}{'maxc'};
        my $monitor_maxc = $live{$bit}{'monmaxc'};
        my $monitor_sname = $live{$bit}{'monsname'};

        my($user,$game,$srvn) = split(/\_/,$bit,3);

        my ( $matched, $sip, $players, $map, $gtype, $sname, %extra, %retteam );

        my $remuser = cPGSLib::getremuser( $user, $game, $srvn );
        if(!$remuser) { $remuser = $user; }
        my %meta;
        my %data;
        $meta{'remip'}   = $live{$bit}{'remip'};
        $meta{'command'} = 'getserverip';
        $meta{'remuser'} = $remuser;
        $meta{'user'}    = $remuser;
        $meta{'game'}    = $game;
        $meta{'srvn'}    = $srvn;
        my $rp = cPGSLib::sendssl( \%meta, \%data );
        #print "$remuser / $game / $srvn \@ $meta{'remip'} :\n\t";

        if(!$rp) {
            print "getserverip() for $remuser / $game / $srvn failed, no reponse from server..\n";
            next;
        }
        if(!defined($rp->{'pubip'})) {
            print "getserverip() for $remuser / $game / $srvn failed, no pubip returned.\n";
            next;
        }
        $$rp{'pubip'} =~ s/(\r|\n)//g;
        $meta{'command'} = 'get_pid';
        my $rp2 = cPGSLib::sendssl( \%meta, \%data );
        if($$rp2{'pid'} eq undef) {
            print "get_pid() for $remuser / $game / $srvn failed, no pid returned.\n";
            next;
        }
        $data{'pid'} = $$rp2{'pid'};
        $meta{'command'} = 'getboundipp';
        my $rp3 = cPGSLib::sendssl( \%meta, \%data );

        my @targets;
        if ( $$rp3{'socks'} ) {
            @targets = @{ $$rp3{'socks'} };
        }
        foreach (@targets) { s/^0\.0\.0\.0\:/$$rp{'pubip'}\:/g; }

        my $cachedtarget = Cpanel::GameServer::getCachedTarget( $user, $game, $srvn, @targets );
        if ( $cachedtarget ne 'na' ) {
            unshift( @targets, $cachedtarget );    # put our cached target at the front
        }

        if ( defined( $loaded_games{$game}{'name'} ) ) {
            my $m = "cPGS\:\:$game";
            if ( ref( $m->can('getStats') ) ) {
                eval { ( $matched, $sip, $players, $map, $gtype, $sname, undef, %retteam ) = $m->getStats( $user, $game, $srvn, $live{'remip'}, $$rp{'pubip'}, 0, @targets ); };
            }
            if ( !$@ ) {
                if ( $matched == 1 && $sip ) {
                    Cpanel::GameServer::saveTargetCache( $user, $game, $srvn, $sip );
                }
                if( $monitor_maxc =~ m/1|^y/i ) {
                    my ( $cur_p, $max_p ) = split(/\//, $players, 2);
                    if( $max_p > $maxc ) {
                        alert("Max players for $user / $game / $srvn is set at $maxc, but running server has $max_p available.");
                    }
                }
                if( $monitor_sname =~ m/1|^y/i ) {
                    my $hostname_file = '/var/cpanel/cpgs/custom_user_configs/' . "$user\_$game\_$srvn\_hostname";
                    if( -f $hostname_file ) {
                        if(open(my $h_fh, '<', $hostname_file)) {
                            my $host_string = <$h_fh>;
                            close($h_fh);
                            chomp($host_string);
                            if($host_string) {
                                if( $sname !~ m/$host_string/ ) {
                                    alert("Server name \"$sname\" for $user / $game / $srvn does not match \"$host_string\".");
                                }
                            }
                        }
                    }
                }

                # let game modules decide what else is checked
                if ( ref( $m->can('limit_check') ) ) {
                    my $ok = 0; # $ok = 0 means ok
                    my @alertmsgs;
                    eval { ( $ok, @alertmsgs ) = $m->limit_check( $user, $game, $srvn, $matched, $sip, $players, $map, $gtype, $sname, \%retteam ); };
                    if( ! $ok ) {
                        foreach my $alertmsg(@alertmsgs) {
                            alert($alertmsg);
                        }
                    }
                }
                print "Server: $sip, $players, $map, $gtype, $sname \n" if $sip;
            }
            else {
                print "Server stats information currently unavailablefor $remuser / $game / $srvn\n";
            }
        }
    }
}
$done = 1;
alert("cpgs_limit_check complete.");



exit;



sub alert {
    my ($msg) = @_;
    my %alert_settings;
    $alert_settings{'email'} = 1;
    $alert_settings{'contactaddress'} = '';
    if( open( my $alert_cfg, '<', '/var/cpanel/cpgs/alert.cfg') ) {
        while(<$alert_cfg>) {
            chomp;
            if( m/email=(.*)/) {
                $alert_settings{'email'} = $1;
            } elsif ( m/contactaddress=(.*)/ ) {
                $alert_settings{'contactaddress'} = $1;
            }
        }
        close($alert_cfg);
    }
    msglog("cpgs_limit_check: $msg");
    my $issue_cnt = @text;

    # if email alerts are enabled, an email address was given and we have something to report and are done walking the user/game/server list..
    if( $alert_settings{'email'} =~ m/1|^y/i && $alert_settings{'contactaddress'} && $issue_cnt > 0 ) {
        if( $done == 1 ) {
            push(@text, $msg);
            eval {
                if ( my $pid = fork() ) {
                    waitpid( $pid, 0 );
                }
                else {
                    if( $dbg > 0 ) {
                        msglog("Sending report mail to " . $alert_settings{'contactaddress'} );
                    }
                    chomp(my $hostname = `hostname`);
                    my $tiempo = localtime(time);
                    if( open( my $sendmail_fh, '|/usr/sbin/sendmail -t') ) {
                        print {$sendmail_fh} 'To: <' . $alert_settings{'contactaddress'} .">\n";
                        print {$sendmail_fh} 'From: <root@' . $hostname .">\n";
                        print {$sendmail_fh} "Subject: cpgs_limit_check report\n\n";
                        print {$sendmail_fh} "The following issues were detected in running servers by $hostname:\n\n";
                        foreach my $line(@text) {
                            print {$sendmail_fh} " - $line\n\n" unless $line =~ m/^cpgs_limit_check\s/;
                        }
                        print {$sendmail_fh} "\nThis email was sent via /var/cpanel/cpgs/cpgs_limit_chk ( $0 )\n from /etc/crontab or manually via the shell.\n\n";
                        close($sendmail_fh);
                        if( $dbg > 0 ) {
                            msglog("Sent report mail.");
                        }
                    } else {
                        msglog("Could not open /usr/sbin/sendmail : $!");
                    }
                    exit;
                }
            };
        } else {
            push(@text, $msg);
        }
    }
    if( $dbg > 0 ) { print "$msg\n"; }
}

sub msglog {
    my($msg)=@_;
    my $time=time;
    my $localtime=localtime($time);
    if(open(my $log_fh,'>>',$logfile)) {
        print $log_fh "\[$localtime\] ($0) " . $msg . "\n";
        close($log_fh);
    }
}

