Сопряжение BG-биллинга и Городской цифровой АТС MC240 и Цифрового шлюза SMG-1016M производства Элтекс
Материал из BiTel WiKi
Max (Обсуждение | вклад) м (переименовал «Сопряжение BG-биллинга и Городской цифровой АТС MC240 производства Элтекс» в «[[Сопряжение BG-биллинга и Городской цифровой АТ) |
Max (Обсуждение | вклад) |
||
| Строка 1: | Строка 1: | ||
| - | Нами была приобретена городская цифровая АТС MC-240 производства Eltex. Данная АТС удовлетворяет всем нормам законодательства в области связи, имеет все сертификаты, и даже что не мало важно СОРМ! | + | Нами в 2010 году была приобретена городская цифровая АТС MC-240 производства Eltex. Данная АТС удовлетворяет всем нормам законодательства в области связи, имеет все сертификаты, и даже что не мало важно СОРМ! |
| - | Стандартно АТС ведёт логи в бинарном виде на свей флешке. Разработчик предусмотрел возможность для доступа к АТС через telnet. Поэтому нами были написаны скрипт на perl'е export.pl который забирает со станции файл с бинарным CDR по протоколу tftp, скармливает его бинарному конвертору bin2bg, полученный результат зипуется и ложится куда нужно биллингу. Разработчиком был нам предоставлен штатный бинарный конвертер который мы модифицировали (bin2bg), что бы вывод был нужного для биллинга формата. Нужно отдельно отметить одну не маловажную особенность и очень не приятную кстати: так как команда на скачивание файлов передаётся через телнет, важно чтобы на станции в этот момент не было активных админских телнет сессий, так как телнет сессия открывается всего одна, и если сессия всёаки кем то открыта, скрипт доступа к станции не получит! | + | Стандартно АТС ведёт логи в бинарном виде на свей флешке и никак иначе, что кстати с моей точки зрения большая проблема. |
| + | Разработчик предусмотрел возможность для доступа к АТС через 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@sp-com.ru'; | ||
| + | |||
| + | our $host="10.9.0.6"; | ||
| + | our $port="23"; | ||
| + | our $password="telemetry"; | ||
| + | |||
| + | 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|Max]] 17:48, 13 мая 2012 (UTC) | ||
Версия 17:48, 13 мая 2012
Нами в 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@sp-com.ru';
our $host="10.9.0.6"; our $port="23"; our $password="telemetry";
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)
