No Excute AGI Command

I am studying to create an ivr with fedora 40 and asterisk 20.8.1.

I am trying to obtain agi.c agi.h from the Internet and run a program written in C using agi.

Value created from c source
gcc -o func_init func_init.c agi.c $(mysql_config --libs) -I/usr/include/mysql/
If you run it with ./func_init 1 334455, it runs normally.

However, if you run agi in dialplan,
<PJSIP/9001-00000007>AGI Rx << cid = 01022638701
<PJSIP/9001-00000007>AGI Tx >> 510 Invalid or unknown command
<PJSIP/9001-00000007>AGI Rx << 1-1
<PJSIP/9001-00000007>AGI Tx >> 510 Invalid or unknown command
<PJSIP/9001-00000007>AGI Rx << 1-2
<PJSIP/9001-00000007>AGI Tx >> 510 Invalid or unknown command
<PJSIP/9001-00000007>AGI Rx << 1-3
<PJSIP/9001-00000007>AGI Tx >> 510 Invalid or unknown command
<PJSIP/9001-00000007>AGI Rx << 11
<PJSIP/9001-00000007>AGI Tx >> 510 Invalid or unknown command
<PJSIP/9001-00000007>AGI Rx << 22
<PJSIP/9001-00000007>AGI Tx >> 510 Invalid or unknown command
<PJSIP/9001-00000007>AGI Rx << 33
<PJSIP/9001-00000007>AGI Tx >> 510 Invalid or unknown command
<PJSIP/9001-00000007>AGI Rx << 44
<PJSIP/9001-00000007>AGI Tx >> 510 Invalid or unknown command
<PJSIP/9001-00000007>AGI Rx << sql = select attname,manno1,manno2,infoyn,infono,w1,w2,hotmanno1,hotmanno2,hotmanno3,weekrest from attread where att = 0
<PJSIP/9001-00000007>AGI Tx >> 510 Invalid or unknown command
<PJSIP/9001-00000007>AGI Rx <<
<PJSIP/9001-00000007>AGI Tx >> 510 Invalid or unknown command
<PJSIP/9001-00000007>AGI Rx << set variable “RTn” “0”

MYSQL con = mysql_init(NULL);
printf(“1-1\n”);
MYSQL_RES
result;
printf(“1-2\n”);
MYSQL_ROW row;
printf(“1-3\n”);

per mysql command

<PJSIP/9001-00000007>AGI Tx >> 510 Invalid or unknown command

Because of this, I cannot get the desired value.

I’m looking for help with the problem.

The c source and dialplan source are as follows.

  • func_init.c
    #define _CRT_SECURE_NO_WARNINGS // 혹은 localtime_s를 사용

////////////////////////////////////////|//////////////////////////////////////
// ANSI include files
////////////////////////////////////////|//////////////////////////////////////
#include <mysql.h> //“/usr/include/mysql/mysql.h”
//#include “/usr/include/mysql/mysql.h”
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <libgen.h>

////////////////////////////////////////|//////////////////////////////////////
// Operating system include files
////////////////////////////////////////|//////////////////////////////////////
#include <syslog.h>

////////////////////////////////////////|//////////////////////////////////////
// Local include files
////////////////////////////////////////|//////////////////////////////////////
#include “agi.h”
#include “all.h”
#undef GNU_LIBRARY
#include “getopt.h”

#include <stdio.h>
#include <time.h>

char *p[7] = {“일요일”,“월요일”,“화요일”,“수요일”,“목요일”,“금요일”,“토요일”};

/*
argv[1] : 회선속성 argv[2]: cid
/
int main(int agrc,char
argv)
{

 time_t    timer;
 time_t    next_timer;
 struct    tm* t;
 struct    tm* next_t;
 char      dt[9];
 char      nextDt[9];
 char      tt[7];
 char      c_yoil[2];
 char      sql[255]; 
 int       Att= 0;
 char      AttName[100];
 int       ManNo1=0;
 int       ManNo2=0;
 int       InfoYN = 0;
 int       InfoNo = 0;
 char      w1[10] ;
 char      w2[10] ;
 int       HotManNo1 = 0;
 int       HotManNo2 = 0;
 int       HotManNo3 = 0;
 char      WeekRest[10];
 char      ToWeek[10];
 int       i;
 char      cid[50];

 Att = atoi(argv[1]);
 sprintf(cid,"%s",argv[2]);


 printf("cid = %s\n",cid);

 MYSQL *con = mysql_init(NULL);
 printf("1-1\n");
 MYSQL_RES* result;
 printf("1-2\n");
 MYSQL_ROW row;
 printf("1-3\n");

 printf("11\n");
 if (con == NULL)
 {     
      fprintf(stderr, "%s\n", mysql_error(con));
      agi_set_variable("RTn","0");
      return -1;
 }
 printf("22\n");
           
 if (mysql_real_connect(con, "localhost", "root", "1234", "parkgolf", 0, NULL, 0) == NULL)
 {
       fprintf(stderr, "%s\n", mysql_error(con));
       mysql_close(con);
       agi_set_variable("RTn","0");
       return -1;
 }
 else
 {
  printf("33\n");
      mysql_set_character_set(con, "utf-8");
 }

 printf("44\n");	
 //sql_num_rows($result);
 //
 //
 sprintf(sql,"select attname,manno1,manno2,infoyn,infono,w1,w2,hotmanno1,hotmanno2,hotmanno3,weekrest from attread where att = %d",Att);
 printf("sql = %s\n",sql);

 if (mysql_query(con, sql))
 {
      printf("%s\n",mysql_error(con));
      fprintf(stderr, "%s\n", mysql_error(con));
      mysql_close(con);
      agi_set_variable("RTn","0");
 
	  return -1;
 }

 result = mysql_store_result(con);

/*
while( (row = mysql_fetch_row(result)) != NULL)
{

      printf("%s %s %s\n",row[0],row[1],row[2]);
 }

*/

 row = mysql_fetch_row(result);
 if(row == NULL)
 {
      printf("%s\n",mysql_error(con));

      mysql_free_result(result);
      mysql_close(con);
      agi_set_variable("RTn","0");
      return -1;
 }

 sprintf(AttName,"%s",row[0]);
 ManNo1    = atoi(row[1]);
 ManNo2    = atoi(row[2]);
 InfoYN    = atoi(row[3]);
 InfoNo    = atoi(row[4]);
 strcpy(w1,row[5]);
 strcpy(w2,row[6]);
 HotManNo1 = atoi(row[7]);
 HotManNo2 = atoi(row[8]);
 HotManNo3 = atoi(row[9]);
 strcpy(WeekRest,row[10]);


 mysql_free_result(result);


 printf("%s %d %d %d %d \n",AttName,ManNo1,ManNo2,InfoYN,InfoNo);


 /*while( (row = mysql_fetch_row(result)) != NULL)
 {

      printf("%s %s %s\n",row[0],row[1],row[2]);
 } 
*/ 
 //mysql_free_result(result);
 //mysql_close(con);

 timer = time(NULL); // 1970년 1월 1일 0시 0분 0초부터 시작하여 현재까지의 초
 next_timer = time(NULL) + (24*60*60);         

 t = localtime(&timer); // 포맷팅을 위해 구조체에 넣기
 next_t = localtime(&next_timer);

 sprintf(dt,"%04d%02d%02d",t->tm_year +1900, t->tm_mon + 1, t->tm_mday);
 sprintf(nextDt,"%04d%02d%02d",next_t->tm_year +1900, next_t->tm_mon + 1, next_t->tm_mday);

 sprintf(tt,"%02d%02d%02d",t->tm_hour, t->tm_min, t->tm_sec);
 sprintf(c_yoil,"%d",t->tm_wday);


 if(InfoYN)
 {
      //mysql_free_result(result);
      mysql_close(con);
      agi_set_variable("Rtn","10");   //공지사항이 있음
      return 1;                                      
 }

 sprintf(sql,"select * from holiday where att = %d and hdate = '%s'",Att, nextDt);

 if(mysql_query(con,sql))
 {
      fprintf(stderr,"%s\n",mysql_error(con));
      //mysql_free_result(result);
      mysql_close(con);
      agi_set_variable("RTn","0");
      return -1;
 }

 result = mysql_store_result(con);

 if(mysql_num_rows(result))
 {
      mysql_free_result(result);
      mysql_close(con);
      agi_set_variable("Rtn","20");
      return 1;
 }

 mysql_free_result(result);

 i = t->tm_wday;

 sprintf(ToWeek,"%s",p[i]);

 if(strcmp(ToWeek,WeekRest) == 0)
 {

      //mysql_free_result(result);
      mysql_close(con);
      agi_set_variable("Rtn","20");  // 주중 휴무일 요일
      return 1;
 }


 if(strcmp(tt,"090000") < 0)
 {
      //mysql_free_result(result);
      mysql_close(con);
      agi_set_variable("Rtn","30"); //아직 서비스 시작이 아님.
      return 1;
 }

 if(strcmp(tt,"180000") > 0)
 {
      //mysql_free_result(result);
      mysql_close(con);
      agi_set_variable("Rtn","30");
      return 1;
 }

 sprintf(sql,"select * from blacklist where att = %d and phone = '%s'",Att, argv[2]);

 if(mysql_query(con,sql))
 {
      fprintf(stderr,"%s\n",mysql_error(con));
      //mysql_free_result(result);
      mysql_close(con);
      agi_set_variable("Rtn","0");
      return 1;
 }

 result = mysql_store_result(con);

 if(mysql_num_rows(result))
 {
      mysql_free_result(result);
      mysql_close(con);
      agi_set_variable("Rtn","40");
      return 1;
 }

 mysql_free_result(result);
 mysql_close(con);
 agi_set_variable("Rtn","50");

 return 0;

}

-extensions.conf
[general]

[global]
;CONSOLE=console/dsp
g_Att = 1
g_AttName = “”
g_ManNo1=0
g_ManNo2=0
g_InfoYN = 0
g_InfoNo = 0
g_w1 = “”
g_w2 = “”
g_HotManNo1 = 0
g_HotManNo2 = 0
g_HotManNo3 = 0
g_WeekRest = “없음”
Rtn = “”
chan_use = 0
dig = “”

[hdlr_Hangup]
exten => s,1,Verbose(0,hdlr_Hangup context is load…)
same => n, Return()

[db_hangup]
exten => han,1, playback(/var/lib/asterisk/sounds/ko/데이타베이스오류)
same => n, Hangup()

[ivr-parkgolf]
include => hdlr_Hangup

exten => s,1,Wait(1)
same => n, Answer()
; same => n, playback(/etc/asterisk/sounds/1_인사말)
same => n, NoOp(…4444444…START …)
; same => n, n,Set(CHANNEL(hangup_handler_push)=hdlr_Hangup,s,1)
same => n, NoOp(${CALLERID(num)})
same => n, Set(chan_use=1)
; same => n, Set(TIMEOUT(digit)=5)
; same => n, Set(TIMEOUT(response)=10)
same => n, AGI(/usr/cprog/func_init,Att,“01022638701”)
same => n, NoOp(attName is ${g_AttName} ManNo1 is ${g_ManNo1} )
same => n, Gotoif($[${Rtn} = “0”] ? Goto(db_hangup,han,1))
same => n, Gotoif($[${Rtn} = “50”] ? Goto(Main,1))

exten => Main,1, Read(dig,/etc/asterisk/sounds/1_인사말,1,3,5)
same => n, GotoIf($[${dig} = 1] ? Goto(M1000,1)
same => n, HangUp()

exten => M1000,1, NoOp(예약)
same => n, Hangup()

exten => 1000, 1, Goto(s,1)

[default]
include => ivr-parkgolf

exten => 1000, 1, goto(ivr-parkgolf,s,1)

exten => 9000,1,Dial(SIP/9000)
exten => 9001,1,Dial(SIP/9001)

An AGI is a program, written in a scripting or compiled language (even FORTRAN), that complies with the AGI protocol. This would be a good topic for you to search for and read a couple of times :slight_smile:

The AGI protocol is how Asterisk and your AGI communicate with each other. While your AGI is executing, STDOUT is how you request Asterisk to do something, and STDIN is how Asterisk returns the result of that request.

Thus, when you execute something like printf(“1-3\n”); you are asking Asterisk to execute the command 1-3 which is not an AGI command (enter agi show commands on the Asterisk console) so Asterisk replies with 510 Invalid or unknown command.

In addition to this request/response dance, when your AGI first executes, Asterisk provides a block of AGI variables via STDIN which your AGI must read before attempting any requests.

The AGI protocol is pretty simple, but nobody gets it right the first time. You should use an existing library to handle all the details for you.

Here’s a snippet from one of my AGIs to show how things can be done.

// read the AGI environment                                                          
	agi_read_environment();

// get the CALL-ID                                                                   
	call_id = agi_get_integer_variable("CALL-ID");

// connect to the database                                                           
	if	(EXIT_FAILURE == (status = agi_connect_to_database(
			  &mysql			// context                                   
			)))
		{
		syslog(LOG_ERR
			, "%s %m, mysql_error = \"%s\""
			, syslog_prefix
			, mysql_error(&mysql)
			);
		agi_verbose(
			  "Failed to connect to the database"
					", mysql_error = \"%s\""
			, mysql_error(&mysql)
			);
		exit(EXIT_FAILURE);
		}

There is very little need for using C for this sort of thing. Yes, it offers greater efficiency, but it also takes a lot more work to get things right, with a lot more opportunities for screwups, particularly if you are not skilled.

Most of the time, it is easier to use a higher-level language. I would recommend Python.

If you look at the agi set debug on state,
It was not caused by the printf statement.
MYSQL con = mysql_init(NULL);
MYSQL_RES
result;
MYSQL_ROW row;
if (mysql_real_connect(con, “localhost”, “root”, “1234”, “parkgolf”, 0, NULL, 0) == NULL)
An error occurred in the command to read mariadb, etc.
The printf statement was added to see where errors occur in debug mode.
This is the content.

cid = 01022638701 is not an AGI command.

  1. Where did you get agi.[ch] from?
  2. Why are you not reading the AGI environment?
  3. Why are you using printf() in your program?
  4. Why are you not reading the response from Asterisk?

I’ve added lookup-dnis.c to steve edwards / agi-in-c · GitLab.

It is a complete AGI written in C. It has suffered through many edits and feature changes over the last 15 years, but it is still in production and shows MySQL access in C.

It seems to me you lose some of the speed of C if you have to launch a new process every time to activate your AGI. Have you thought of using the FastAGI interface instead?

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.