Сопряжение BG-биллинга и Городской цифровой АТС MC240 и Цифрового шлюза SMG-1016M производства Элтекс

Материал из BiTel WiKi

Версия от 17:52, 13 мая 2012; Max (Обсуждение | вклад)
(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к: навигация, поиск

Нами в 2010 году была приобретена городская цифровая АТС MC-240 производства Eltex. Данная АТС удовлетворяет всем нормам законодательства в области связи, имеет все сертификаты, и даже что не мало важно СОРМ!
Стандартно АТС ведёт логи в бинарном виде на свей флешке и никак иначе, что кстати с моей точки зрения большая проблема.
Разработчик предусмотрел возможность для доступа к АТС через telnet. Поэтому нами были написаны скрипт на perl'е export.pl который забирает со станции файл с бинарным CDR по протоколу tftp, скармливает его бинарному конвертору bin2bg, полученный результат зипуется (zip) и ложится куда нужно биллингу.
Разработчиком был нам предоставлен штатный бинарный конвертер который мы модифицировали (bin2bg), что бы вывод был нужного для биллинга формата. Нужно отдельно отметить одну не маловажную особенность и очень не приятную кстати: так как команда на скачивание файлов передаётся через телнет, важно чтобы на станции в этот момент не было активных админских телнет сессий, так как телнет сессия открывается всего одна, и если сессия всёаки кем то открыта, скрипт доступа к станции не получит!
Содержимое export.pl:

#!/usr/bin/perl
use Socket;
#use strict;
#use warnings;
use Cwd;
 
#version 1.0.0
 
#========================Настройки==========================
our $subject="WARNING!!! ATS CONVERTATION LOG ERROR!!!";
our $mail_address='admin@domain.ru';
 
our $host="10.9.0.6";
our $port="23";
our $password="xxxxx";
 
our $converter="/usr/local/BGBillingServer/scripts/bin2bg";
our $redirect="/usr/local/BGBillingServer/scripts/redirect.db";
our $export_dir="/usr/local/BGBillingServer/Phone";
our $input_dir="/usr/local/BGBillingServer/tftp/billing";
our $zip="/usr/local/bin/zip";
our $unzip="/usr/local/bin/unzip";
our $rm="/bin/rm";
our $cp="/bin/cp";
our $tmpfile="/tmp/export.tm";
our $log_file="/usr/local/logs/export.log";
our $ats_delay=10;
 
#======================основная программа===================
$SIG{PIPE}="epipe_handler";
socket(SOCK, PF_INET, SOCK_STREAM, getprotobyname('tcp'));
my $ipaddr=inet_aton($host);
my $paddr=sockaddr_in($port,$ipaddr);
my @data;
 
#if ($#ARGV < 1){
#   print "Too few arg\n";
#   print "Usage: export.pl input_dir export_dir\n";
#   exit 0;
#       }
 
#Соединяемся
connect(SOCK,$paddr) || send_alarm ("Connect ERROR-1\n");
send(SOCK,"\r\n",0);
#Вводим пароль
send(SOCK,"$password\r\n",0);
send(SOCK,"trace off\r\n",0);
#Проверяем наличие billing.bak
send(SOCK,"ls \r\n",0);
send(SOCK,"logout\r\n",0);
 
@data=<SOCK>;
close (SOCK);
 
my $file_present=0;
foreach my $lin (@data){
   if ($lin =~ /.*billing\.bak.*/){
      $file_present=1;
   }
}
 
#Если файл найден, то оскачиваем его
if ($file_present){
 
   print "Старый файл лога billing.bak найден\n";
   socket(SOCK, PF_INET, SOCK_STREAM, getprotobyname('tcp'));
   connect(SOCK,$paddr) || send_alarm("Connect ERROR-2\n");
 
   send(SOCK,"\r\n",0);
   #Вводим пароль
   send(SOCK,"$password\r\n",0);
   send(SOCK,"mv billing.bak $mday-$mon-$hour.bak\r\n",0);
   send(SOCK,"tftp p $mday-$mon-$hour.bak /billing/billing.bak\r\n",0);
   #Задержка перед отправкой logout
   sleep($ats_delay);
   send(SOCK,"trace ss7isup\r\n",0);
   send(SOCK,"trace call l30\r\n",0);
   send(SOCK,"logout\r\n",0);
 
   @data=<SOCK>;
   close (SOCK);
   #print @data;
 
   #Ищем признак успешной отправки файла
   my $send_OK=0;
   foreach my $lin (@data){
           if ($lin =~ /^\[TFTP\] Uploaded/){
                $send_OK=1;
           }
           #Если файл был пустой
           if ($lin =~ /^\[TFTP\] Client stop, code 0, err 0/){
                   $send_OK=1;
           }
   }
  #При успешной отправке  удаляем файл журнала
  if ($send_OK){
     remove_and_process();
  }
  #При НЕ успешной отправке выводим лог общения с сервером
  else {
      send_alarm("File send ERROR-3\n");
      print "File send ERROR-3 !!\n";
      print "Log:\n";
      print @data;
      exit -1;
  }
 
}
#Формируем и скачиваем новый файл
socket(SOCK, PF_INET, SOCK_STREAM, getprotobyname('tcp'));
connect(SOCK,$paddr) || send_alarm("Connect ERROR-4\n");
send(SOCK,"\r\n",0);
#Вводим пароль
send(SOCK,"$password\r\n",0);
send(SOCK,"trace off\r\n",0);
send(SOCK,"sysrename\r\n",0);
print("Rename billing.bin to billing.bak\n");
send(SOCK,"mv billing.bak $mday-$mon-$hour.bak\r\n",0);
send(SOCK,"tftp p $mday-$mon-$hour.bak /billing/billing.bak\r\n",0);
#Задержка перед отправкой logout
sleep($ats_delay);
send(SOCK,"trace call l30\r\n",0);
send(SOCK,"trace ss7isup\r\n",0);
send(SOCK,"logout\r\n",0);
@data=<SOCK>;
close (SOCK);
#print @data;
#Ищем признак успешной отправки файла
my $send_OK=0;
foreach my $lin (@data){
   if ($lin =~ /^\[TFTP\] Uploaded/){
      $send_OK=1;
   }
   #Если файл был пустой
   if ($lin =~ /^\[TFTP\] Client stop, code 0, err 0/){
       $send_OK=1;
   }
}
#При успешной отправке  удаляем файл журнала
if ($send_OK){
   remove_and_process();
}
#При НЕ успешной отправке выводим лог общения с сервером
else {
   send_alarm("File send ERROOR-5\n");
   print "File send ERROR-5 !!\n";
   print "Log:\n";
   print @data;
   exit -1;
}
 
exit 0;
 
 
#===========================Функции==================================
 
#Послать письмо с сообщением об ошибке
sub send_alarm{
  my($message)=$_[0];
  print "ERROR: $message\n";
  system ("/bin/echo \"$message\"|/usr/bin/mail -s \"$subject\" $mail_address");
  exit -1;
}
#Послать письмо с сообщением об ошибке
sub send_alarm_noexit{
  my($message)=$_[0];
  print "ERROR: $message\n";
  system ("/bin/echo \"$message\"|/usr/bin/mail -s \"$subject\" $mail_address");
}
 
#Удалить billing.bak c АТС  сконвертировать и заархивировать его на компе
sub remove_and_process{
   print "TFTP put file  successful\n";
   print "Now remove billing.bak file form ATC\n";
 
   socket(SOCK, PF_INET, SOCK_STREAM, getprotobyname('tcp'));
   connect(SOCK,$paddr) || send_alarm("Connect ERROR-6\n");
   send(SOCK,"\r\n",0);
   #Вводим пароль
   send(SOCK,"$password\r\n",0);
   send(SOCK,"rm $mday-$mon-$hour.bak\r\n",0);
   sleep($ats_delay);
   send(SOCK,"logout\r\n",0);
   @data=<SOCK>;
   close (SOCK);
   #print @data;
   print "Remove billing.bak form ATC successful\n";
 
   #Получаем текущее время
   $curr_time = time();
   print "Origunal time: $curr_time\n";
   my ($sec,$min,$hour,$mday,$mon,$year,
          $wday,$yday,$isdst) = localtime($curr_time - 3600);
        #Корректировка года и месяца
        $mon+=1;
        $year+=1900;
 
   if ($hour < 10) { $hour="0".$hour };
        if ($mday < 10) { $mday="0".$mday };
        if ($mon < 10) { $mon="0".$mon };
 
   print "Archive time: $year/$mon/$mday\_$hour\n";
 
        #Конвертация
        #Проверяем наличние струтуры каталогов
        #проверка корневого католога с годом
        if (!(-e "$export_dir/$year")){
           #создаём подкаталог
                mkdir ("$export_dir/$year");
        }
        #проверка каталога с месяцом
        if (!(-e "$export_dir/$year/$mon")){
           #создаём подкаталог
                mkdir ("$export_dir/$year/$mon");
        }
   #Проверяем наличие архива
   if(-e "$export_dir/$year/$mon/$mday\_$hour.zip"){
      #Если архив есть, то распаковываем его
      system("$unzip $export_dir/$year/$mon/$mday\_$hour.zip -d $export_dir/$year/$mon/ ");
      #Ударяем архив
      system("$rm -f $export_dir/$year/$mon/$mday\_$hour.zip");
   }
   #Конвертируем c дописыванием
   print "Now convert Log (billing.bak)  file\n";
   if (system("$converter /3 $input_dir/billing.bak  $export_dir/$year/$mon/$mday\_$hour $redirect > $tmpfile")!=0){
           my $alarm_str="File convert ERROR-7\n";
                my $tstr;
           open(TMP,$tmpfile);
           while($tstr=<TMP>){
                           $alarm_str=$alarm_str.$tstr
           }
           send_alarm_noexit($alarm_str);
   }
        #Копируем billing.bin
        system("$cp -f $input_dir/billing.bak  $export_dir/$year/$mon/billing.bak");
 
   printf("Log convert successful\n");
   #Перемещяемся в нужный каталог
   chdir("$export_dir/$year/$mon");
   #Архивируем
   print "Now compress Log  file\n";
   system "chmod 664 $mday\_$hour.zip";
   system("$zip $mday\_$hour.zip $mday\_$hour billing.bak");
   #Удаляем
   system("$rm -f $mday\_$hour");
   printf("Log  compress successful\n");
   system "chmod 664 $export_dir/$year/$mon/$mday\_$hour.zip";
   return 0;
}
 
sub epipe_handler{
  send_alarm("Connection close. ATS is BUSY(broken pipe) \n");
}

--Max 17:48, 13 мая 2012 (UTC) PS: Незабывем благодарить поднятием кармы автору (тобиж мне).

Личные инструменты