[asterisk-users] carefulwrite: write() returned error:Brokenpipe
Steve Edwards
asterisk.org at sedwards.com
Thu Oct 22 14:45:02 CDT 2009
Un-top-posting...
> On Thu, 22 Oct 2009, Danny Nicholas wrote:
>
>> So this would actually be proper?
>
> [snip]
>
>>> my $envvars = <STDIN>;
> [mailto:asterisk-users-bounces at lists.digium.com] On Behalf Of Steve Edwards
>
> I don't "do" Perl, but if that statement reads everything buffered on
> STDIN -- i.e., the AGI environment, then I would guess it would work.
>
> "Proper" would be to read and parse the environment "properly." You could
> make the argument that since you're not going to use anything from the AGI
> environment, why waste the cycles.
>
> I would counter that "best practice" would be to read and parse the
> environment as well as setting up a SIGHUP handler, initializing syslog(),
> setting a STATUS channel variable to FAILURE (and setting it to SUCCESS
> upon successful completion), etc., etc., etc.
On Thu, 22 Oct 2009, Danny Nicholas wrote:
> For my (and any other lazy watchers) benefit, would you post how you would
> do my snippet in C?
I don't think it will do you much good since you don't have my AGI
library, but below is an AGI from a current project that reads a bunch
of stuff from a database and sets a bunch (hundreds) of variables.
I'm a big fan of using an established library so all the funky details
are taken care of for you and you don't get "bit" by changes like you
have. If I had found a C library when I started, I would have used it.
This wasn't written with "publication" in mind but it does show my
"framework" for all my AGIs.
Keep in mind the AGI below executes in less than a second, including the
database accesses.
My apologies to the list for the length :)
//
// Filename: lookup-dnis.c
//
#define Version "002"
//
// Edit date: 2009-10-16
//
// Facility: Asterisk
//
// Abstract: This AGI 'script' implements the lookup-dnis
// application.
//
// Environment: Asterisk
//
// Author: Steven L. Edwards
//
// Modified by
//
// 000 2009-03-23 SLE Create.
// 001 2009-10-16 SLE Log variables if debug.
// 002 2009-10-16 SLE Add flags.
////////////////////////////////////////|//////////////////////////////////////
// ANSI include files
////////////////////////////////////////|//////////////////////////////////////
#include <ctype.h>
#include <errno.h>
#include <signal.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
////////////////////////////////////////|//////////////////////////////////////
// Operating system include files
////////////////////////////////////////|//////////////////////////////////////
#include <syslog.h>
////////////////////////////////////////|//////////////////////////////////////
// Local include files
////////////////////////////////////////|//////////////////////////////////////
#include "agi.h"
#include "agi-mysql.h"
#include "all.h"
#include "getopt.h"
#include "mysql.h"
////////////////////////////////////////|//////////////////////////////////////
// Defines
////////////////////////////////////////|//////////////////////////////////////
////////////////////////////////////////|//////////////////////////////////////
// Macros
////////////////////////////////////////|//////////////////////////////////////
////////////////////////////////////////|//////////////////////////////////////
// Typedefs
////////////////////////////////////////|//////////////////////////////////////
////////////////////////////////////////|//////////////////////////////////////
// Global constants
////////////////////////////////////////|//////////////////////////////////////
////////////////////////////////////////|//////////////////////////////////////
// Global variables
////////////////////////////////////////|//////////////////////////////////////
////////////////////////////////////////|//////////////////////////////////////
// Global functions
////////////////////////////////////////|//////////////////////////////////////
////////////////////////////////////////|//////////////////////////////////////
// External constants
////////////////////////////////////////|//////////////////////////////////////
////////////////////////////////////////|//////////////////////////////////////
// External variables
////////////////////////////////////////|//////////////////////////////////////
extern char *optarg;
////////////////////////////////////////|//////////////////////////////////////
// External functions
////////////////////////////////////////|//////////////////////////////////////
////////////////////////////////////////|//////////////////////////////////////
// Static constants
////////////////////////////////////////|//////////////////////////////////////
////////////////////////////////////////|//////////////////////////////////////
// Static variables
////////////////////////////////////////|//////////////////////////////////////
static int debug_mode;
static MYSQL mysql;
static MYSQL_ROW mysql_row;
static int test_mode;
static int verbose_mode;
////////////////////////////////////////|//////////////////////////////////////
// Static functions
////////////////////////////////////////|//////////////////////////////////////
static int lookup_dnis
(
const char *dnis_pointer
);
static void hangup
(
void
);
////////////////////////////////////////|//////////////////////////////////////
// Main function
////////////////////////////////////////|//////////////////////////////////////
global int main
(
int argc
, char **argv
)
{
auto char dnis[256];
static struct option long_options[]
= {
{"debug-mode", no_argument, &debug_mode, 1}
, {"help", no_argument, 0, '?'}
, {"null", no_argument, 0, 0}
, {"test-mode", no_argument, &test_mode, 1}
, {"verbose-mode", no_argument, &verbose_mode, 1}
, {"version", no_argument, 0, 'v'}
, {0, 0, 0, 0}
};
auto int optchar;
auto char *pointer1;
auto char *pointer2;
auto int status;
// set the syslog ident
setlogmask(LOG_UPTO(LOG_NOTICE));
openlog(argv[0], LOG_PID, LOG_USER);
// read the AGI environment
agi_read_environment();
// assume failure
agi_set_status_failure();
// get the DNIS
memset(dnis, 0, sizeof(dnis));
agi_get_variable("DNIS", dnis);
// process the command line arguments
while (-1 != (optchar
= getopt_long(
argc
, argv
, ""
, long_options
, 0
)))
{
switch (optchar)
{
// help
case '?':
default:
puts("Usage:\tlookup-dnis\\");
puts("\t\t--debug-mode");
puts("\t\t--help\\");
puts("\t\t--null\\");
puts("\t\t--verbose-mode\\");
puts("\t\t--version");
exit(EXIT_SUCCESS);
break;
// version
case 'v':
printf("%s version %s\n"
, *argv
, Version
);
printf("Compiled on %s at %s\n"
, __DATE__
, __TIME__
);
exit(EXIT_SUCCESS);
break;
// something automagically handled by getopt_long()
case 0:
break;
}
}
// set verbose mode
if (0 != verbose_mode)
{
setlogmask(LOG_UPTO(LOG_INFO));
}
// set debug mode
if (0 != debug_mode)
{
setlogmask(LOG_UPTO(LOG_DEBUG));
}
// say who we are
syslog(LOG_DEBUG
, "Starting, version %s"
, Version
);
// trap SIGHUP -- caller hung up
signal(SIGHUP, (void (*)(int))(int)hangup);
// clean the DNIS
pointer1 = pointer2 = dnis;
--pointer1;
while (0 != *++pointer1)
{
// keep letters, forcing to lower case
if (0 != isalpha(*pointer1))
{
*pointer2++ = 32 | *pointer1;
continue;
}
// keep numbers
if (0 != isdigit(*pointer1))
{
*pointer2++ = *pointer1;
continue;
}
}
// terminate the DNIS
*pointer2 = 0;
// drop leading 1
if ('1' == *dnis)
{
auto char temp[256];
strcpy(temp, dnis + 1);
strcpy(dnis, temp);
}
// log the DNIS
syslog(LOG_DEBUG, "DNIS = %s", dnis);
// connect to the database
if (EXIT_FAILURE == (status = agi_connect_to_database(
&mysql // context
)))
{
syslog(LOG_ERR
, "%m, mysql_error = \"%s\""
, mysql_error(&mysql)
);
agi_verbose(
"Failed to connect to the database"
", mysql_error = \"%s\""
, mysql_error(&mysql)
);
exit(EXIT_FAILURE);
}
// lookup the DNIS
if (EXIT_FAILURE == (status = lookup_dnis(dnis)))
{
mysql_close(&mysql);
agi_set_status_failure();
return(EXIT_FAILURE);
}
// function exit
mysql_close(&mysql);
agi_set_status_success();
return(EXIT_SUCCESS);
}
////////////////////////////////////////|///////////////////////////////|//////
// hangup()
//
// Asterisk delivers a SIGHUP when the caller hangs up. Since we have
// already registered a process termination function, all we have to
// do is exit.
////////////////////////////////////////|///////////////////////////////|//////
static void hangup
(
void
)
{
mysql_close(&mysql);
exit(EXIT_SUCCESS);
}
////////////////////////////////////////|///////////////////////////////|//////
// lookup_dnis()
//
// Lookup the DNIS. Exit if successful.
////////////////////////////////////////|///////////////////////////////|//////
static int lookup_dnis
(
const char *dnis_pointer
)
{
auto int column;
auto MYSQL_FIELD *fields;
auto int index;
auto int num_fields;
auto int num_rows;
auto MYSQL_RES *result_pointer;
static const char recipes[]
= "select"
" client_id"
", confirm_prompt"
", goodbye"
", initial_language"
", outbound_dialstring"
", verification_prompt_a"
", verification_prompt_b"
", you_entered_prompt"
" from"
" dnises"
", recipes"
" where '%s' = dnis"
" and dnises.recipe = recipes.recipe"
;
auto int status;
static const char steps[]
= "select"
" steps.idx"
// idx must be the first column
", steps.active"
", steps.data"
", steps.flags"
", steps.max_length"
", steps.min_length"
", steps.prompt"
", steps.retry_prompt"
", steps.type"
" from"
" dnises"
", recipes"
", steps"
" where '%s' = dnis"
" and dnises.recipe = recipes.recipe"
" and recipes.recipe = steps.recipe"
" order by idx"
;
// look for the recipe parameters
exec_sql(&mysql
, &result_pointer
, recipes // select statement template
, dnis_pointer // dnis
);
// complain if not found
if ((1 != mysql_num_rows(result_pointer))
|| ((0 == (mysql_row = mysql_fetch_row(result_pointer)))))
{
syslog(LOG_ERR
, "No setup for DNIS %s in the DNISES"
" and RECIPES tables."
, dnis_pointer
);
return(EXIT_FAILURE);
}
// set the variables
num_fields = mysql_num_fields(result_pointer);
fields = mysql_fetch_fields(result_pointer);
for (column = 0; column < num_fields; ++column)
{
auto char *pointer;
auto char temp[256];
if ((0 == mysql_row[column])
|| ('(' == *mysql_row[column]))
{
continue;
}
strcpy(temp, fields[column].name);
pointer = temp;
while (0 != *pointer)
{
if (islower(*pointer))
{
*pointer = toupper(*pointer);
}
if ('_' == *pointer)
{
*pointer = '-';
}
++pointer;
}
syslog(LOG_DEBUG, "%s = \"%s\"", temp, mysql_row[column]);
agi_set_variable(temp, mysql_row[column]);
}
// look for the step parameters
status = exec_sql(&mysql
, &result_pointer
, steps // select statement template
, dnis_pointer // dnis
);
if (0 != status)
{
syslog(LOG_ERR
, "%m, mysql_error = \"%s\""
, mysql_error(&mysql)
);
}
// complain if not found
if (1 > (num_rows = mysql_num_rows(result_pointer)))
{
syslog(LOG_ERR
, "No setup for DNIS %s in the DNISES,"
" RECIPES, and STEPS tables."
, dnis_pointer
);
return(EXIT_FAILURE);
}
// walk through the rows
for (index = 0; ; ++index)
{
mysql_data_seek(result_pointer, index);
if (0 == (mysql_row = mysql_fetch_row(result_pointer)))
{
break;
}
// set the variables
num_fields = mysql_num_fields(result_pointer);
fields = mysql_fetch_fields(result_pointer);
for (column = 0; column < num_fields; ++column)
{
auto char *pointer;
auto char temp[256];
if ((0 == mysql_row[column])
|| ('(' == *mysql_row[column]))
{
continue;
}
sprintf(temp
, "STEP-%02d-%s"
, atoi(mysql_row[0])
, fields[column].name
);
pointer = temp + 5;
while (0 != *pointer)
{
if (islower(*pointer))
{
*pointer = toupper(*pointer);
}
if ('_' == *pointer)
{
*pointer = '-';
}
++pointer;
}
syslog(LOG_DEBUG, "%s = \"%s\"", temp, mysql_row[column]);
agi_set_variable(temp, mysql_row[column]);
}
}
// free the result set
mysql_free_result(result_pointer);
// set the agi status
agi_set_status_failure();
// function exit
return(EXIT_SUCCESS);
}
// (end of lookup-dnis.c)
--
Thanks in advance,
-------------------------------------------------------------------------
Steve Edwards sedwards at sedwards.com Voice: +1-760-468-3867 PST
Newline Fax: +1-760-731-3000
More information about the asterisk-users
mailing list