Сопряжение BG-биллинга и Городской цифровой АТС MC240 и Цифрового шлюза SMG-1016M производства Элтекс
Материал из BiTel WiKi
Нами в 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: Незабывем благодарить поднятием кармы автору (тобиж мне).