login | register
Wed 08 of Oct, 2008 [07:15 UTC]

voip-info.org

Discuss [7] History

Asterisk addon rate-engine

Created by: oej,Last modification on Sun 11 of Jun, 2006 [01:27 UTC] by mfedyk

Rate engine for Asterisk

Adds a new application:

RouteCall
Do cost based routing of a call and set call time limit

Description

 RouteCall(extension[|flags])

Does Least Cost Routing of a call, and sets an absolute timeout on call length based on customers credit worthiness.
If a route is found, a dialstring suitable for use with the Dial application is created in the variable ${DESTINATIONnn}, to be used as
 Dial(${DESTINATIONnn}) 
where 'nn' is a number from 1 and up, with the route in ${DESTINATION1} being the lowest-cost route found, the route in ${DESTINATION2} being the next lowest rate found and so on. An AbsoluteTimeout limit may also be set for the call.

Return codes

If there exists a priority n + 101, and no route could be found, then the channel will be set up to continue at that priority level.
Otherwise, Always returns 0.


News

Work has started to port this to Asterisk 1.2. It seems the original developer has lost interest, so I, Roy Sigurd Karlsbakk, have taken up the work. There'll be new versions of the code launched on my website irregularly as new bugs are introduced or perhaps fixed...


From the README:


This is a module for The Asterisk Open Source PBX. It is currently licensed under the GPL.

To build and install, you must already have Asterisk and MySQL devel packages installed on your system. The sample configuration file can be installed by executing "make samples". You will need to set up the database schema manually — a sample schema that is suitable for use with MySQL has been included.

You must also have PCRE — a Perl Regular Expression package for C installed. On RedHat this is accomplished by installing the pcre and pcre-devel RPMs.

The module will install itself as both an application that will do Least Cost Routing, and a CDR logger that will log a call with cost calculated based on the actual route used.

Fixes and additions to the code are welcomed, but we do require that such contributed code be disclaimed, as we will be providing this module under a dual license. For a disclaimer form, see the file "DISCLAIMER" in this directory. The disclaimer must be either faxed to +47 55987201 or mailed to:

       Disclaimers
       Troll Phone Networks AS
       Kokstaddalen 4  
       NO-5257  KOKSTAD
       Norway

Either of these will be fine, but a dislaimer form must be on file before we can accept any patches or enhancements.

Yes, this code uses alloca(). Yes, on some systems the man page for alloca(3) says "Its use is discouraged." Deal with it.



See also



Go back to Asterisk


Comments

Comments Filter
222

333Re: using rate engine

by , Tuesday 15 of February, 2005 [13:50:57 UTC]
Hm i just noticed that if you want to use the agi.. you have to watch out as everything in square brakets are displayed as linik
so if you want to use ti you have to reverse this.. so in function write_rates
change the set_var('DESTINATION'.$i,$rate"destination");
and so on .. to $rate and then the square braket and then "destination" squarebraket
...
this should help i think

222

333Still nothing

by , Saturday 05 of February, 2005 [18:16:04 UTC]
This didn't work for me either, even with the AGI in place still wasn't getting the least cost being returned.

My C knowledge isn't good 'nuff to work out why but I think it's something to do with it not correctly working out which is actually cheapest and therefore just throwing the records into memory in the order they are read from the database.

Changing the SQL statement on line 1748 in file 'rate_engine.c' the one before 'table_cost);' from ....

'FROM %s'

to ....

'FROM %s ORDER BY prefix, (startcost + periodcost) / (firstperiod + periods) DESC'

seems to make it work!!!!

Perhaps not the most idea way or working out the cheapest but works for my purposes.
222

333....sorry forgot the extensions.conf

by , Sunday 16 of January, 2005 [17:51:18 UTC]
oh i will just include that here.
(:cool:)
macro-dial-lcr
; ARG1 = number to dial
; ARG2 = timeout value
; ARG3 = flag determines if hangup or return on no answer
; HR = hangup and return (default)
; RT = return without hangup (must set)
;
exten => s,1,SetGlobalVar(FOUNDME=ANSWER)
exten => s,2,GotoIf($${LEN(${ARG1})} = 10?2
4)
exten => s,2,SetVar(NumToDial=${ARG1})
exten => s,3,RouteCall(${NumToDial})
;exten => s,6,Goto(s,6)
;
exten => s,4,NoOp(${ISO})
;exten => s,5,NoOp(${DESTINATION1})
exten => s,6,SetGlobalVar(FOUNDME=${DIALSTATUS})
exten => s,5,NoOp(${DESTINATION1} ${PERIODCOST1} "vs" ${DESTINATION2} ${PERIODCOST2})
exten => s,7,AGI(sort-trunksphp.agi);
exten => s,8,NoOp(${DESTINATION1} ${ECOST1} "vs" ${DESTINATION2} ${ECOST2})
exten => s,9,Noop
exten => s,10,Dial(${DESTINATION1},${ARG2})
exten => s,11,SetGlobalVar(FOUNDME=${DIALSTATUS})
exten => s,12,GotoIf($${DIALSTATUS} = CHANUNAVAIL?9:20)
;
exten => s,13,SetGlobalVar(FOUNDME=ANSWER)
exten => s,14,Dial(${DESTINATIION2},${ARG2})
exten => s,15,SetGlobalVar(FOUNDME=${DIALSTATUS})


exten => s,16,GotoIf($${DIALSTATUS} = CHANUNAVAIL?13:20)
;
exten => s,17,SetGlobalVar(FOUNDME=ANSWER)
exten => s,18,Dial(${DESTINATIION3},${ARG2})
exten => s,19,SetGlobalVar(FOUNDME=${DIALSTATUS})
exten => s,20,GotoIf($${DIALSTATUS} = CHANUNAVAIL?18:20)
;
exten => s,21,SetGlobalVar(FOUNDME=ANSWER)
exten => s,22,Dial(${DESTINATIION4},${ARG2})
exten => s,23,SetGlobalVar(FOUNDME=${DIALSTATUS})
exten => s,24,Goto(s-${DIALSTATUS},1)



and in the dial plan ...
exten => _00XX.,1,macro(dial-lcr,${EXTEN}, ${LONGTIMEOUT})
exten => _011XX.,1,macro(dial-lcr,00${EXTEN:3}, ${LONGTIMEOUT})
222

333using rate engine

by , Sunday 16 of January, 2005 [17:47:36 UTC]
so after some closer tlook at this addon i got it finally to work. Note that this won't sort (:exclaim:)
the rates for you , you have to write an script which would do that.
here is my php agi (it took me a full day fo figure out that this actually don't sort


require "phpagi.php";
//include('/etc/asterisk/config.php');
ob_implicit_flush(true);
global  $agi;
$agi = new AGI();
 set_time_limit(5);

 error_reporting(0);
//L:wq$in = fopen("php://stdin","r");

$debug=false;

 $avglen=300;

function load_rates() {
global $agi;
$j=0;
for ($i=1 ; $iget_var('DESTINATION'.$i);

$firstlen=$agi->get_var('FIRSTLEN'.$i);

$restlen=$agi->get_var('RESTLEN'.$i);
$startcost=$agi->get_var('STARTCOST'.$i);
$periodcost=$agi->get_var('PERIODCOST'.$i);
$trialcost=$agi->get_var('TRIALCOST'.$i);

 if (isset($destination) ) {
$j ++;
  $ecost = calcaveragecall($firstlen, $restlen,$startcost,$periodcost);

$tmp = array("destination"=>$destination,"firstlen"=>$firstlen,"restlen"=>$restlen,"startcost"=>$startcost,"periodcost"=>$periodcost,"trialcost"=>$trialcost,"ecost"=>$ecost);
 $rates$j = $tmp;

$agi->con_print_r($tmp);
}
}

return $rates;
}



 function calcaveragecall($firstlen, $restlen,$startcost,$periodcost){
global $avglen,$agi;

  if ($firstlen >= $avglen ){

      $estimatecost = $firstlen/$restlen * $periodecost;}
 else{
   $estimatecost = ($avglen/$restlen) * $periodcost;


}
$estimatecost += $startcost;
$agi->con_print_r($estimatecost);
   return $estimatecost;
}

function write($line) {
  global $debug, $stdlog,$agi;
  if ($debug) fputs($stdlog, "write: $line\n");
  echo $line."\n";
}

 function write_rates($rates){
 global $agi;
 $agi->con_print_r($rates);
 $i=0;

 foreach ($rates as $rate){
 $i++;
 $agi->set_var('DESTINATION'.$i,$rate"destination");
$agi->set_var('FIRSTLEN'.$i,$rate"firstlen");
$agi->set_var('RESTLEN'.$i,$rate"restlen");
$agi->set_var('STARTCOST'.$i,$rate"startcost");
$agi->set_var('PERIODCOST'.$i,$rate"periodcost");
$agi->set_var('TRIALCOST'.$i,$rate"trialcost");
$agi->set_var('ECOST'.$i,$rate"ecost");

}


 }
 function read() {
 global $in, $debug, $stdlog;
 $input = str_replace("\n", "", fgets($in, 4096));
 if ($debug) fputs($stdlog, "read: $input\n");
 return $input;
}



function array_sort($array, $key)
{
  for ($i = 1; $i con_print_r($sortedrates);
 write_rates($sortedrates);

exit;

it is not really a nice script but it will work. any updates welcome
next you have to fill the database
so for using for instance voipjet



| route_id | provider_id | technology | peer | pattern | substitute | description |

| 1 | 3 | IAX2 | XXX@voipjet | 00 | 011$1 | try |

which would subtitute 00 with 011 and adds IAX2/XXX@voipjet/011
not tha you would have to add adifferent line to egress if you wanna
dial to the us .

next an exampel for the rate feed

| rate_id | route_id | iso | type | country | extra | prefix | active_date | expires_date | firstperiod | periods | startcost | periodcost | trialcost |

| 9 | 9 | 1 | | usa alaska | | 001907 | 0000-00-00 | 0000-00-00 | 0 | 1 | 2980 | 0 | 0 |
| 10 | 9 | 1 | | usa hawaii | | 001808 | 0000-00-00 | 0000-00-00 | 0 | 1 | 2980 | 0 | 0 |
| 95 | 9 | 1 | | usa proper | | 001 | 0000-00-00 | 0000-00-00 | 0 | 1 | 2980 | 28 | 0 |
| 2594 | 3 | 1 | | usa alaska | | 001907 | 0000-00-00 | 0000-00-00 | 6 | 6 | 0 | 197 | 0 |
| 2595 | 3 | 1 | | usa hawaii | | 001808 | 0000-00-00 | 0000-00-00 | 6 | 6 | 0 | 161 | 0 |
| 2596 | 3 | 1 | | usa proper | | 001 | 0000-00-00 | 0000-00-00 | 6 | 6 | 0 | 130 | 0 |

so for the route_id you would have to use the key from the egress table.
that will make it work
the extra column is actually for the identifier mobile or proper but i still have not done the work . to make that happen
so maybe this will help you save some time .. (:biggrin:)
i would have appreciate it..
      kyra






222

333DOes this work?

by , Saturday 18 of December, 2004 [03:56:33 UTC]
I know that many people have tried this, but has anyone ever made it work?
222

333Examples for rate-engine?

by Ber5erker, Monday 25 of October, 2004 [14:57:17 UTC]
Have anybody an example for rate-engine e.g. extensions.conf with database-entrys?
222

333PostgreSQL

by , Sunday 23 of May, 2004 [07:51:09 UTC]
I'd like to see a PostgreSQL version of this.