BiTel

Форум BiTel
bgbilling.ru     docs.bitel.ru     wiki.bitel.ru     dbinfo.bitel.ru     bgcrm.ru     billing.bitel.ru     bitel.ru    
Текущее время: 05 дек 2024, 01:38

Часовой пояс: UTC + 5 часов [ Летнее время ]




Начать новую тему Ответить на тему  [ Сообщений: 12 ] 
Автор Сообщение
СообщениеДобавлено: 01 апр 2010, 12:20 
Не в сети

Зарегистрирован: 16 ноя 2007, 16:11
Сообщения: 829
Карма: 49
Оттестировали на 4.6 ipfw manad и скрипт с поддержкой изменения правил. Попутно в manad внесены изменения для помещения его правил в отдельный set ipfw.
За основу были взяты [url]http://wiki.bgbilling.ru/index.php/Реализация_стандартного_шлюза_Manad_на_BeanShell[/url] и [url]http://wiki.bgbilling.ru/index.php/Изменения_в_manad_для_работы_с_одним_pipe_на_множество_IP_адресов[/url]

При модификации преследовались две цели - минимизировать потерю производительности и обеспечить совместимость старого manad с новым скриптом и встроенного скрипта с новым manad.

При отработке смены правил используется последовательность remove-add, так что возможны "разрывы".


Последний раз редактировалось vdd 01 апр 2010, 12:32, всего редактировалось 1 раз.

Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 01 апр 2010, 12:22 
Не в сети

Зарегистрирован: 16 ноя 2007, 16:11
Сообщения: 829
Карма: 49
После полного перехода на новый manad строчку
Код:
if(rid==null && status.ruleType!=null) ruleChanged=false; // совместимость со старым manad

заменить на
Код:
if(rid==null && status.ruleType!=null) ruleChanged=true;

Код:
import java.io.*;
import java.net.*;
import java.util.*;
import bitel.billing.common.module.ipn.*;
import bitel.billing.server.ipn.bean.*;
 
protected void doSync()
{
        host = gate.getHost();
        port = gate.getPort();
        gid = gate.getId();
 
        if ( log.isDebugEnabled() )
        {
            log.debug( gid + " gate: " + host + ":" + port );
        }
 
 
        try
        {
                socket = new Socket( host, port );
                out = new PrintWriter( socket.getOutputStream(), true );
                isr = new InputStreamReader( socket.getInputStream() );
                in = new BufferedReader( isr );
                out.println( "testRID" );
                kods = in.readLine();

        if ( log.isDebugEnabled() )
        {
            log.debug( gid + " Test => " + kods + "\n" );
        }
 
                // список открытых договоров с шлюза
                gateRules = new HashMap( 5, 5 );
                st = new StringTokenizer( kods );
                while ( st.hasMoreTokens() )
                {
                  sp=st.nextToken().split("-");
                  if(sp.length==2) gateRules.put( new Integer( sp[0] ),(sp[1]==null)?null:new Integer(sp[1]) );
                  else gateRules.put( new Integer( sp[0] ),null);
                }
 
                for( i = 0; i < statusList.size(); i++ )
                {
                        status = statusList.get(i);
                        cid = status.contractId;
 
                        // флаг того то правило есть на шлюзе
                        flag = false;
                   ruleChanged=false;
                        // правило для этого договора есть на шлюзе
                        if ( gateRules.containsKey( cid ) )
                        {
                                //      если правило есть а юзер заблокирован - удаляем правило
                                if ( status.status > 0 )
                                {
                                        rule = generateRule( status );
                                        command = "remove\t" + cid.intValue() + "\t" + rule;
                                        out.println( command );
                                     if ( log.isDebugEnabled() ) {
                                     log.debug( gid + " " + command );
                                        }

                                 }else{
                           // правило есть и юзер открыт - проверяем тип правила
                           rid=gateRules.get(cid);
                           if(rid!=null && status.ruleType==null) ruleChanged=true;
                           if(rid==null && status.ruleType!=null) ruleChanged=false; // совместимость со старым manad
                           if(rid!=null && status.ruleType!=null && !rid.equals(status.ruleType.getId())) ruleChanged=true;
                           if(ruleChanged){
                                     if ( log.isDebugEnabled() ) {
                                     log.debug( gid + " rule changed");
                                        }

                           }
                           }                                               
 
                                flag = true;
                                gateRules.remove( cid );
                        }
 
                        // правила нет, а юзер открыт, правило есть, но было изменение типа правила
                        if ( (!flag &&
                                status.status == IPNContractStatus.STATUS_OPEN ) ||(ruleChanged && status.status == IPNContractStatus.STATUS_OPEN ))
                        {
                                rule = generateRule( status );
 
                                command = "add\t" + cid.intValue() + "\t" + rule; // в случае изменения manad затрет старые правила ipfw
                          if( status.ruleType != null ) command+=" // RULE"+status.ruleType.getId();
                  
                                out.println( command );
 
                            if ( log.isDebugEnabled() )
                {
                    log.debug( gid + " " + command );
                }



                        }
                }
 
                in.close();
                out.close();
                socket.close();
        }
        catch ( e )
        {
                throw new RuntimeException ( e );
        }
}
 
private generateRule( status )
{
        rule = null;
 
        // пользовательское правило, без типа
        if( status.ruleType == null )
        {
                rule = status.rule.getRuleText();
        }
        // типизированное правило
        else
        {       
 
                ruleText = ManadUtils.getRule( status.gateType, status.ruleType );
                rule =  ManadUtils.generateRule( ruleText,  status.rule.getRuleText(), null, status.ruleType );                     
        }
 
 
        rule = rule.replaceAll( "\r", "" );
        rule = rule.replaceAll( "\n", "|" );
 
        return rule;
}


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 01 апр 2010, 12:29 
Не в сети

Зарегистрирован: 16 ноя 2007, 16:11
Сообщения: 829
Карма: 49
#!/usr/bin/perl

use POSIX;
use IO::Socket;
use IO::Select;
use Socket;
use Fcntl;
use Tie::RefHash;


$debug = 1;
$port = 4444;
$ipfw = "/sbin/ipfw";
$rule_start = 15000;
$pipe_start = 200;
$set = 10;

# База данных правил клиентов
%CLRULE = ();
%CLRULE_ID = ();

# База данных используемых номеров правил
%USERULEN = ();
%CLUSERULEN = ();

# База данных используемых номеров труб
%USEPIPEN = ();
%CLUSEPIPEN = ();

# Начать с пустыми буферами
%inbuffer = ();
%outbuffer = ();
%ready = ();

tie %ready, 'Tie::RefHash';

# Прослушивать порт
$server = IO::Socket::INET->new( LocalPort => $port, Listen => 10 )
or die "Can`t make server socket: $@\n";

nonblock( $server );

$SIG{INT} = sub { $server->close(); exit( 0 ); };

$select = IO::Select->new( $server );

$pid = getpid();

open(FILE, ">/var/run/manad.pid");
print FILE $pid;
close(FILE);

# Устанавливаем новый root каталог для процесса
# chroot( $homedir ) or die "Couldn`t chroot to $homedir: $!\n";

# Главный цикл: проверка чтения/принятия, проверка записи,
# проверка готовности к работе

while( 1 )
{
my $client;
my $rv;
my $data;

# Проверить наличие новой информации на имеющихся подключениях

# Есть ли что-нибудь для чтения или подтверждения?
foreach $client ( $select->can_read( 1 ) )
{
if ( $client == $server )
{
# Принять новое подключение
$client = $server->accept();
$select->add( $client );
nonblock( $client );
}
else
{
# Прочитать данные
$data = '';
$rv = $client->recv( $data, POSIX::BUFSIZ, 0 );

unless( defined( $rv ) && length $data )
{
# Это должен быть конец файла, поэтому закрываем клиента
delete $inbuffer{$client};
delete $outbuffer{$client};
delete $ready{$client};

$select->remove( $client );
close $client;
next;
}

$inbuffer{$client} .= $data;

# Проверить, говорят ли данные в буфере или только что прочитанные
# данные о наличии полного запроса, ожидающего выполнения. Если да -
# заполнить $ready{$client} запросами, ожидающими обработки.
while( $inbuffer{$client} =~ s/(.*\n)// ) { push( @{$ready{$client}}, $1 ) }
}
}

# Есть ли полные запросы для обработки?
foreach $client ( keys %ready ) { handle( $client ); }

# Сбрасываем буферы?
foreach $client ( $select->can_write( 1 ) )
{
# Пропустить этого слиента, если нам нечего сказать
next unless $outbuffer{$client};

$rv = $client->send( $outbuffer{$client}, 0 );
unless( defined $rv )
{
# Пожаловаться, но следовать дальше
warn "I was told I could write? but I can`t.\n";
next;
}
if ( $rv == length $outbuffer{$client} || $! == POSIX::EWOULDBLOCK )
{
substr( $outbuffer{$client}, 0, $rv ) = '';
delete $outbuffer{$client} unless length $outbuffer{$client};
}
else
{
# Не удалось записать все данные и не из-за блокировки.
# Очистить буферы и следовать дальше.
delete $inbuffer{$client};
delete $outbuffer{$client};
delete $ready{$client};

$select->remove($client);
close($client);
next;
}
}
}

# handle( $socket ) обрабатывает все необработанные запросы
# для клиента $client
sub handle
{
# Запрос находится в $ready{$client}
# Отправить вывод в $outbuffer{$client}
my $client = shift;
my $request;

foreach $request ( @{$ready{$client}} )
{
print "\nrequest=".$request if ( $debug == 1 );

if ( $request =~ /^testRID/ )
{
my $open_client = "";
foreach my $kod ( keys %CLRULE )
{ $open_client .= $open_client eq "" ? $kod : " ".$kod;
($CLRULE_ID{$kod} ne "")?$open_client.="-".$CLRULE_ID{$kod}:"";
}
$outbuffer{$client} .= $open_client."\n";
}
elsif ( $request =~ /^test/ )
{
my $open_client = "";
foreach my $kod ( keys %CLRULE )
{ $open_client .= $open_client eq "" ? $kod : " ".$kod;}
$outbuffer{$client} .= $open_client."\n";
}
elsif ( $request =~ /^add\t([0-9]+)\t(.*)/ )
{
my ($skip,$rid)=split /RULE/,$2;
print "\n=rule".$rid."\n" if ( $debug == 1 );
my ($kod, $rule) = ($1, $2);
&delete_rule( $kod ) if ( exists $CLRULE{$kod} );
&add_rule( $kod, $rule,$rid ) if ( !exists $CLRULE{$kod} );
}
elsif ( $request =~ /^remove\t([0-9]+)/ )
{
&delete_rule( $1 ) if ( exists $CLRULE{$1} );
}
}

delete $ready{$client};
}

# nonblock( $socket ) переводит сокет в неблокирующий режим
sub nonblock
{
my $socket = shift;
my $flags;

$flags = fcntl( $socket, F_GETFL, 0 )
or die "Can`t get flags for socket: $!\n";
fcntl( $socket, F_SETFL, $flags | O_NONBLOCK )
or die "Can`t make socket nonblocking: $!\n";
}

sub add_rule
{
my $kod = $_[0];
my $rule = $_[1];
my $rid = $_[2];
my %N = ();
my %P = ();

$CLRULE{$kod} = $rule;
$CLRULE_ID{$kod} = $rid;

while ( $rule =~ /\{N([AB0-9]+)\}/ )
{
my $n = $1;
my $i = $rule_start - 1;
my $j = 0;
while( 1 )
{
while( 1 )
{
$i++;
last if ( !exists $USERULEN{$i} );
}
$j++;
last if ( $j == $n );
last if ( $n == 0 );
}
$USERULEN{$i} = $kod;
$N{$n} = $i;
$rule =~ s/\{N$n\}/$N{$n}/g;
}

while ( $rule =~ /\{P([AB0-9]+)\}/ )
{
my $p = $1;
my $i = $pipe_start - 1;
my $j = 0;
while( 1 )
{
while( 1 )
{
$i++;
last if ( !exists $USEPIPEN{$i} );
}
$j++;
last if ( $j == $p );
last if ( $p == 0 );
}
$USEPIPEN{$i} = $kod;
$P{$p} = $i;
$rule =~ s/\{P$p\}/$P{$p}/g;
}

foreach my $i ( keys %N ) { $CLUSERULEN{$kod} .= exists $CLUSERULEN{$kod} && $CLUSERULEN{$kod} ne "" ? " ".$N{$i} : $N{$i}; }
foreach my $i ( keys %P ) { $CLUSEPIPEN{$kod} .= exists $CLUSEPIPEN{$kod} && $CLUSEPIPEN{$kod} ne "" ? " ".$P{$i} : $P{$i}; }

$rule =~ s/\|pipe/; \/sbin\/ipfw -q pipe /g;
$rule =~ s/\|add ([0-9]+)/; \/sbin\/ipfw -q add $1 set $set /g;
$rule =~ s/^pipe/\/sbin\/ipfw -q pipe /g;
$rule =~ s/^add ([0-9]+)/\/sbin\/ipfw -q add $1 set $set /g;
# print "$ipfw -q $rule\n" if ( $debug == 1 );
# $err = `$ipfw -q $rule`;
print "$rule\n" if ( $debug == 1 );
$err = `$rule`;

}

sub delete_rule
{
my $kod = $_[0];

if ( exists $CLRULE{$kod} )
{
my @N = split( / /, $CLUSERULEN{$kod} );

foreach my $i ( @N )
{
print "$ipfw delete $i\n" if ( $debug == 1 );
$err = `$ipfw delete $i`;
delete $USERULEN{$i};
}

my @P = split( / /, $CLUSEPIPEN{$kod} );

foreach my $i ( @P )
{
print "$ipfw pipe delete $i\n" if ( $debug == 1 );
$err = `$ipfw pipe delete $i`;
delete $USEPIPEN{$i};
}

delete $CLUSERULEN{$kod};
delete $CLUSEPIPEN{$kod};
delete $CLRULE_ID{$kod};
delete $CLRULE{$kod};
}
}


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 02 апр 2010, 17:15 
Не в сети
Разработчик

Зарегистрирован: 08 ноя 2007, 01:05
Сообщения: 8343
Откуда: Уфа
Карма: 238
если не сложно, то выложите, пожалуйста в wiki


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 02 апр 2010, 17:27 
Не в сети

Зарегистрирован: 16 ноя 2007, 16:11
Сообщения: 829
Карма: 49
Погоняем с месяц на "боевых" и обязательно выложим на вики.
Сюда запостили после стендовых тестов для "замечаний и предложений".


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 06 апр 2010, 13:41 
Не в сети

Зарегистрирован: 16 ноя 2007, 16:11
Сообщения: 829
Карма: 49
Вылез косяк с пустыми строками.
Нужно добавить
Код:
$rule =~ s/\|/;/g;


к
Код:
$rule =~ s/\|pipe/; \/sbin\/ipfw -q pipe /g;
 $rule =~ s/\|add ([0-9]+)/; \/sbin\/ipfw -q add $1 set $set /g;
 $rule =~ s/^pipe/\/sbin\/ipfw -q pipe /g;
 $rule =~ s/^add ([0-9]+)/\/sbin\/ipfw -q add $1 set $set /g;


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 22 июн 2010, 12:15 
Не в сети

Зарегистрирован: 16 ноя 2007, 16:11
Сообщения: 829
Карма: 49
Добавлено в wiki.
http://wiki.bgbilling.ru/index.php/FreeBSD_manad,_понимающий_изменения_правил_в_тарифах


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 22 июн 2010, 12:19 
Не в сети

Зарегистрирован: 17 ноя 2009, 08:47
Сообщения: 215
Откуда: krsn
Карма: 48
т.е. если я клиенту тарифный план поменяю, ваш скрипт автоматом на манаде правила изменит?

_________________
Изображение
using billingClient.BGB 4.6;
using server.Ubuntu server 9.10;
using server.Java "1.6.0_15";
using client.Ubuntu 10.04;


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 22 июн 2010, 12:35 
Не в сети

Зарегистрирован: 16 ноя 2007, 16:11
Сообщения: 829
Карма: 49
По крайней мере, должен отреагировать на любое изменение RuleId. В наших новых тарифных планах работает уже пару месяцев.
Разумеется, скрипт и манад должны быть изменены до смены тарифного плана, что бы в манад ушла информация о старом RuleId.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 22 июн 2010, 12:47 
Не в сети

Зарегистрирован: 17 ноя 2009, 08:47
Сообщения: 215
Откуда: krsn
Карма: 48
круто. надо будет узнать, на чем у нас манад крутитса :D

_________________
Изображение
using billingClient.BGB 4.6;
using server.Ubuntu server 9.10;
using server.Java "1.6.0_15";
using client.Ubuntu 10.04;


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 07 дек 2011, 11:37 
Не в сети
Аватара пользователя

Зарегистрирован: 14 окт 2011, 14:38
Сообщения: 122
Карма: 0
vdd писал(а):
После полного перехода на новый manad


А что подразумевается под старым и новым манадом? :?:


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 13 дек 2011, 17:03 
Не в сети

Зарегистрирован: 16 ноя 2007, 16:11
Сообщения: 829
Карма: 49
Под старым подразумевался ipfw manad без поддержки смены правил.


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 12 ] 

Часовой пояс: UTC + 5 часов [ Летнее время ]


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  
POWERED_BY
Русская поддержка phpBB
[ Time : 0.051s | 40 Queries | GZIP : On ]