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.