LCR-AGI
A FastAGI interface to a Least Cost Routing engine for Asterisk
# This file is part of LCR-AGI.
#
# LCR-AGI is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# LCR-AGI is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with LCR-AGI. If not, see .
#
# Copyright (C) 2009 Alkaloid Networks LLC
# Author: Ben Klang
# Author: Bryan Rite
# Alkaloid Networks LLC - http://projects.alkaloid.net
# $Id$
!! NOTE !!
Please read this file all the way to the end. If you are using this system
you are likely trying to save money on telephone calls. Getting least cost
routing correct can be tricky, and getting it wrong can be expensive!
This software makes several assumptions which are outlined below.
!! NOTE !!
If you have any questions on the software please feel free to contact the
primary author, Ben Klang No support is promised, guaranteed
or otherwise implied.
Commercial support for this application, and other technology needs, can be
purchased through the author's company, Verendus.
Please visit http://www.verendus.com for information.
Required libraries:
Library name - tested version
* rubygems - 1.3.1 (all of the following can be installed as gems)
* activesupport - 2.3.2 (ragi dependency - not automatically installed!)
* ragi - 1.0.1
* dbi - 0.1.1
* dbd-mysql
* mysql - 2.7.5 (dependency of dbd-mysql)
* getopt - 1.3.8
* parseexcel - 0.5.2 (Only needed for NANPA Area Codes right now)
Assumptions:
This library was written in the United States by an American citizen for use
with US-based callers and callees. As such it tends to view the telephony world
through the lense of an American. At the time of this release there is much
logic given to the routing of domestic US calls, including inter- vs. intra-
state rate variances. Since the authors are not particularly aware of non-US
and non-NANPA practices, this engine may be of limited use outside of
the US and North America.
However, that does not mean we want it to stay that way! Contributions and
enhancements, especially those that improve international routing, are
welcomed and appreciated.
Technical Assumptions:
All telephone numbers fed into this LCR engine are expected to be in the
form of:
This includes both the caller and the callee telephone numbers.
DO NOT pass in Caller ID name information, only the actual telephone number.
Examples:
For the United States this would be similar to:
14044754840
(Note the 10 digits plus the "1" country code).
For an international number this would be
442078878000
!!NOTE!!
There is no '+', no international dialing prefix (such as '011') nor any other
punctuation or spaces. Failure to format the numbers as above WILL result in
unexpected and suboptimal (expensive!) routing decisions. You have been warned!
!!NOTE!!
Installation:
Start by making sure you have recent versions of the libraries listed above.
All of the above libraries can be installed with Ruby Gem. For example:
user@host$ sudo gem install ragi
After all libraries are installed, the next step is to set up the database.
Create a database and populate it with the two tables defined in the file
"lcr-agi.sql", a part of this distribution. Instructions on importing that
SQL file can be found in the documentation for your database engine of choice.
LCR-AGI is only developed and tested with MySQL.
Once the database is created you will need to customize the file "config.rb".
This package includes several programs. All depend on a working config.rb.
You must tailor the distributed config.rb to meet your needs before continuing.
Documentation on that configuration file can be found in its comments.
Programs:
This package contains several programs:
lcr-import.rb
This program is responsible for importing route cost information into the
database. LCR-AGI ships with two importers by default: one for Gafachi
(http://www.gafachi.com) and one for VoIPJet (http://www.voipjet.com).
lcr-query.rb
This is a simple script to test call routes by reading two or three whitespace-
delimited fields from STDIN. The first two fields must be the caller's
telephone number and the callee's telephone number respectively. The third
field is optional and is expected to be the call duration in MM:SS format.
After reading each line, lcr-query will look up the route from the database
and print out the selected route. If a call duration was provided it will also
calculate the cost of the call on the selected route. On EOF it will print the total number of routes researched and the total cost, if available.
fastagi.rb
This is a generic server for the RAGI library. When invoked it will set up
a listener on the FastAGI port (tcp/4573) and accept incoming FastAGI
connections. This server is configured to route unspecified AGI requests to
the 'LCR' handler and its 'getLowestCostRoute' method. Other handlers and
methods may be added to the 'handlers/' directory but is beyond the scope of
this document.
nanpaxls.rb
This program will read the Excel spreadsheet published by NANPA and import all
NANPA area codes with their respective locations to the database. This
information is used to determine whether a call qualifies as intra- or inter-
state for domestic US telephone calls.
Developing New Route Cost Parsers
The importer is a simple class that exposes a single method: "getrates()".
This method will be called as a block so it must yield back a simple array with
three elements:
1) A call source. This must be one of "any", "intrastate", "interstate", or
"international". If a carrier uses a call source other than "any" for any
given destination it MUST NOT provide an "any" route to that destinion.
Other destinations from that carrier may use the "any" source.
2) A destination. This is a variable length field and can be anything from a
single digit all the way up to a full telephone number. LCR-AGI will always
select the most-specific match from each carrier to determine its effective
rate for the call.
3) A cost. This is currently limited to 6 decimal places of precision.
For example:
GOOD:
['any', 1404, 0.0150]
['intrastate', 1678, 0.0150]
['interstate', 1678, 0.0145]
BAD:
['any', 1404, 0.0150]
['intrastate', 1404, 0.0250]
!! Note the conflict between "any" and "intrastate" for the
!! same destination !!
This information can be generated by any source, but it must be yield()ed one
array at a time to be entered into the database. A simple example routing
all Atlanta area codes down a fixed-price line ($0.00 per minute usage)
can be found in 'routes/Example.rb'.
Most carriers publish a rate table in tab-delimited or csv-delimited format.
Examples on the parsing and generation can be found in the VoIPJet and Gafachi
parsers. Gafachi's parser is actually two-in-one: they publish a fairly
complicated rate structure with different tiers and costs depending on the call
source. In addition to the tiered domestic US rates they publish a separate
International rate table. Both are handled by this class.