#!/usr/bin/perl 
##########################################################################
#                                                                        #
# Perl Script for Resend lost Accouting packet to portaone Repius Server #
#                                                                        #
# Switzernet(c)2011                                                      #
#                                                                        #
##########################################################################
# my modules
use strict;
use warnings;
use POSIX;
use Config::IniFiles;
use Switch;
use DBI;
##########################################################################
# Setting
my $lock_file = '/var/run/exec-registration.pid';
my $runas_user = 'root';
my $config_file = '/etc/dba/setup-mysql-replication.conf';
##########################################################################
# Globals
my ($dbh1,$dbh2,$User,$Pass,$master_host,$master_user,$dba_user,$SYNC_DBA);
my @dba_hosts;
my @dba_dbh;
my $ipaddress;
##########################################################################
#                             Initialization                             #
##########################################################################
# Check if already running
if( -e $lock_file ) {
	open(PID,$lock_file);
	my $pid=<PID>;
	close PID;
	chomp $pid;
	if( !-e "/proc/$pid" ) {
		print STDERR "Lock file present, but no process with pid=$pid.\n";
		die "Can't delete lock file $lock_file\n" if !unlink $lock_file;
		print STDERR "Lock file has been removed.\n";
	} else {
		die "Lockfile present, another copy is punning pid=$pid\n";
	}
}
my ($name, $passwd, $uid, $gid) = getpwnam($runas_user) or die "$runas_user not in passwd file";;
##########################################################################
# set C locale
POSIX::setlocale(LC_ALL, "C");
##########################################################################
# Become daemon
my $pid;
if( !defined($pid = fork()) ) {
    die "cannot fork: $!";
} elsif ($pid) {
    # Create lockfile, and finish parent process
    open(PID, "> $lock_file") || die "exec-registration.pl: Unable to create lockfile $lock_file\n";
    print PID "$pid";
    close PID;
    chown $uid, $gid, $lock_file;
    exit;
} else {
    # daemon
    setpgrp();
    select(STDERR); $| = 1;
    select(STDOUT); $| = 1;
}

##########################################################################
# Install signall handler
$SIG{INT} = \&safe_exit;
$SIG{QUIT} = \&safe_exit;
$SIG{TERM} = \&safe_exit;
$SIG{HUP} = \&load_config;
##########################################################################
# Drop privileges
setuid($uid);
$< = $uid;
$> = $uid;
##########################################################################
# Signal Handlers
sub safe_exit {
    unlink $lock_file ;
    $dbh1->disconnect or warn "Disconnection failed: $DBI::errstr\n";
    $dbh2->disconnect or warn "Disconnection failed: $DBI::errstr\n";
    foreach my $tdbh (@dba_dbh) {
       $tdbh->disconnect or warn "Disconnection failed: $DBI::errstr\n";
    }
    exit;
}
##########################################################################
#                                FUNCTION                                #
##########################################################################
# Remove leading and trailing white space from a string
sub chomp_plus {
    my $string=shift;
    $string =~ s/^\s+//;$string =~ s/\s+$//;
    chomp $string;
    return $string;
}
##########################################################################
# Load config from mysql.conf
sub load_config {
    my $conf=Config::IniFiles->new(-file => $config_file);
    return 0 if !defined $conf ;
    $User  = $conf->val('SLAVE','User');
    $Pass  = $conf->val('SLAVE','Pass');      
    $master_host = $conf->val('MASTER','Master');
    $master_user = $conf->val('MASTER','User');
    my @ifconfigresult = `/sbin/ifconfig|/bin/grep "addr.*Bcast" -oE`;
    $ifconfigresult[0] =~ m/addr:([^ ]+)[ ]*Bcast/;
    my $ipaddress      = $1;
    $dba_user = $conf->val('DBA','User');
    @dba_hosts=split(',', $conf->val('DBA','Host'));
    my $i = 0;
    foreach my $t (@dba_hosts) {
        $t=chomp_plus($t);
        delete $dba_hosts[$i] if ($dba_hosts[$i] eq $ipaddress);
        $i++;
    }
    $SYNC_DBA = $conf->val('DBA','Sync');
    if ($SYNC_DBA=~ m/(on|yes|1)/i) {$SYNC_DBA=1;}
    else {$SYNC_DBA=0};
    return 1;
}
##########################################################################
# Astrad Radius DB connect
sub db_connect {
    my $dbh = DBI->connect_cached("DBI:mysql:".$_[0].";host=".$_[1],$_[2],$_[3]);
    return $dbh if $dbh ;
    safe_exit();
}
##########################################################################
# 
sub exec_register {
my ($str,$stp)=(0,0);
my $req1=' ';
my $req2=' ';
my @req3;
my $sth = $dbh1->prepare("SELECT * FROM registration where dba=(select value from config where name='ipaddr') ORDER BY id LIMIT 30;");
safe_exit() if !$sth->execute();
return 0 if  !$sth->rows;
while (my $result = $sth->fetchrow_hashref) {
    $str=$result->{id} if !$str;
    $stp=$result->{id};
    if ($result->{action} eq 'REGISTER') {
       $result->{useragent} = 'Unknown' if (!defined $result->{useragent});
       $req1 .= "('".$result->{username}."','".$result->{domain}."','sip:".$result->{username}.'@'.$result->{ipaddr}.':'.$result->{port}."','".$result->{expires}."',-1.00,'Astrad-V010', 1, 1, '".$result->{useragent}."'),";
       push(@req3, "INSERT INTO location2 (username,domain,dba,ipaddr,port,expires,register) VALUES ('".$result->{username}."','".$result->{domain}."','".$result->{dba}."','".$result->{ipaddr}."','".$result->{port}."','".$result->{expires}."','".$result->{register}."') ON DUPLICATE KEY UPDATE expires='".$result->{expires}."', register='".$result->{register}."';");
#       push(@req3, "UPDATE location2 SET useragent='".$result->{useragent}."' WHERE username = '".$result->{username}."' AND domain = '".$result->{domain}."' AND dba = '".$result->{dba}."' AND ipaddr = '".$result->{ipaddr}."' AND port = '".$result->{port}."';");
       }
    elsif  ($result->{action} eq 'UNREGISTER') {
       $req2 .= "(username='".$result->{username}."' AND domain='".$result->{domain}."' AND contact='sip:".$result->{username}.'@'.$result->{ipaddr}.':'.$result->{port}."' AND expires='".$result->{expires}."') OR ";
       push(@req3, "DELETE FROM location2 WHERE username='".$result->{username}."'AND domain='".$result->{domain}."'AND dba='".$result->{dba}."' AND expires='".$result->{expires}."'");
       }
    }
$sth->finish;
$dbh2->do("REPLACE INTO location (username,domain,contact,expires,q,callid,cseq,flags,user_agent) VALUES ".substr($req1,0,length($req1)-1)) if $req1 ne ' ';
$dbh2->do("DELETE FROM location WHERE ".substr($req2,0,length($req2)-3)) if $req2 ne ' ';
$dbh1->do("DELETE FROM registration WHERE id BETWEEN $str AND $stp");
return 1 if (!$SYNC_DBA);
foreach my $treq (@req3) {
   foreach my $tdbh (@dba_dbh) {
      $tdbh->do($treq);
   }
}
undef(@req3);
return 1;
}
##########################################################################
#                                 main()                                 #
##########################################################################
load_config();
for (my $i=0;$i<30;$i++) {
  $dbh1=db_connect("astrad","localhost",$User,$Pass);
  $dbh2=db_connect("porta-sip",$master_host,$master_user,'');
  if ($SYNC_DBA) {
     foreach my $t (@dba_hosts) {push(@dba_dbh,db_connect("astrad",$t,$dba_user,'')) if (defined $t);}
     }
  $i=0 if exec_register();
  sleep 1 if $i;
  undef(@dba_dbh);
}
safe_exit();
##########################################################################
#                                  END                                   #
##########################################################################