Upgrade 3CX to v18 and get it hosted free!

Application LCDial

Application LCDial() – Least Cost Routing / FailOver application for Asterisk 1.4 and 1.6

Description

LCDial is a very powerful and versatile solution for Least Cost Routing/FailOver which gets information about call routing from 2 tables stored into a MySQL database.
Since release 770, it permits to specify an argument that established which paths the outgoing call should take: this is a very important feature for PBX that is shared by different companies.

The source code for the application with some examples and an automatic installation script is available for free, released under GNU GPL license.

The MySQL database should contain 2 tables:

  • lcdial_providers, within the provider name, dial string, and a flag to enable/disable it
  • lcdial_rates, within the regexp prefix, provider name, rate, and a comment

In this way is very very simple to compile the LCR database by hand, using phpmyadmin or other tool: you can insert a complete lcdial_rates table with several provider costs, and enable it into lcdial_providers table only the available providers.

How does it do

  • In extensions.conf you need to dial a call using LCDial() instead of Dial() application
  • table lcdial_rates will be scan to extract all prefixes which match (using REGEXP) to the destination number
  • for each provider, if more than one record match, the longest will be taken (i.e. calling 0039328 matches both ^0039 and ^00393, so only the rate corresponding to ^00393 will be taken into account)
  • only enabled provider will be evaluated: this feature permits to manage least cost routing using a long lcdial_rates table with the costs for every provider and enabling into lcdial_providers only the telephony provider really accessible (both VoIP, PSTN, Mobile)
  • provider will be sorted from the cheapest to the most expensive
  • Dial() application will be invoked for the #1 enabled provider (the cheapest)
  • if the call will be answered, at the end of the application return; if the call will not be answered, the Dial() application will be invoked for the #2 enabled provider (less cheaper than #1), and so on.

As you can see, in this way the LCDial() application provides a FailOver mechanism so if provider #1 does not work, the 2nd one will be tried automatically, then the 3rd one, and so on.

Tables structure

The lcdial_providers define the list of providers. Look at the enabled field: freevoip is disabled (enabled=0), company 1 uses fastweb, wind-leonardo, voipvoice, voipvoice_backup (enabled=1), company2 uses fastweb and voipvoice (enabled=2).

lcdial_providers table structure/example
id provider dialstr enabled ratename ratemul
1 fastweb Zap/g1/%s 1 fastweb 1
2 freevoip IAX2/freevoip/%s 0 freevoip 1
3 wind-leonardo SIP/%s@100 1 wind-leonardo 1
4 voipvoice IAX2/voipvoice1/%s 1 voipvoice 1
5 voipvoice_backup IAX2/voipvoice2/%s 1 voipvoice 1.2
6 company2_fastweb Zap/g2/%s 2 fastweb 1
7 company2_voipvoice IAX2/voipvoice3/%s 2 voipvoice 1

 

lcdial_rates table structure/example
prefix ratename rate note
^005521 freevoip 0.03 brazil rio de janeiro
^32……. wind-leonardo 0 wind cellulars
^3[3469]……. wind-leonardo 0.06 italian cellulars (not wind)

Using LCDial() on PBX for a single company (r770 o above)


  [trunknational]
  ; National context accessed through trunk
  exten => _0ZXXX.,1,NoOp(National outcall)
  exten => _0ZXXX.,n,LCDial(1,${EXTEN},90)
  exten => _0ZXXX.,n,Hangup

Using LCDial() on PBX for 3 different companies (r770 or above)

This feature is useful for PBX used by more than one company, so you can define that users 11,12,13,14,15 calls through the providers where the enabled field (in providers table) is 1, while users 51,52,53,54 calls through the providers which has enabled=2, and users 61,62,63 calls through the providers which has enabled=3
This can be done for up to 10 routes, between 1 and 9.
If the first parameter is not specified, 1 is assumed.


  LCDIAL_PATH_2=51,52,53,54
  LCDIAL_PATH_3=61,62,63

  [macro-LCDialSetPath]
  ; set the variable "LCDialPath" (first argument of LCDial) to select
  ; the path for the outgoing call
  exten => s,1,Set(LCDialPath=1)
  ;exten => s,n,MacroExit
  ; select the path
  exten => s,n,GotoIf($["a${LCDIAL_PATH_2}"="a"]?:20)
  ; LCDIAL_PATH_2 exists: check that the extension that originate the call is inside LCDIAL_PATH_2
  exten => s,n,MacroExit
  exten => s,20,GotoIf(${REGEX("${CALLERID(number)}" ${LCDIAL_PATH_2})}?:40)
  exten => s,n,Set(LCDialPath=2)
  exten => s,n,MacroExit
  exten => s,20,GotoIf(${REGEX("${CALLERID(number)}" ${LCDIAL_PATH_3})}?:60)
  exten => s,n,Set(LCDialPath=3)
  exten => s,n,MacroExit
  exten => 60,MacroExit

  [trunknational]
  ; National context accessed through trunk
  exten => _0ZXXX.,1,NoOp(National outcall)
  exten => _0ZXXX.,n,Macro(LCDialSetPath) ; set the path to call to (enable=1 or enable=2 or...)
  exten => _0ZXXX.,n,LCDial(${LCDialPath},${EXTEN},90)
  exten => _0ZXXX.,n,Hangup


Original implementation of LCDial(), by Wolfgang Pichler

Synopsis

Does a mysql Database lookup to find the cheapest provider for a given destination number, and then it invokes the dial command. If the channel is unavailable then it will fall back to the next configured Provider.

Description

  • LCDial(number to dial,timeout,options,URL) — dial one channel

Parameters:

  • number to dial specifies the number which should get dial.
  • all other options are the same as within the standard Asterisk cmd Dial command (the are directly passed to the dial command)

Return codes

Behaves exactly like Asterisk cmd Dial

Example:
exten => 4000,1,LCDial(${EXTEN},15)

For an up to date LCDial application, please look below at the “Improved version of LCDial() for Asterisk” section!

mysql Database Layout

table description
provider Informations about each Provider (name,id,dialstr,status)
providerdestination Which destinations (countryprefixid) are available with which provider
providerrate The tariffrate for the given provider / destination
countryprefix Table with dial codes
country optional – not really needed – but if you want to have nice names for the countries

 

CREATE TABLE `bit_countryprefix` (
`countryprefixid` int(11) NOT NULL auto_increment,
`prefix` text NOT NULL,
`countrycode` char(3) default NULL,
`subcode` varchar(10) NOT NULL default ”,
PRIMARY KEY (`countryprefixid`)
) TYPE=MyISAM;

CREATE TABLE `bit_provider` (
`providerid` int(11) NOT NULL auto_increment,
`providername` text NOT NULL,
`dialstr` varchar(200) NOT NULL default ”,
`status` tinyint(3) unsigned NOT NULL default ‘0’,
PRIMARY KEY (`providerid`)
) TYPE=MyISAM;

CREATE TABLE `bit_providerdestination` (
`providerdestinationid` int(11) NOT NULL auto_increment,
`countryprefixid` int(11) NOT NULL default ‘0’,
`providerid` int(11) NOT NULL default ‘0’,
PRIMARY KEY (`providerdestinationid`)
) TYPE=MyISAM;

CREATE TABLE `bit_providerrate` (
`providerrateid` int(11) NOT NULL auto_increment,
`providerid` int(11) NOT NULL default ‘0’,
`countryprefixid` int(11) NOT NULL default ‘0’,
`rate` double NOT NULL default ‘0’,
PRIMARY KEY (`providerrateid`)
) TYPE=MyISAM;

CREATE TABLE `bit_country` (
`countrycode` char(3) default NULL,
`countryname` text NOT NULL,
`countryid` int(11) default NULL
) TYPE=MyISAM;

Configuration

LCDial needs a configuration file called lcdial.conf in the standard asterisk configuration directory.
Example Configuration:


[global]
hostname=localhost
dbname=asterisk
user=asterisk
password=asterisk
port=3306

[sql]
getproviders=SELECT providerrate.rate, dialstr, countryprefix.countryprefixid, provider.providerid, provider.providername FROM countryprefix LEFT JOIN providerdestination USING ( countryprefixid ) LEFT JOIN provider USING ( providerid )  LEFT JOIN providerrate ON concat( provider.providerid, countryprefix.countryprefixid ) = concat( providerrate.providerid, providerrate.countryprefixid ) WHERE prefix = substring( '%s', 1, length( prefix ) ) AND provider.status=0  ORDER BY length( prefix ) DESC , providerrate.rate ASC

Compile It

It assumes that the asterisk sources can be found at /usr/src/asterisk, that the asterisk modules directory is at /usr/lib/asterisk/modules and that the asterisk configuration is at /etc/asterisk/.
For compiling it you need to have already installed asterisk 😉 – and the mysql client library and header files.
From asterisk stable to asterisk cvs head the channel structure has changed a little bit – so if you want to compile against asterisk stable then you have to comment this “CFLAGS+=-DUSE_CVS” line to get it to compile (else you would get an error like “error: structure has no member named `cid'”

Help

If you are having trouble getting the application up and running and need professional help, feel free to drop us a line at [email protected]

Management Interface

If you are looking for a management frontend or a turn-key-solution please get in touch with us: [email protected]


See also


Asterisk | Asterisk cmd Dial


Article Reviews

Write a Review

Your email address will not be published. Required fields are marked *

Required Field. Minimum 5 characters.

Required Field. Minimum 5 characters, maximum 50.

Required field.There is an error with this field.

Required Field.

This site uses Akismet to reduce spam. Learn how your comment data is processed.

There are no reviews for this article. Be the first one to write a review.

Related Posts:

Get 3CX - Absolutely Free!
Link up your team and customers Phone System Live Chat Video Conferencing

Hosted or Self-managed. Up to 10 users free forever. No credit card. Try risk free.

3CX
A 3CX Account with that email already exists. You will be redirected to the Customer Portal to sign in or reset your password if you've forgotten it.