Difference between revisions of "Provider AGI script"
(19 intermediate revisions by the same user not shown) | |||
Line 6: | Line 6: | ||
<br> | <br> | ||
= What is it for? = | = What is it for? = | ||
This feature allows to execute custom script which tells MOR to either '''allow''' | This feature allows to execute custom script which tells MOR to either '''allow'''/'''reject''' call to specific Provider or '''add suffix''' to destination number when dialing through specific Provider. This is useful if you require some additional number/Provider validation that is not implemented in MOR. | ||
= How does it work? = | = How does it work? = | ||
If this feature is enabled then MOR Core executes custom AGI script. Script is executed just before dial command of each Provider (after all other validations are done by Core). MOR Core passes these variables to script:<br/> | If this feature is enabled then MOR Core executes custom AGI script. Script is executed just before dial command of each Provider (after all other validations are done by Core). MOR Core passes these variables to script:<br/> | ||
Line 16: | Line 17: | ||
* '''MOR_AGI_RUN_TIME''' - if your script calculates run time, then you can set elapsed time to this variable. Variable is optional. | * '''MOR_AGI_RUN_TIME''' - if your script calculates run time, then you can set elapsed time to this variable. Variable is optional. | ||
* '''MOR_AGI_TIMEOUT''' - in case your script has timeout prevention and you want to reject call on timeout, you may set this variable value to 1 and then core will reject call when AGI script timeouts. Variable is optional. | * '''MOR_AGI_TIMEOUT''' - in case your script has timeout prevention and you want to reject call on timeout, you may set this variable value to 1 and then core will reject call when AGI script timeouts. Variable is optional. | ||
* '''MOR_AGI_DESTINATION_SUFFIX''' - if this variable is set, then value will be added to destination number. For example if original destination number is '''370123456''' and '''MOR_AGI_DESTINATION_SUFFIX''' is set to ''';cic=123''', then MOR will send '''370123456;cic=123''' as destination number to Provider. Variable is optional. | |||
As you can see, call flow can be controlled by using variables '''MOR_AGI_STATUS''' and '''MOR_AGI_TIMEOUT'''. Also note that variable '''MOR_AGI_STATUS''' is '''required''' and call will be rejected if this variable is missing (or value is not 1). | As you can see, call flow can be controlled by using variables '''MOR_AGI_STATUS''' and '''MOR_AGI_TIMEOUT'''. Also note that variable '''MOR_AGI_STATUS''' is '''required''' and call will be rejected if this variable is missing (or value is not 1).<br/> | ||
If AGI script returns MOR_AGI_STATUS = 0 and rejects call, then other Providers will not be checked. Call will be terminated completely. Following hangupcause codes are assosiated with this feature:<br> | If AGI script returns MOR_AGI_STATUS = 0 and this way rejects call, then other Providers will not be checked. Call will be terminated completely. Following hangupcause codes are assosiated with this feature:<br> | ||
* 266 Provider skipped because AGI script returned timeout error | * 266 Provider skipped because AGI script returned timeout error | ||
* 267 Provider skipped because AGI script rejected this provider (AGI script status 0) | * 267 Provider skipped because AGI script rejected this provider (AGI script status 0) | ||
= How to enable this feature = | |||
For this feature to work, you need to enable 'Execute AGI script' in selected [http://wiki.kolmisoft.com/index.php/Providers#Advanced Provider] settings. In addition, you have to set path to AGI script in [http://wiki.kolmisoft.com/index.php/Mor.conf mor.conf] configuration file (variable '''provider_agi_script_path'''). | |||
=HLR number lookup example script= | |||
Asterisk AGI can be used in many programming languages. In this example we will use PHP AGI library (http://phpagi.sourceforge.net, look for phpagi-2.20.tgz or newer).<br/> | |||
Let's build AGI script that checks number availability in HLR database.<br/><br/> | |||
'''Note that Kolmisoft does not provide support for custom AGI scripts and these scripts should be developed by MOR administrator! Also, HLR services are paid and Kolmisoft does not provide HLR service accounts.'''<br/><br/> | |||
HLR number lookup PHP example script:<br/> | |||
<pre> | |||
#!/usr/bin/php -q | |||
<?php | |||
// These values should be set by admin | |||
define("HLR_PASSWORD", "YOUR_PASSWORD"); | |||
define("HLR_API_KEY", "YOUR_API"); | |||
define("TIMEOUT_SECONDS", "4"); | |||
// These lines are used to calculate script run time | |||
declare(ticks = 1); | |||
$start = microtime(true); | |||
if (function_exists('pcntl_signal')) { | |||
pcntl_signal(SIGHUP, SIG_IGN); | |||
} | |||
error_reporting(E_ALL ^ (E_NOTICE | E_WARNING)); | |||
// Include Asterisk PHP AGI library (http://phpagi.sourceforge.net) | |||
include("/var/lib/asterisk/agi-bin/HLR/lib/phpagi/phpagi.php"); | |||
// Function to loopuk number in HLR database | |||
function lookupCarrier(&$response, &$status, $msisdn, &$timeout_state) { | |||
// Set URL | |||
$url = "https://www.hlrlookup.com/api/hlr/?apikey=" . HLR_API_KEY . "&password=" . HLR_PASSWORD . "&msisdn=$msisdn"; | |||
$ch = curl_init(); | |||
curl_setopt($ch, CURLOPT_URL, $url); | |||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); | |||
curl_setopt($ch, CURLOPT_TIMEOUT, TIMEOUT_SECONDS); | |||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, TIMEOUT_SECONDS); | |||
// Send request and get response | |||
$response = curl_exec($ch); | |||
// Check if response is received | |||
if (strlen($response)) { | |||
// If we got response, then connection did not timeout | |||
$timeout_state = 0; | |||
// Parse response | |||
$decoded_response = json_decode($response); | |||
// Get value of 'error_text' variable | |||
if (isset($decoded_response->{'error_text'})) { | |||
$status = $decoded_response->{'error_text'}; | |||
} | |||
} | |||
// Limit response length | |||
$response = substr($response, 0, 1000); | |||
} | |||
// initialize AGI | |||
$agi = new AGI(); | |||
// Get variable MOR_AGI_DESTINATION (this variable is set by MOR Core) | |||
$msisdn = $agi->get_variable("MOR_AGI_DESTINATION"); | |||
$msisdn = $msisdn['data']; | |||
$response = ''; | |||
$status = ''; | |||
// Set default status | |||
$agi->set_variable("MOR_AGI_STATUS", "0"); | |||
// Set default state | |||
$timeout_state = 1; | |||
// Get status | |||
lookupcarrier($response, $status, $msisdn, $timeout_state); | |||
// Map response status to AGI return status | |||
switch ($status) { | |||
// Set MOR_AGI_STATUS to 1 if error_text contains 'Absent Subscriber' or 'Live' messages | |||
// Call will be accepted on these messages and rejected on any other | |||
case "Absent Subscriber": $agi->set_variable("MOR_AGI_STATUS", "1"); break; | |||
case "Live": $agi->set_variable("MOR_AGI_STATUS", "1"); break; | |||
} | |||
// Calculate elapsed time | |||
$time_elapsed_secs = microtime(true) - $start; | |||
// Set variables back to MOR Core (MOR_AGI_STATUS is already set) | |||
$agi->set_variable("MOR_AGI_RUN_TIME", $time_elapsed_secs); | |||
$agi->set_variable("MOR_AGI_RESPONSE", $response); | |||
$agi->set_variable("MOR_AGI_TIMEOUT", $timeout_state); | |||
return 0; | |||
?> | |||
</pre> | |||
Let's create separate directory for HLR lookup functionality: | |||
<pre>mkdir -p /var/lib/asterisk/agi-bin/HLR</pre> | |||
This directory will include our PHP AGI script and library: | |||
<pre> | |||
[root@dev]# ls -l /var/lib/asterisk/agi-bin/HLR/ | |||
total 8 | |||
-rwxrwxrwx 1 root root 2100 Apr 15 16:10 hlr_carrier_lookup.php | |||
drwxrwxrwx 3 root root 4096 Mar 12 22:24 lib | |||
</pre> | |||
Set executable permissions to our AGI script: | |||
<pre>chmod 777 -R /var/lib/asterisk/agi-bin/HLR/hlr_carrier_lookup.php</pre> | |||
Now that we have placed our script in '''/var/lib/asterisk/agi-bin/HLR/''' and set proper permission, we need to enable Provider AGI script in '''/etc/asterisk/mor.conf''' configuration file. To do so, just set correct path to our AGI script in variable provider_agi_script_path: | |||
<pre>provider_agi_script_path = /var/lib/asterisk/agi-bin/HLR/hlr_carrier_lookup.php</pre> | |||
Now reload MOR core: | |||
<pre>asterisk -rx "mor reload"</pre> | |||
Finally, enable 'Execute AGI script' in selected [http://wiki.kolmisoft.com/index.php/Providers#Advanced Provider] settings. | |||
= Example how to add suffix to destination number = | |||
It is possible to add suffix to destination number when dialing through specific Provider. In this example PHP script we retrieve suffix by MOR_AGI_DESTINATION/MOR_AGI_PROVIDER_ID from some external database. Retrieved suffix is set to MOR_AGI_DESTINATION_SUFFIX and MOR core will use this variable to modify outgoing number. | |||
<pre> | |||
#!/usr/bin/php -q | |||
<?php | |||
// These lines are used to calculate script run time | |||
declare(ticks = 1); | |||
$start = microtime(true); | |||
if (function_exists('pcntl_signal')) { | |||
pcntl_signal(SIGHUP, SIG_IGN); | |||
} | |||
error_reporting(E_ALL ^ (E_NOTICE | E_WARNING)); | |||
// Include Asterisk PHP AGI library (http://phpagi.sourceforge.net) | |||
include("/var/lib/asterisk/agi-bin/HLR/lib/phpagi.php"); | |||
// initialize AGI | |||
$agi = new AGI(); | |||
// Get variable MOR_AGI_DESTINATION (this variable is set by MOR Core) | |||
$destination_number = $agi->get_variable("MOR_AGI_DESTINATION"); | |||
$destination_number = $destination_number['data']; | |||
// Get variable MOR_AGI_PROVIDER_ID (this variable is set by MOR Core) | |||
$provider_id = $agi->get_variable("MOR_AGI_PROVIDER_ID"); | |||
$provider_id = $provider_id['data']; | |||
// CODE GOES HERE | |||
// CODE GOES HERE | |||
// CODE GOES HERE | |||
// set to 1, otherwise provider will be skipped | |||
$agi->set_variable("MOR_AGI_STATUS", "1"); | |||
// SELECT CIC BY $destination_number or $provider_id FROM EXTERNAL DB AND SET IT TO MOR_AGI_DESTINATION_SUFFIX | |||
$agi->set_variable("MOR_AGI_DESTINATION_SUFFIX", ";cic=123"); | |||
// CODE GOES HERE | |||
// CODE GOES HERE | |||
// CODE GOES HERE | |||
// Calculate elapsed time | |||
$time_elapsed_secs = microtime(true) - $start; | |||
= How to | // Set other variables | ||
$agi->set_variable("MOR_AGI_RUN_TIME", $time_elapsed_secs); | |||
$agi->set_variable("MOR_AGI_TIMEOUT", "0"); | |||
return 0; | |||
?> | |||
</pre> | |||
If user dials '''370123456''' and retrieved suffix is ''';cic=123''', then outgoing number will be '''370123456;cic=123''' | |||
= How to debug = | |||
If you suspect that script is not working properly, you can check [http://wiki.kolmisoft.com/index.php/Call_Info#Call_Log Call Log] to get more information about that call attempt.<br/> | |||
Firstly, we need to find those calls. There are two hangup cause codes related to Provider AGI script:<br/> | |||
* 266 Provider skipped because AGI script returned timeout error | |||
* 267 Provider skipped because AGI script rejected this provider (AGI script status 0) | |||
In [http://wiki.kolmisoft.com/index.php/Last_Calls Last Calls] page we can find such calls:<br/> | |||
[[File:Provider agi debug last calls.png]]<br/><br/> | |||
Press blue Call info button and then at the bottom of the page click 'Retrieve Log file' button. Wait till Log file is found and then you should be able to see additional information about custom Provider AGI script:<br/><br/> | |||
[[File:Provider agi debug call log.png]]<br/><br/> | |||
From this output we can see that AGI script status is 0, that means script rejected call. AGI Script response output shows more detailed information and we can see that 'error_text' contains message 'Dead'. Our example AGI script rejects call based on 'error_text' variable so we know that this particular number was rejected correctly.<br/> | |||
In addition, we can see that script took about 2 seconds to execute and it did not timeout. |
Latest revision as of 09:16, 4 August 2017
This topic is ADVANCED and shows how to MODIFY MOR call flow. Please do not use this functionality if you are not sure what you are doing!
Asterisk AGI knowledge is necessary to use this feature.
What is it for?
This feature allows to execute custom script which tells MOR to either allow/reject call to specific Provider or add suffix to destination number when dialing through specific Provider. This is useful if you require some additional number/Provider validation that is not implemented in MOR.
How does it work?
If this feature is enabled then MOR Core executes custom AGI script. Script is executed just before dial command of each Provider (after all other validations are done by Core). MOR Core passes these variables to script:
- MOR_AGI_DESTINATION - localized destination number.
- MOR_AGI_PROVIDER_ID - Provider id which is being validated.
AGI script should validate number/Provider and set these variables back to Core (via AGI):
- MOR_AGI_STATUS - this variables tells core to allow/reject call. If value is 1, then call is allowed. If value is 0, then call is rejected. This variable is required!
- MOR_AGI_RESPONSE - variable is used to pass description of why call was rejected or allowed to go to Provider. For example, this variable could contain message "Number is blocked". Variable is optional.
- MOR_AGI_RUN_TIME - if your script calculates run time, then you can set elapsed time to this variable. Variable is optional.
- MOR_AGI_TIMEOUT - in case your script has timeout prevention and you want to reject call on timeout, you may set this variable value to 1 and then core will reject call when AGI script timeouts. Variable is optional.
- MOR_AGI_DESTINATION_SUFFIX - if this variable is set, then value will be added to destination number. For example if original destination number is 370123456 and MOR_AGI_DESTINATION_SUFFIX is set to ;cic=123, then MOR will send 370123456;cic=123 as destination number to Provider. Variable is optional.
As you can see, call flow can be controlled by using variables MOR_AGI_STATUS and MOR_AGI_TIMEOUT. Also note that variable MOR_AGI_STATUS is required and call will be rejected if this variable is missing (or value is not 1).
If AGI script returns MOR_AGI_STATUS = 0 and this way rejects call, then other Providers will not be checked. Call will be terminated completely. Following hangupcause codes are assosiated with this feature:
- 266 Provider skipped because AGI script returned timeout error
- 267 Provider skipped because AGI script rejected this provider (AGI script status 0)
How to enable this feature
For this feature to work, you need to enable 'Execute AGI script' in selected Provider settings. In addition, you have to set path to AGI script in mor.conf configuration file (variable provider_agi_script_path).
HLR number lookup example script
Asterisk AGI can be used in many programming languages. In this example we will use PHP AGI library (http://phpagi.sourceforge.net, look for phpagi-2.20.tgz or newer).
Let's build AGI script that checks number availability in HLR database.
Note that Kolmisoft does not provide support for custom AGI scripts and these scripts should be developed by MOR administrator! Also, HLR services are paid and Kolmisoft does not provide HLR service accounts.
HLR number lookup PHP example script:
#!/usr/bin/php -q <?php // These values should be set by admin define("HLR_PASSWORD", "YOUR_PASSWORD"); define("HLR_API_KEY", "YOUR_API"); define("TIMEOUT_SECONDS", "4"); // These lines are used to calculate script run time declare(ticks = 1); $start = microtime(true); if (function_exists('pcntl_signal')) { pcntl_signal(SIGHUP, SIG_IGN); } error_reporting(E_ALL ^ (E_NOTICE | E_WARNING)); // Include Asterisk PHP AGI library (http://phpagi.sourceforge.net) include("/var/lib/asterisk/agi-bin/HLR/lib/phpagi/phpagi.php"); // Function to loopuk number in HLR database function lookupCarrier(&$response, &$status, $msisdn, &$timeout_state) { // Set URL $url = "https://www.hlrlookup.com/api/hlr/?apikey=" . HLR_API_KEY . "&password=" . HLR_PASSWORD . "&msisdn=$msisdn"; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_TIMEOUT, TIMEOUT_SECONDS); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, TIMEOUT_SECONDS); // Send request and get response $response = curl_exec($ch); // Check if response is received if (strlen($response)) { // If we got response, then connection did not timeout $timeout_state = 0; // Parse response $decoded_response = json_decode($response); // Get value of 'error_text' variable if (isset($decoded_response->{'error_text'})) { $status = $decoded_response->{'error_text'}; } } // Limit response length $response = substr($response, 0, 1000); } // initialize AGI $agi = new AGI(); // Get variable MOR_AGI_DESTINATION (this variable is set by MOR Core) $msisdn = $agi->get_variable("MOR_AGI_DESTINATION"); $msisdn = $msisdn['data']; $response = ''; $status = ''; // Set default status $agi->set_variable("MOR_AGI_STATUS", "0"); // Set default state $timeout_state = 1; // Get status lookupcarrier($response, $status, $msisdn, $timeout_state); // Map response status to AGI return status switch ($status) { // Set MOR_AGI_STATUS to 1 if error_text contains 'Absent Subscriber' or 'Live' messages // Call will be accepted on these messages and rejected on any other case "Absent Subscriber": $agi->set_variable("MOR_AGI_STATUS", "1"); break; case "Live": $agi->set_variable("MOR_AGI_STATUS", "1"); break; } // Calculate elapsed time $time_elapsed_secs = microtime(true) - $start; // Set variables back to MOR Core (MOR_AGI_STATUS is already set) $agi->set_variable("MOR_AGI_RUN_TIME", $time_elapsed_secs); $agi->set_variable("MOR_AGI_RESPONSE", $response); $agi->set_variable("MOR_AGI_TIMEOUT", $timeout_state); return 0; ?>
Let's create separate directory for HLR lookup functionality:
mkdir -p /var/lib/asterisk/agi-bin/HLR
This directory will include our PHP AGI script and library:
[root@dev]# ls -l /var/lib/asterisk/agi-bin/HLR/ total 8 -rwxrwxrwx 1 root root 2100 Apr 15 16:10 hlr_carrier_lookup.php drwxrwxrwx 3 root root 4096 Mar 12 22:24 lib
Set executable permissions to our AGI script:
chmod 777 -R /var/lib/asterisk/agi-bin/HLR/hlr_carrier_lookup.php
Now that we have placed our script in /var/lib/asterisk/agi-bin/HLR/ and set proper permission, we need to enable Provider AGI script in /etc/asterisk/mor.conf configuration file. To do so, just set correct path to our AGI script in variable provider_agi_script_path:
provider_agi_script_path = /var/lib/asterisk/agi-bin/HLR/hlr_carrier_lookup.php
Now reload MOR core:
asterisk -rx "mor reload"
Finally, enable 'Execute AGI script' in selected Provider settings.
Example how to add suffix to destination number
It is possible to add suffix to destination number when dialing through specific Provider. In this example PHP script we retrieve suffix by MOR_AGI_DESTINATION/MOR_AGI_PROVIDER_ID from some external database. Retrieved suffix is set to MOR_AGI_DESTINATION_SUFFIX and MOR core will use this variable to modify outgoing number.
#!/usr/bin/php -q <?php // These lines are used to calculate script run time declare(ticks = 1); $start = microtime(true); if (function_exists('pcntl_signal')) { pcntl_signal(SIGHUP, SIG_IGN); } error_reporting(E_ALL ^ (E_NOTICE | E_WARNING)); // Include Asterisk PHP AGI library (http://phpagi.sourceforge.net) include("/var/lib/asterisk/agi-bin/HLR/lib/phpagi.php"); // initialize AGI $agi = new AGI(); // Get variable MOR_AGI_DESTINATION (this variable is set by MOR Core) $destination_number = $agi->get_variable("MOR_AGI_DESTINATION"); $destination_number = $destination_number['data']; // Get variable MOR_AGI_PROVIDER_ID (this variable is set by MOR Core) $provider_id = $agi->get_variable("MOR_AGI_PROVIDER_ID"); $provider_id = $provider_id['data']; // CODE GOES HERE // CODE GOES HERE // CODE GOES HERE // set to 1, otherwise provider will be skipped $agi->set_variable("MOR_AGI_STATUS", "1"); // SELECT CIC BY $destination_number or $provider_id FROM EXTERNAL DB AND SET IT TO MOR_AGI_DESTINATION_SUFFIX $agi->set_variable("MOR_AGI_DESTINATION_SUFFIX", ";cic=123"); // CODE GOES HERE // CODE GOES HERE // CODE GOES HERE // Calculate elapsed time $time_elapsed_secs = microtime(true) - $start; // Set other variables $agi->set_variable("MOR_AGI_RUN_TIME", $time_elapsed_secs); $agi->set_variable("MOR_AGI_TIMEOUT", "0"); return 0; ?>
If user dials 370123456 and retrieved suffix is ;cic=123, then outgoing number will be 370123456;cic=123
How to debug
If you suspect that script is not working properly, you can check Call Log to get more information about that call attempt.
Firstly, we need to find those calls. There are two hangup cause codes related to Provider AGI script:
- 266 Provider skipped because AGI script returned timeout error
- 267 Provider skipped because AGI script rejected this provider (AGI script status 0)
In Last Calls page we can find such calls:
Press blue Call info button and then at the bottom of the page click 'Retrieve Log file' button. Wait till Log file is found and then you should be able to see additional information about custom Provider AGI script:
From this output we can see that AGI script status is 0, that means script rejected call. AGI Script response output shows more detailed information and we can see that 'error_text' contains message 'Dead'. Our example AGI script rejects call based on 'error_text' variable so we know that this particular number was rejected correctly.
In addition, we can see that script took about 2 seconds to execute and it did not timeout.