[Asterisk-Users] AGI commands STDOUT problem

Moises Silva
Thu, 24 Mar 2005 12:06:11 -0000

i have a problem with AGI in Asterisk 1.0.5, the problem occurs either
with PHP or C AGI scripts/programs. Well, its simple,
either asterisk is not sending correctly the command responses to the
standard output, or for some unknown reason to me the
scripts/programs are not able to read it from standard input.

I have the next C test program for AGI:

#include <stdio.h>
main()
{
	char line[80];
	setlinebuf(stdout);
	setlinebuf(stderr);
	while (1)
	{
		fgets(line,80,stdin);
		if ( strlen(line) <= 1 )
		{
			break;
		}
	}
	printf("SAY NUMBER 55 \"\"\n");
	fgets(line,80,stdin);

	printf("SAY NUMBER 66 \"\"\n");
	fgets(line,80,stdin);

 }

 I currently have 2 servers with Asterisk. The problematic one, as i
said is running Asterisk 1.0.5, the other server
 is running Asterisk 1.0.0, and it run the C test perfectly, the
problematic one just run the first command, never reach
 the secondth command (SAY NUMBER 66).

 I have a PHP test a little bit more meaningfull, because it says a
lot of things of what is going on, besides im PHP programmer
 not C one, so i feel more comfortable with it. The test code is:

 <?php
include_once
'/var/www/localhost/htdocs/ivsadmin/apps/pavoz/classes/AgiTest.php';
$agi = new AgiTest();
die();
?>

i guess the code before doesnt say anything :p , the class AgiTest code is:

<?php
class AgiTest
{
	private $read_bytes                     = 80;
	private $asterisk_environment_variables = array();
	private $log_stream                     = null;

	public function __construct()
	{
		$this->log_stream = fopen('/var/log/pavoz/asterisk','w');
		//reading asterisk initial variables and writing them to log
		$this->ReceiveAsteriskEnvironmentVariables();

		//now we try to execute a command, and track the point of error
		$command  = "SAY NUMBER 55 \"\"";
		$this->ExecuteCommand($command);

		$command  = "SAY NUMBER 66 \"\"";
		$this->ExecuteCommand($command);
		return true;
	}

	public function __destruct()
	{
		fclose($this->log_stream);
	}

	private function WriteLog($Message)
	{
		return fwrite($this->log_stream, $Message."\n");
	}

	private function ReadStdin($Bytes = null)
	{
		$Bytes = $Bytes === null ? $this->read_bytes : $Bytes;
		$this->WriteLog("\nReading {$Bytes} bytes response from
Asterisk...");
		$response = fgets(STDIN, $Bytes);
		$this->WriteLog("Received response: {$response}");
		return $response;
	}

	private function WriteStdout($String)
	{
		$escaped_string = str_replace("\n", '\n', $String);
		$this->WriteLog("\nSending string {$escaped_string} to
Asterisk...");
		$bytes = fwrite(STDOUT, $String);
		fflush(STDOUT);
		$this->WriteLog("Wroten bytes to STDOUT: {$bytes}");
		return $bytes;
	}

	private function ReceiveAsteriskEnvironmentVariables()
	{
		do
		{
			$asterisk_string       = $this->ReadStdin();
			if ( $asterisk_string != "\n" )
			{
				$delimiter_position
strpos($asterisk_string,':');
				$data_name                                        substr($asterisk_string,
0, $delimiter_position);
				$data_value                                       substr($asterisk_string,
$delimiter_position + 1);
				$this->asterisk_environment_variables[$data_name] = trim($data_value);
			}
		} while ( $asterisk_string != "\n" );
		return true;
	}

	public function GetAsteriskEnvironmentVariable($VariableName)
	{
		if ( array_key_exists($VariableName,$this->asterisk_environment_variables)
)
		{
			return $this->asterisk_environment_variables[$VariableName];
		}
		else
		{
			return false;
		}
	}

	public function ExecuteCommand($Command)
	{
		$Command .= "\n";
		$bytes    = $this->WriteStdout($Command);
		$response = $this->ReadStdin();
		return $response;
	}
}
?>

As you can see, the test is exactly the same, in fact, the output to
the asterisk console is the same, but here i can log the communication
between Asterisk and my PHP script. The log output in the file defined
in the script is:

Reading 80 bytes response from Asterisk...
Received response: agi_request: agi_cdr.php


Reading 80 bytes response from Asterisk...
Received response: agi_channel: SIP/12-d91b


Reading 80 bytes response from Asterisk...
Received response: agi_language: en


Reading 80 bytes response from Asterisk...
Received response: agi_type: SIP


Reading 80 bytes response from Asterisk...
Received response: agi_uniqueid: 1111659738.1


Reading 80 bytes response from Asterisk...
Received response: agi_callerid: "Moises Silva" <12>


Reading 80 bytes response from Asterisk...
Received response: agi_dnid: 10


Reading 80 bytes response from Asterisk...
Received response: agi_rdnis: unknown


Reading 80 bytes response from Asterisk...
Received response: agi_context: macro-root


Reading 80 bytes response from Asterisk...
Received response: agi_extension: s


Reading 80 bytes response from Asterisk...
Received response: agi_priority: 4


Reading 80 bytes response from Asterisk...
Received response: agi_enhanced: 0.0


Reading 80 bytes response from Asterisk...
Received response: agi_accountcode:


Reading 80 bytes response from Asterisk...
Received response:


Sending string SAY NUMBER 55 ""\n to Asterisk...
Wroten bytes to STDOUT: 17

Reading 80 bytes response from Asterisk...
Received response:

Sending string SAY NUMBER 66 ""\n to Asterisk...
Wroten bytes to STDOUT: 0

Reading 80 bytes response from Asterisk...
Received response:


As we can see, the initial data is received well by the script, but,
after executing a command, is not possible to read the response. But
even worse, the script hangs until i hangup the phone. It stays in the
same point, the line where i attempt to read with fread(); the
response from Asterisk.

this is the output with the same script in the server that is running correctly

Reading 80 bytes response from Asterisk...
Received response: agi_request: agi_test.php


Reading 80 bytes response from Asterisk...
Received response: agi_channel: SIP/13-b3d1


Reading 80 bytes response from Asterisk...
Received response: agi_language: en


Reading 80 bytes response from Asterisk...
Received response: agi_type: SIP


Reading 80 bytes response from Asterisk...
Received response: agi_uniqueid: 1111686414.65


Reading 80 bytes response from Asterisk...
Received response: agi_callerid: "Andrew" <13>


Reading 80 bytes response from Asterisk...
Received response: agi_dnid: 21


Reading 80 bytes response from Asterisk...
Received response: agi_rdnis: unknown


Reading 80 bytes response from Asterisk...
Received response: agi_context: macro-root


Reading 80 bytes response from Asterisk...
Received response: agi_extension: s


Reading 80 bytes response from Asterisk...
Received response: agi_priority: 4


Reading 80 bytes response from Asterisk...
Received response: agi_enhanced: 0.0


Reading 80 bytes response from Asterisk...
Received response: agi_accountcode:


Reading 80 bytes response from Asterisk...
Received response:


Sending string SAY NUMBER 55 ""\n to Asterisk...
Wroten bytes to STDOUT: 17

Reading 80 bytes response from Asterisk...
Received response: 200 result=0


Sending string SAY NUMBER 66 ""\n to Asterisk...
Wroten bytes to STDOUT: 17

Reading 80 bytes response from Asterisk...
Received response: 200 result=0

I was tired of looking for errors in the script, but the fact that the
script in PHP and the C test program runs perfectly in the other
server is very annoying :( , So, i started to look out in the Asterisk
C code. I checked out mainly the file res/agi_res.c
well, once here i checked the function 'static void setup_env' that
function sends the initial environment variables, uses
the function fdprintf, that appears to be a redefinition of
printf_to_agi_result_buffer function,to send data to the AGI script.
I assume that since i receive correctly the initial data, then the
function fdprintf works fine. Then i checked out the function
that handles the command SAY_NUMBER, this function is called
handle_saynumber, i put some extra ast_log warnings to verify that the
function is doing all well, and in effect, it does.

The output in the asterisk console when i try to execute the agi_script is:

    -- Executing Macro("SIP/12-dec6", "root|sipextens") in
new stack
    -- Executing GotoIf("SIP/12-dec6", "1 ? 2 : 5") in new
stack
    -- Goto (macro-root,s,2)
    -- Executing SetVar("SIP/12-dec6", "dialed=10") in new
stack
    -- Executing SetVar("SIP/12-dec6", "authtype=sipextens")
in new stack
    -- Executing AGI("SIP/12-dec6", "agi_cdr.php") in new
stack
    -- Launched AGI Script /var/lib/asterisk/agi-bin/agi_cdr.php
Mar 24 05:06:18 WARNING[2911]: res_agi.c:376
printf_to_agi_result_buffer: Valid buffer!
Mar 24 05:06:18 WARNING[2911]: res_agi.c:376
printf_to_agi_result_buffer: Valid buffer!
Mar 24 05:06:18 WARNING[2911]: res_agi.c:376
printf_to_agi_result_buffer: Valid buffer!
Mar 24 05:06:18 WARNING[2911]: res_agi.c:376
printf_to_agi_result_buffer: Valid buffer!
Mar 24 05:06:18 WARNING[2911]: res_agi.c:376
printf_to_agi_result_buffer: Valid buffer!
Mar 24 05:06:18 WARNING[2911]: res_agi.c:376
printf_to_agi_result_buffer: Valid buffer!
Mar 24 05:06:18 WARNING[2911]: res_agi.c:376
printf_to_agi_result_buffer: Valid buffer!
Mar 24 05:06:18 WARNING[2911]: res_agi.c:376
printf_to_agi_result_buffer: Valid buffer!
Mar 24 05:06:18 WARNING[2911]: res_agi.c:376
printf_to_agi_result_buffer: Valid buffer!
Mar 24 05:06:18 WARNING[2911]: res_agi.c:376
printf_to_agi_result_buffer: Valid buffer!
Mar 24 05:06:18 WARNING[2911]: res_agi.c:376
printf_to_agi_result_buffer: Valid buffer!
Mar 24 05:06:18 WARNING[2911]: res_agi.c:376
printf_to_agi_result_buffer: Valid buffer!
Mar 24 05:06:18 WARNING[2911]: res_agi.c:376
printf_to_agi_result_buffer: Valid buffer!
Mar 24 05:06:18 WARNING[2911]: res_agi.c:376
printf_to_agi_result_buffer: Valid buffer!
Mar 24 05:06:18 WARNING[2911]: res_agi.c:579 handle_saynumber:
Entering function handle_saynumber!
Mar 24 05:06:18 WARNING[2911]: res_agi.c:586 handle_saynumber: About
to execute ast_say_number_full function!
    -- Playing 'digits/50' (language 'en')
    -- Playing 'digits/5' (language 'en')
Mar 24 05:06:20 WARNING[2911]: res_agi.c:588 handle_saynumber:
Executed function, return value is 0!
Mar 24 05:06:20 WARNING[2911]: res_agi.c:591 handle_saynumber:
returning value to AGI with fdprintf!
Mar 24 05:06:20 WARNING[2911]: res_agi.c:376
printf_to_agi_result_buffer: Valid buffer!
Mar 24 05:06:20 WARNING[2911]: res_agi.c:594 handle_saynumber:
returning succes to asterisk!

after i hangup the call then:
  == Spawn extension (macro-root, s, 4) exited non-zero on
'SIP/12-dec6' in macro 'root'
  == Spawn extension (localplans.some, 10, 1) exited non-zero on
'SIP/12-dec6'

the warnings are messages set by me to check that the buffer where
asterisk is written are valid and
some other info inside the handle_saynumber function.


The information of the Servers and the software installed in them is:

Server Running Correctly:
Gnu/Linux Distro: Gentoo
uname: Linux intervoip1 2.6.9-ivsol1 #2 Thu Nov 25 08:25:32 CST 2004
i686 Intel(R) Pentium(R) 4 CPU 2.40GHz GenuineIntel GNU/Linux
Compiler: GCC Version 3.4.3
Glibc: Version 2.3.4.20041021
Asterisk: Version 1.0.0

Server Running With Bugs:
Gnu/Linux Distro: Gentoo
uname: Linux hq 2.6.9-ivsol1 #1 Fri Nov 19 22:37:46 CST 2004 i686 AMD
Athlon(tm) XP 2400+ AuthenticAMD GNU/Linux
Gcc: Version 3.4.3
Glibc: Version 2.3.4.20041102
Asterisk: Version 1.0.5

The main difference is the Asterisk version and the Glibc version.

I appreciate any help with this. Sorry if i omit information that may
be important, but that was all i thought it is.