Asterisk: Initiate a call from extension by PHP script

If you have an asterisk PBX and some kind of internal web-based system like intranet or CRM with a contacts that your team need to call from time to time, there is an easy way to allow users fast dial those contact by linking a telephone number on a web page with a script that will call Asterisk and instruct it to dial first the user extension, and then connect him to the contact number.

The example code, that was originally taken from here and slightly modified looks like this:

# ip address that asterisk is on.
$strHost = ""; 

# asterisk manager username and password
$strUser = "admin";
$strSecret = "secret_password"; 

# specify the channel (extension) you want to receive the call requests with
# e.g. SIP/XXX, IAX2/XXXX, ZAP/XXXX, etc
$strChannel = $_REQUEST['exten'];
$strContext = "from-internal";

$number = strtolower($_REQUEST['number']);
$strCallerId = $number;

#specify the amount of time you want to try calling the specified channel before hangin up
$strWaitTime = "30";

#specify the priority you wish to place on making this call
$strPriority = "1";

# validation
$valNumber = '/^\d+$/';
$valExt = '/^(SIP|IAX2|ZAP)\/\d+$/';

if (!preg_match($valNumber, $number)) {
    print "The number is incorrect, should match '$valNumber' pattern\n";
if (!preg_match($valExt, $strChannel)) {
    print "The extension is incorrect, should match '$valExt' pattern\n";

$errno=0 ;
$errstr=0 ;
$oSocket = fsockopen ($strHost, 5038, $errno, $errstr, 20);

if (!$oSocket) {
    echo "$errstr ($errno)<br>\n";

fputs($oSocket, "Action: login\r\n");
fputs($oSocket, "Events: off\r\n");
fputs($oSocket, "Username: $strUser\r\n");
fputs($oSocket, "Secret: $strSecret\r\n\r\n");
fputs($oSocket, "Action: originate\r\n");
fputs($oSocket, "Channel: $strChannel\r\n");
fputs($oSocket, "WaitTime: $strWaitTime\r\n");
fputs($oSocket, "CallerId: $strCallerId\r\n");
fputs($oSocket, "Exten: $number\r\n");
fputs($oSocket, "Context: $strContext\r\n");
fputs($oSocket, "Priority: $strPriority\r\n\r\n");
fputs($oSocket, "Action: Logoff\r\n\r\n");

echo "Extension $strChannel should be calling $number." ;

So, for example, if you put this code on the asterisk server in a web root as call.php and then call http://<your_asterisk_ip_address>/call.php?exten=SIP/737&number=77777777, your asterisk will attempt to connect extension 737 with number 77777777. and how to cook it


One of the things I am heavily involved to is doing all sorts of infrastructure automation, and while ansible is a perfect tool for system administration automation, when it comes to more complex things like interacting with different APIs, and making all kind of more hardcore things, (robo) is what can really save you.

I have started learning robo few weeks ago, but the problem is that they have pretty short documentation, and few basic examples, so it was not that easy at all and I am still in the process of finding best ways to go around, but I already have quite few things that I want to share here for anyone to use and for me have it saves in a safe place.

Ok, this one gonna be long enough and even probably a series of posts, but I have to share my experience.

While you can use single RoboFile.php with all commands you need in the project directory and call it via ./vendor/bin/robo, this is not a very comfortable approach for complex things, as this file get huge and messy very-very fast. For a proper use of robo, you should write a set of tasks, a set of command classes and then use all of it from your stand-alone robo app. For a sake of example, lets assume that all robo related commands and tasks are under src/Robo directory with Foo\Robo namespace prefix and you have a robo.php file with the actual app that you call.

To make it clear, here is a directory structure I have with some real tasks and commands already in place:

├── composer.json
├── composer.lock
├── .env
├── robo.php
└── src
    └── Robo
        ├── AbstractApiTask.php
        ├── AbstractCommand.php
        ├── AbstractTask.php
        ├── Command
        │   ├── BitbucketCommand.php
        │   ├── HipchatCommand.php
        │   └── RedmineCommand.php
        └── Task
            ├── Bitbucket
            │   ├── BranchRestrict.php
            │   ├── BranchUnrestrict.php
            │   ├── RepoCreate.php
            │   └── RepoDelete.php
            ├── Hipchat
            │   ├── RoomCreate.php
            │   └── RoomDelete.php
            └── Redmine
                └── ProjectCreate.php

(vendor directory is excluded on purpose to make tree clear)


So now we have all in place and first thing first – we need to configure our app with a variety of different parameters. Robo does have Config implemented and configuration part is covered in a Robo as a Framework section of their site, but that mostly rely on storing your configuration in YML files, while I already have all configuration in a $config array and need to supply it to robo. To do that, we need to create a default robo container and pass our config to it, so in robo.php we have:

\Robo\Robo::createDefaultContainer(null, null, null, $config); 
$statusCode = \Robo\Robo::run(
    "Foo Robo",

Moreover, as we are passing the $commandClasses array with a list of the command classes, we want that part to be auto-generated as well, so above the code that creates a container we have:

$cmdPath = "src/Robo/Command";
$cmdNamespace = "\\Foo\\Robo\\Command";
$commandClasses = [];
foreach (glob("$cmdPath/*.php") as $file) {
    if (preg_match('/^.*\/(.*)\.php$/', $file, $matches) and class_exists($cmdNamespace . "\\" . $matches[1])) {
        $commandClasses []= $cmdNamespace . "\\" . $matches[1];

And that’s pretty much all we need to have in robo.php apart of the code that fill the $config array, which is irrelevant to this blog post.

Task auto-loading

One thing that I found annoying in Extending robo how-to is the way they load tasks to commands. Basically for each collection of tasks you would have a loadTasks trait that describes each task and then you use it in the command class. While traits are questionable by nature, writing lots of same functions for a purpose of describing tasks is boring, time consuming and no way flexible. So instead of doing trait bullshit, we go with magic __call method in the AbstractCommand class that is extended by all actual tasks:

 * Base command class for Foo
 * @see
namespace Foo\Robo;

use \Robo\Common\ConfigAwareTrait as configTrait;

abstract class AbstractCommand extends \Robo\Tasks
    use configTrait;

     * @var string $taskDir path to Tasks dir relative to our namespace
    protected $taskDir = 'Task';

     * Magic __call that tries to find and execute a correct task based
     * on called method name that must start with 'task'
     * @param string $method Method name that was called
     * @param array $args Arguments that were passed to the method
     * @return 
    public function __call($method, $args = null)
        if (preg_match('/^task([A-Z]+.*?)([A-Z]+.*)$/', $method, $matches)) {
            $className = __NAMESPACE__ . "\\" . $this->taskDir . "\\" . $matches[1] . "\\" . $matches[2];
            if (!class_exists($className)) {
                throw new \RuntimeException("Failed to find class '$className' for '$method' task");
            return $this->task($className, $args);
        throw new \RuntimeException("Called to undefined method '$method' of '" . get_called_class() . "'");

This class follows the naming convention and directory structure to auto-load tasks based on the method names and in out example the following code will work as expected from inside any command:



So now we are focused only on writing tasks (example):


namespace Foo\Robo\Task\Hipchat;

use Robo\Result;
use Foo\Utility\Hash;

 * Creates a HipChat room.
 * <?php
 * $this->taskRoomCreate()
 * ->name('testroomname')
 * ->topic('This is a test room. Feel free to chat')
 * ->privacy('public')
 * ->run();
 * ?>
class RoomCreate extends \Foo\Robo\AbstractApiTask
     * @var array data
     * @see
    protected $data = [
        'name'                      => null,
        'privacy'                   => 'public',
        'delegate_admin_visibility' => null,
        'topic'                     => null,
        'guest_access'              => false

     * @var array requiredData
     * @see
    protected $requiredData = [

     * {@inheritdoc}
    public function run()

        $this->printInfo("Creating {name} room", $this->data);

        try {
            $data = $this->api->post('room', $this->data);
        } catch (\Exception $e) {
            return Result::fromException($this, $e);

        if (!$data || !is_array($data)) {
            return Result::error($this, "Failed to create room", $this->data);

        // Because the create call returns only id, we'll make a new call to get
        // complete info about new room

        $this->printInfo("Retrieving {name} room info", $this->data['name']);
        try {
            $data = $this->api->get('room/' . $data['id']);
        } catch (\Exception $e) {
            return Result::fromException($this, $e);

        if (!$data || !is_array($data)) {
            return Result::error($this, "Failed to retrieve room info", $this->data);

        $data = array_filter(Hash::flatten($data));
        return Result::success($this, "Room successfully created", $data);

and commands (example):


 * Foo HipChat commands file
 * @see

namespace Foo\Robo\Command;

use \Consolidation\OutputFormatters\StructuredData\PropertyList;
use \Foo\Robo\AbstractCommand;

class HipchatCommand extends AbstractCommand

     * Create a HipChat room
     * @param string $name Room name
     * @param string $topic Room topic
     * @param string $privacy Room privacy
     * @option string $format Output format (table, list, csv, json, xml)
     * @option string $fields Limit output to given fields, comma-separated
     * @return PropertyList Room info
     * @field-labels:
     *   id: id
     *   name: name
     *   topic: topic
     *   privacy: privacy
     *   xmpp_jid: xmpp_jid
     *   is_archived: is_archived
     *   is_guest_accessible: is_guest_accessible
     * owner_id
     * owner_name
     *   created: created
     *   last_active: last_active
    public function hipchatRoomCreate($name, $topic = "", $privacy = 'public', $opts = ['format' => 'table', 'fields' => ''])
        $result = $this->taskHipchatRoomCreate()

        return new PropertyList($result->getData());

     * Delete HipChat room
     * @param string $name Room name
     * @option bool $force Force deletion
     * @return bool true on success and false on failure
    public function hipchatRoomDelete($name, $opts = ['force' => false ])
        if (!$opts['force']) {
            $this->say("Won't delete anything unless you force me to");
            return false;

        return $this->taskHipchatRoomDelete()

I hope this post will be useful for someone (at least for me). There are few things in the examples above that are also tricks and not really standard to robo, including printInfo() method, data and requiredData properties, etc, but that will be covered later in another post.

AWS net.ipv4.tcp_tw_recycle follow-up

Yesterday I wrote a post on AWS EC2 instance networking problem that I was pretty surprised to find out. And while yesterday I was focusing on fixing the problem, today my first task was to find out what actually sets the flag, and quick grep on /etc of the instance revealed that the settings were applied by /etc/sysctl.d/net.ipv4.tcp_tw_recycle.

Very strange to find it there along with net.ipv4.tcp_tw_reuse which is also something that you should not touch. Anyhow, the problem identified, fixed and is about to be added to monitoring…

Amazon AWS, WTF?

Spend the whole day troubleshooting a problem of some pretty random, but stable tcp connection timeouts to one of the Amazon AWS EC2 instance. The problem was that some PCs/laptops/servers would face long term connection timeout to the instance, while others were working fine. The ones with timeouts would experience problems only on TCP level, while ICMP ping would pass normally. The other strange thing is that rebooting client to different kernel would fix the problem for that particular client for a while.

After checking and googling with no luck and getting completely pissed off, I gave the problem another thought and this time I felt that something is wrong with AWS NATting. That clearly brought the memories of troubleshooting TCP fine tuning. So I checked the article, found out the values to make sure are present and went to check the actual instance. Quick look into /proc/sys/net/ipv4/tcp_tw_recycle revealed the problem with its value being 1, so changing it back to 0 with cat to apply immediately fixed the connectivity issues, but then, when I looked into /etc/sysctl.conf, I saw that the value there was already 0!!! How come is it possible if we didn’t change it manually via proc, nor have we touched sysctl.conf for ages and the last server reboot was only few days ago done by Amazon due to their planned maintenance?


Cannot allocate shared memory and kernel.shmmax, kernel.shmall

Ok, this one is short but cool. After server update and reboot I noticed the zabbix-proxy (and later on found out that zabbix-agent also) didn’t start up. Running service zabbix-proxy start gives you OK, but status check later tells that non-OK and service is stopped.

Quick look into zabbix-proxy log file shows the following:

cannot allocate shared memory of size 16777216: [22] Invalid argument

Hmmm… Checking system memory and looking around I didn’t notice any problems or lack of resources, so a big of googling pointed me to check kernel’s shared memory configuration

]# sysctl -a | grep shmmax
kernel.shmmax = 0

And here 0 doesn’t mean unlimited, but literally zero! Ok, fine, but what’s in /etc/sysctl.conf?

 # Controls the maximum shared segment size, in bytes

Don’t ask me why the value is exactly what it is, it was there historically. Anyway, this is wrong, as it is bigger than 0. We need to change it!

]# echo 68719476736 > /proc/sys/kernel/shmmax 
]# sysctl -a |grep shmmax
kernel.shmmax = 0
]# sysctl -w kernel.shmmax=68719476736
kernel.shmmax = 68719476736
]# sysctl -a |grep shmmax
kernel.shmmax = 0

WTF? WTF? WTF? (retvals from my brain doing and seeing above). Again a bit of googling, and here we are:

  • After setting kernel parameter SHMMAX to a value larger than 4GB on a 32-bit Red Hat Enterprise Linux system, this value appears to be reset to 0.

Checking that the server has 2GB RAM, changed the value of shmmax to 2147483648 and repeating the above all worked out as expected with value being applied. Restarting my zabbix services, checking again, still no luck with a slightly different message this time:

cannot allocate shared memory of size 16777216: [28] No space left on device

Seriously?! Checking /etc/sysctl.conf one more time, I found that kernel.shmall has a bit value there as well, but 0 in real life. Adjusting it to match kernel.shmmax and restarting the services worked this time.

It’s a pity that RedHat knowledge base doesn’t make a hint about it, as the problem is common for SHMMAX and SHMALL.