提交 e0a49c35 authored 作者: Nazim Aghabayov's avatar Nazim Aghabayov

Initial import of xmlcdrd

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk/contrib@16974 d0543943-73ff-0310-b7d9-9358b9ac24b2
上级 657951b9
Nazim Aghabayov
mail-to: nazim.aghabayov at buta-tech.com
差异被折叠。
SHELL = /bin/sh
VPATH = @srcdir@
confdir = "/etc/xmlcdrd"
subdirs = @subdirs@
top_srcdir = @top_srcdir@
srcdir = @srcdir@
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = $(exec_prefix)/bin
infodir = $(prefix)/info
libdir = $(prefix)/lib
includedir = $(prefix)/include
mandir = $(prefix)/man/man1
snapshot = $(srcdir)/../`date +xmlcdr_%Y%m%d_%H%M`
CC = @CC@
CPPFLAGS = @CPPFLAGS@
CFLAGS = $(CPPFLAGS) -fPIC -Wall @CFLAGS@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
INCS = @INCS@
INSTALL = @INSTALL@
all:
$(CC) $(CFLAGS) @with_glib2_flags@ -c stmtexpldr.c
$(CC) $(CFLAGS) @with_glib2_flags@ -lconfig -c stmtexp.c
$(CC) $(CFLAGS) @with_glib2_flags@ -c plug.c
$(CC) $(CFLAGS) @with_glib2_flags@ -c plugldr.c
$(CC) $(CFLAGS) -c log.c
$(CC) $(CFLAGS) `@with_apreq2_config@ --libs --includes` \
`@with_apr_config@ --libs --includes --cppflags` @with_glib2_flags@ -c urldecode.c
if BUILDMYSQLCDR
$(MAKE) -C plugins/mysqlcdr
endif
if BUILDLUAEXEC
$(MAKE) -C plugins/luaexec
endif
$(CC) $(CFLAGS) \
`@with_apreq2_config@ --libs --includes` \
`@with_apr_config@ --libs --includes --cppflags --link-ld ` \
@with_glib2_flags@ -lglib-2.0 \
`@with_xml2_config@ --cflags --libs` \
$(LIBS) \
stmtexpldr.o stmtexp.o log.o urldecode.o \
plugldr.o plug.o \
-o xmlcdr.fcgi main.c
snapshot:
-tar --exclude-vcs -zcf $(snapshot).tgz -R $(srcdir) ; fi
install:
-cp xmlcdr.fcgi $(bindir)/
-if [ ! -d $(confdir) ]; then mkdir $(confdir); fi
-cp conf/* $(confdir)/
if BUILDMYSQLCDR
$(MAKE) -C plugins/mysqlcdr install
endif
if BUILDLUAEXEC
$(MAKE) -C plugins/luaexec install
endif
clean:
-rm -f *.o xmlcdr.fcgi
if BUILDMYSQLCDR
$(MAKE) -C plugins/mysqlcdr clean
endif
if BUILDLUAEXEC
$(MAKE) -C plugins/luaexec clean
endif
#!/bin/sh
aclocal
autoconf
autoheader
automake
rm -rf autom4te*.cache
dbuserid="ddp";
dbpasswd="password";
dbschema="ddp";
dbipaddr="localhost";
dbipport=3306;
stmt_template="insert into cdr (caller_id_number, effective_caller_id_number, destination_number, billsec) values ('$<caller_id_number>','$<effective_caller_id_number>', '$<destination_number>', $<billsec>)";
## bind to port (default: 80)
server.port = 8080
server.modules = (
"mod_access",
"mod_alias",
"mod_accesslog",
"mod_compress",
"mod_fastcgi"
)
fastcgi.debug = 1
server.document-root = "/home/nazim/www/"
server.errorlog = "/home/nazim/var/log/lighttpd/error.log"
index-file.names = ( "index.php", "index.html",
"index.htm", "default.htm",
"index.lighttpd.html" )
accesslog.filename = "/home/nazim/var/log/lighttpd/access.log"
url.access-deny = ( "~", ".inc" )
static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )
server.pid-file = "/home/nazim/var/run/lighttpd.pid"
dir-listing.encoding = "utf-8"
server.dir-listing = "enable"
server.username = "www-data"
server.groupname = "www-data"
compress.cache-dir = "/home/nazim/var/cache/lighttpd/compress/"
compress.filetype = ("text/plain", "text/html", "application/x-javascript", "text/css")
include_shell "/usr/share/lighttpd/create-mime.assign.pl"
include_shell "/usr/share/lighttpd/include-conf-enabled.pl"
$HTTP["remoteip"] == "127.0.0.1" {
alias.url += (
"/doc/" => "/usr/share/doc/",
"/images/" => "/usr/share/images/"
)
$HTTP["url"] =~ "^/doc/|^/images/" {
dir-listing.activate = "enable"
}
}
fastcgi.server = (
"xmlcdr.fcgi" =>
( "localhost" =>
(
"socket" => "/home/nazim/tmp/lighttpd-cdr-fcgi.socket",
"max-procs" => 5,
"bin-path" => "/home/nazim/prj/buta/xmlcdr/trunk/xmlcdr.fcgi",
"check-local" => "disable"
)
)
)
luascript = "/etc/xmlcdrd/test.lua";
--print(xcdr_varget("uuid"), xcdr_varget("billsec"), xcdr_varget("uuid") )
uuid = xcdr_varget("uuid")
billsec = xcdr_varget("billsec")
require "luasql.odbc"
env = assert(luasql.odbc())
db_conn = assert(env:connect("ddp") )
db_conn:execute(string.format("insert into cdr (uuid,billsec) values ('%s', %d)", uuid, billsec))
db_conn:close()
env:close()
--local file = assert(io.open("output.lua", "w"))
--file:write("Hello world\n")
--file:close()
#Copy this file to /etc/xmlcdrd/xmlcdr.conf
#Variables section
Variables = (
{
name = "uuid";
var_id = "uuid";
xpath = "/cdr/callflow[@profile_index='1']/caller_profile/uuid";
}
,
{
name = "context";
var_id = "context";
xpath = "/cdr/callflow[@profile_index='1']/caller_profile/context";
}
,
{
name = "effective_caller_id_number";
var_id = "effective_caller_id_number";
xpath = "/cdr/variables/effective_caller_id_number";
}
,
{
name = "caller_id_number";
var_id = "caller_id_number";
xpath = "/cdr/callflow[@profile_index='1']/caller_profile/caller_id_number";
}
,
{
name = "destination_number";
var_id = "destination_number";
xpath = "/cdr/callflow[@profile_index='1']/caller_profile/destination_number";
}
,
{
name = "profile_destination_number";
var_id = "profile_destination_number";
xpath = "/cdr/callflow[@profile_index='1']/caller_profile/originatee/originatee_caller_profile/destination_number";
}
,
{
name = "callgroup";
var_id = "callgroup";
xpath = "/cdr/variables/planeta_callgroup";
}
,
{
name = "billsec";
var_id = "billsec";
xpath = "/cdr/variables/billsec";
}
,
{
name = "startep";
var_id = "startep";
xpath = "/cdr/variables/start_epoch";
}
,
{
name = "answep";
var_id = "answep";
xpath = "/cdr/variables/answer_epoch";
}
,
{
name = "endep";
var_id = "endep";
xpath = "/cdr/variables/end_epoch";
}
);
#End of Variables
#Plugins directory
plugin_dir = "/usr/local/lib/xmlcdrd";
#Plugins section
Plugins = (
#Plugin declaration
{
#name is a name of so file without the extension
name="mysqlcdr";
#config file for plugin
options = "/etc/xmlcdrd/db1.conf";
priority = 10;
#Metrics control plugin execution
#Plugin with no metrics defined will be executed everytime
Metrics = (
{
metric = "destination_number";
regexp = "^6969.*";
}
);
#end of metrics
},
{
name="luaexec";
options="/etc/xmlcdrd/luaexec.conf";
priority=20;
}
#End of plugin declaration
#You could define multiple plugins
#Plugin declarations are separated with comma. See libconfig manual for details.
);
#End of Plugin section
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.6])
AC_INIT([xmlcdrd], [0.1], [xmlcdr@buta-tech.com])
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([urldecode.c])
AC_CONFIG_HEADERS([config.h])
# Checks for programs.
AC_PROG_CC
AC_PROG_INSTALL
# Checks for libraries.
AC_CHECK_LIB([apreq2], [main])
AC_CHECK_LIB([apr-1], [main])
AC_CHECK_LIB([config], [main])
AC_CHECK_LIB([dl], [main])
AC_CHECK_LIB([fcgi], [main])
AC_CHECK_LIB([pcre], [main])
AC_CHECK_LIB([glib-2.0], [main])
AC_CHECK_LIB([xml2], [main])
# Checks for header files.
AC_CHECK_HEADERS([malloc.h stdlib.h string.h syslog.h])
#check for library config scripts
AC_MSG_CHECKING(for apreq2config)
AC_ARG_WITH(apreq2_config,
AC_HELP_STRING([--with-apreq2-config@<:@=PATH@:>@],[Location of apreq2 configuration script.]),
[with_apreq2_config="$withval"],[with_apreq2_config="apreq2-config"])
AC_SUBST(with_apreq2_config)
AC_MSG_CHECKING(for aprconfig)
AC_ARG_WITH(apr_config,
AC_HELP_STRING([--with-apr-config@<:@=PATH@:>@],[Location of apr configuration script.]),
[with_apr_config="$withval"],[with_apr_config="apr-1-config"])
AC_SUBST(with_apr_config)
AC_MSG_CHECKING(for mysqlconfig)
AC_ARG_WITH(mysql_config,
AC_HELP_STRING([--with-mysql-config@<:@=PATH@:>@],[Location of mysql configuration script.]),
[with_mysql_config="$withval"],[with_mysql_config="mysql_config"])
AC_SUBST(with_mysql_config)
AC_MSG_CHECKING(for xml2config)
AC_ARG_WITH(xml2_config,
AC_HELP_STRING([--with-xml2-config@<:@=PATH@:>@],[Location of libxml2 configuration script.]),
[with_xml2_config=="$withval"],[with_xml2_config="xml2-config"])
AC_SUBST(with_xml2_config)
AC_MSG_CHECKING(for glib2 flags)
AC_ARG_WITH(glib2_flags,
AC_HELP_STRING([--with-glib2-flags],[glib2 CFLAGS.]),
[with_glib2_flags="$withval"],[with_glib2_flags="-I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include"])
AC_SUBST(with_glib2_flags)
#Plugins to build
#mysqlcdr
domysqlcdr=yes
AC_ARG_ENABLE(mysqlcdr,
AS_HELP_STRING([--disable-mysqlcdr], [Disable building of mysqlcdr plugin]),
[if test "$enableval" = "no"; then domysqlcdr="no"; fi],
[
domysqlcdr=yes
]
)
AM_CONDITIONAL(BUILDMYSQLCDR, test x$domysqlcdr = xyes)
#luaexec
doluaexec=yes
AC_ARG_ENABLE(luaexec,
AS_HELP_STRING([--disable-luaexec], [Disable building of luaexec plugin]),
[if test "$enableval" = "no"; then doluaexec="no"; fi],
[
doluaexec=yes
]
)
AM_CONDITIONAL(BUILDLUAEXEC, test x$doluaexec = xyes)
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.
AC_FUNC_MALLOC
AC_FUNC_REALLOC
AC_CHECK_FUNCS([memset strchr strdup strstr])
AC_CONFIG_FILES([Makefile
plugins/mysqlcdr/Makefile
plugins/luaexec/Makefile])
AC_OUTPUT
差异被折叠。
#include "log.h"
#include <syslog.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
void syslog_open (const char *ident, int facility) {
openlog(ident, LOG_PID, facility);
return;
}
void syslog_close () {
closelog ();
return;
}
void syslog_error (const char *message) {
syslog (LOG_ALERT, "error. %s", message);
}
void syslog_msg (int priority, int echotoconsole, const char *fmt, ...) {
int n, size;
char *p;
va_list ap;
size = 100;
if (NULL == (p = malloc (size))) {
fprintf (stderr, "syslog_msg failed. malloc error %s:%d\r\n", __FILE__, __LINE__);
return;
}
while (1) {
va_start(ap, fmt);
n = vsnprintf (p, size, fmt, ap);
va_end(ap);
if (n > -1 && n < size) {
syslog (priority, "%s", p);
if (echotoconsole) fprintf (stderr, "%s\r\n", p);
free (p);
return;
}
if (n > -1) size = n+1;
else size *= 2;
if ((p = realloc (p, size)) == NULL) {
fprintf (stderr, "syslog_msg failed. realloc error %s:%d\r\n", __FILE__, __LINE__);
return;
}
}
}
#ifndef LOG_H
#define LOG_H
#include <stdlib.h>
void syslog_open (const char *ident, int facility);
void syslog_close (void);
void syslog_msg (int priority, int echotoconsole, const char *fmt, ...);
void syslog_error (const char *message);
#endif
#include <fcgi_stdio.h> /* fcgi library; put it first*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>
#include <libxml/tree.h>
#include <libxml/parser.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>
#include "log.h"
#include "urldecode.h"
#include "stmtexp.h"
#include "stmtexpldr.h"
#include "plugldr.h"
#include "plug.h"
#define STR_MAX 512
#define CONFIG "/etc/xmlcdrd/xmlcdr.conf"
#define XURL_CDR "cdr"
typedef struct
{
xmlDocPtr doc;
xmlXPathContextPtr xpathCtx;
} stmtexp_cb_data_t;
#if defined(LIBXML_XPATH_ENABLED) && defined(LIBXML_SAX1_ENABLED)
stmtexp_tab_t vex;
void stmtexp_callback (stmtexp_key_t *key, stmtexp_val_t *val, void *userdata);
void stmtexp_callback_clean (stmtexp_key_t *key, stmtexp_val_t *val,
void *userdata);
int execute_xpath_expression(const char* buf, int buflen);
int execute_xpath_expression(const char* buf, int buflen)
{
xmlDocPtr doc;
stmtexp_cb_data_t cbd;
memset (&cbd, 0x0, sizeof (stmtexp_cb_data_t));
/* Load XML document */
doc = xmlParseMemory (buf, buflen);
if (doc == NULL)
{
fprintf(stderr, "Error: unable to parse memory\n");
return(-1);
}
/* Create xpath evaluation context */
cbd.xpathCtx = xmlXPathNewContext(doc);
if(cbd.xpathCtx == NULL)
{
fprintf(stderr,"Error: unable to create new XPath context\n");
xmlFreeDoc(doc);
return(-1);
}
/*run callback*/
stmtexp_foreach_callback (&vex, stmtexp_callback, &cbd);
xmlXPathFreeContext(cbd.xpathCtx);
xmlFreeDoc(doc);
return(0);
}
void stmtexp_callback_clean (stmtexp_key_t *key, stmtexp_val_t *val, void *userdata)
{
if (NULL != val)
{
if (NULL != val->val)
{
free (val->val);
val->val = NULL;
}
}
}
void stmtexp_callback (stmtexp_key_t *key, stmtexp_val_t *val, void *userdata)
{
xmlXPathObjectPtr xpathObj;
xmlNodePtr cur;
stmtexp_cb_data_t * cbd = (stmtexp_cb_data_t *) userdata;
/* Evaluate xpath expression */
xpathObj = xmlXPathEvalExpression((xmlChar*)key->xpath, cbd->xpathCtx);
if(xpathObj == NULL)
{
fprintf(stderr,
"Error: unable to evaluate xpath expression \"%s\"\n",
key->xpath);
return;
}
/* Print results */
xmlNodeSetPtr nodes = xpathObj->nodesetval;
if (NULL != nodes)
{
if (0 < nodes->nodeNr)
{
if (nodes->nodeTab[0])
{
if(nodes->nodeTab[0]->type == XML_ELEMENT_NODE)
{
cur = nodes->nodeTab[0];
if(cur->ns)
{
fprintf(stderr, "= element node \"%s:%s\"\n",
cur->ns->href, cur->name);
} else
{
fprintf(stderr, "= element node \"%s\"\n",
cur->name);
xmlChar *content = xmlNodeGetContent(cur);
if (NULL != val)
{
if (NULL != val->val)
{
free (val->val);
val->val = NULL;
}
val->val = strdup((const char*)content);
fprintf(stderr, "%s\n", val->val);
xmlFree (content);
}
}
}
}
} else /* if (0 < nodes->nodeNr) */
{
if (NULL != val)
{
if (NULL != val->val)
{
free (val->val);
val->val = NULL;
}
}
}
}
/* Cleanup */
xmlXPathFreeObject(xpathObj);
}
/*
*
*/
int main(int argc, char** argv)
{
XCDR_PLUGTAB plugtab;
if (-1 == xcdr_plugldr_load_config(&plugtab, CONFIG))
{
fprintf (stderr, "Failed to configure plugins from config: '%s'", CONFIG);
return -1;
}
if (-1 == xcdr_plugldr_load_plugins(&plugtab) )
{
fprintf (stderr, "Failed to load plugins from config: '%s'", CONFIG);
xcdr_plugldr_free_plugins (&plugtab);
return -1;
}
if (-1 == stmtexp_load_config (&vex, CONFIG))
{
fprintf (stderr, "Failed to load vars from config: '%s'", CONFIG);
xcdr_plugldr_free_plugins (&plugtab);
stmtexp_free (&vex);
return -1;
}
/* Init libxml */
xmlInitParser();
LIBXML_TEST_VERSION
GString * cgi_req_str = g_string_sized_new (102400);
GString * cgi_decoded_str = g_string_sized_new (102400);
GString * temp = g_string_sized_new (102400);
while (FCGI_Accept() >= 0)
{
//Set length of received request to 0
int cgi_req_len = 0;
g_string_set_size (cgi_req_str, 0);
char c;
while (EOF != (c = fgetc (stdin)) )
{
g_string_append_c (cgi_req_str, c);
cgi_req_len++;
} //~while We have received the full request string
//fprintf (stderr, "%s\n", cgi_req_str->str);
stmtexp_foreach_callback (&vex, stmtexp_callback_clean, NULL);
int decoded_len = cgi_req_len * 3 + 1;
g_string_set_size (cgi_decoded_str, decoded_len);
memset (cgi_decoded_str->str, 0x0, decoded_len);
int status;
if (NULL != urldecode_expand_value (cgi_req_str,
XURL_CDR, strlen(XURL_CDR),
1,
temp, &status,
cgi_decoded_str))
{
execute_xpath_expression(cgi_decoded_str->str,
strlen(cgi_decoded_str->str) );
/*Dump entire dom tree on stdout*/
//fprintf (stderr, "%s\n", cgi_decoded_str->str);
int i;
XCDR_PLUGINFO *plug;
for (i = 0; i < plugtab.tag_count; i ++)
{
plug = &plugtab.tags[i].plug;
//If no metrics defined, run anyway
if (0 == plugtab.tags[i].metrics.tag_count)
{
plug->plugin_main(&vex, &plug->state);
continue;
}
//match metric regexps
int j;
int run = 0;
for (j = 0; j < plugtab.tags[i].metrics.tag_count; j++)
{
const char *metric_val =
stmtexp_lookup_var (&vex,
plugtab.tags[i].metrics.tags[j].metric);
//if metric is not found, replace with an empty string.
if (NULL == metric_val)
{
metric_val = "";
}
fprintf (stderr, "metric [%s] '%s':'%s'\n",
plugtab.tags[i].metrics.tags[j].metric,
plugtab.tags[i].metrics.tags[j].regexp,
metric_val);
if (-1 <
xcdr_plugldr_match_regexp (
plugtab.tags[i].metrics.tags[j].regexp,
metric_val, strlen(metric_val)) )
run = 1;
else run = 0;
}
if (0 < run)
{
fprintf (stderr, "metrics matched\n");
plug->plugin_main(&vex, &plug->state);
}
}
} else fprintf (stderr, "'%s' not found in '%s'\n",
XURL_CDR, cgi_req_str->str);
}
g_string_free (cgi_req_str, TRUE);
g_string_free (cgi_decoded_str, TRUE);
g_string_free (temp, TRUE);
stmtexp_free (&vex);
xcdr_plugldr_free_plugins(&plugtab);
xmlCleanupParser();
return 0;
}
#else
int main(void) {
fprintf(stderr, "XPath support not compiled in\n");
exit(1);
}
#endif
差异被折叠。
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include "plug.h"
/*returns 0 on success, -1 on error*/
int plug_init(const char *filename, const char *options,
XCDR_PLUGINFO *plug)
{
char *error;
if (NULL == (plug->handle = dlopen(filename, RTLD_LAZY | RTLD_GLOBAL)))
{
fprintf(stderr, "%s\r\n", dlerror());
return -1;
}
//clear any existing dl error.
dlerror();
*(void **) (&plug->plugin_get_name) = dlsym(plug->handle, "plugin_get_name");
if ((error = dlerror()) != NULL)
{
fprintf(stderr, "%s\n", error);
return -1;
}
dlerror();
*(void **) (&plug->plugin_get_description) = dlsym(plug->handle, "plugin_get_description");
if ((error = dlerror()) != NULL)
{
fprintf(stderr, "%s\n", error);
return -1;
}
dlerror();
*(void **) (&plug->plugin_init) = dlsym(plug->handle, "plugin_init");
if ((error = dlerror()) != NULL)
{
fprintf(stderr, "%s\n", error);
return -1;
}
dlerror();
*(void **) (&plug->plugin_free) = dlsym(plug->handle, "plugin_free");
if ((error = dlerror()) != NULL)
{
fprintf(stderr, "%s\n", error);
return -1;
}
dlerror();
*(void **) (&plug->plugin_main) = dlsym(plug->handle, "plugin_main");
if ((error = dlerror()) != NULL)
{
fprintf(stderr, "%s\n", error);
return -1;
}
strncpy(plug->name, plug->plugin_get_name(), XCDR_PLUGIN_NAME_LEN_MAX);
if (-1 == plug->plugin_init(filename, options, &plug->state))
{
fprintf(stderr, "Failed to load plugin:'%s' InternalName:'%s' Options:'%s'\n", plug->name, filename, options);
return -1;
}
return 0;
}
int plug_free(XCDR_PLUGINFO *plug)
{
if (NULL != plug->handle)
{
plug->plugin_free(&plug->state);
}
return 0;
}
int plug_destroy(XCDR_PLUGINFO *plug)
{
if (NULL != plug->handle)
{
return dlclose(plug->handle);
}
return 0;
}
#ifndef PLUG_H
#define PLUG_H
#include "plugcommon.h"
#include "stmtexptab.h"
typedef struct xcdr_plugin_info
{
void *handle;
char name [XCDR_PLUGIN_NAME_LEN_MAX];
XCDR_PLUGSTATE state;
/*Functions exported by plugin*/
int (*plugin_init) (const char *filename, const char *options,
XCDR_PLUGSTATE *state);
int (*plugin_free) (XCDR_PLUGSTATE *state);
char* (*plugin_get_description) (void);
char* (*plugin_get_name) (void);
/*
Main function which processes a hash table of variables/values @vex
Function returns:
PLUG_STATUS_OK
PLUG_STATUS_ERR */
int (*plugin_main) (STMTEXP_TAB *vex, XCDR_PLUGSTATE *state);
/* ~Functions exported by plugin*/
} XCDR_PLUGINFO, *PXCDR_PLUGINFO;
/* plug_int() calls plugin_init() which initializes
XCDR_PLUGSTATE.state used by plugin internally */
int plug_init (const char *filename, const char *options, XCDR_PLUGINFO *plug);
/* plug_free() calls plugin_free() to deallocate all dynamic resources
bound to XCDR_PLUGSTATE.local_vars. Must be invoked before plug_destroy() */
int plug_free (XCDR_PLUGINFO *plug);
/* plug_destroy() calls library dlclose() AFTER plug_free() */
int plug_destroy(XCDR_PLUGINFO *plug);
#endif
#ifndef PLUGCOMMON_H
#define PLUGCOMMON_H
#define XCDR_PLUGIN_NAME_LEN_MAX 64
#define XCDR_PLUGIN_FILENAME_LEN_MAX 256
#define XCDR_PLUGIN_STRMAXLEN 256
#define PLUG_STATUS_OK 0
//#define PLUG_STATUS_STOPPROCESSING_HERE 1
#define PLUG_STATUS_ERROR -1
typedef struct xcdr_plugin_state
{
/* local_vars are initialized by plugin during plugin_init
and destroyed in plugin_free
*/
void *local_vars;
} XCDR_PLUGSTATE, *PXCDR_PLUGSTATE;
#endif
SHELL = /bin/sh
CC = @CC@
FLAGS= -W -Wmissing-prototypes -Wstrict-prototypes -g3 -Wall $(CFLAGS)
all:
$(CC) $(CFLAGS) \
-shared -fPIC -o luaexec.so luaexec.c \
-I../../ \
@with_glib2_flags@ \
-llua -ldl -lglib-2.0 \
-lconfig \
../../stmtexpldr.o ../../stmtexp.o ../../log.o
install:
-cp luaexec.so $(libdir)/xmlcdrd/
clean:
-rm -f *.o luaexec.so
/*
plugin_init() accepts single option - absolute name of configuration file to parse.
*/
#include "plugcommon.h"
#include "plug.h"
#include "stmtexp.h"
#include "log.h"
#include <syslog.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libconfig.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#include <dlfcn.h>
#define PLUGIN_NAME "lua exec"
#define PLUGIN_DESC "Lua script wrapper"
#define FILENAME_LEN_MAX 512
#define STR_LEN_MAX 256
/*that's what lua script would call to get variable*/
#define LUA_VAR_GET_FUNC "xcdr_varget"
typedef struct luaexec_local_vars
{
char *t;
int cfgres;
config_t cfg;
config_setting_t *setting;
luaL_reg *lualibs;
int lualibs_count;
char luascript [FILENAME_LEN_MAX];
lua_State *L;
STMTEXP_TAB *vex;
} LUAEXECVARS;
/*Local variables*/
LUAEXECVARS *vars;
char * plugin_get_name ()
{
return PLUGIN_NAME;
}
char * plugin_get_description ()
{
return PLUGIN_DESC;
}
static int l_varget (lua_State *L)
{
const char* varid = luaL_checkstring(L, 1);
const char* val = stmtexp_lookup_var (vars->vex, varid);
lua_pushstring(L, val);
return 1;
}
/**/
int plugin_init (const char* filename, const char *options, XCDR_PLUGSTATE *state)
{
int i;
vars = calloc (1, sizeof(LUAEXECVARS) );
state->local_vars = vars;
if (NULL == vars)
{
fprintf (stderr,
"%s plugin_init(). Can't allocate memory for state vars\n",
PLUGIN_NAME);
return PLUG_STATUS_ERROR;
}
fprintf (stderr, "%s plugin_init (%s) \n", PLUGIN_NAME, options);
config_init(&vars->cfg);
if (!config_read_file(&vars->cfg, options) )
{
fprintf (stderr, "%s plugin_init (%s). Error parsing: '%s'\n",
PLUGIN_NAME, options, options);
config_destroy(&vars->cfg);
return PLUG_STATUS_ERROR;
}
memset (vars->luascript , 0x0, FILENAME_LEN_MAX);
const char *t = NULL;
if (CONFIG_TRUE == config_lookup_string (&vars->cfg, "luascript", &t) )
snprintf (vars->luascript, FILENAME_LEN_MAX - 1, "%s", t);
config_destroy(&vars->cfg);
return PLUG_STATUS_OK;
}
int plugin_free (XCDR_PLUGSTATE *state)
{
vars = state->local_vars;
free (vars);
return PLUG_STATUS_OK;
}
int plugin_main (STMTEXP_TAB *vex, XCDR_PLUGSTATE *state)
{
vars = state->local_vars;
vars->vex = vex;
vars->L = lua_open();
luaL_openlibs (vars->L);
lua_pushcfunction(vars->L, l_varget);
lua_setglobal(vars->L, LUA_VAR_GET_FUNC);
if (luaL_loadfile(vars->L, vars->luascript) )
fprintf(stderr, "can't load file: %s, %s\n", vars->luascript,
lua_tostring(vars->L, -1));
if(lua_pcall(vars->L, 0, 0, 0) )
fprintf(stderr, "can't run file: %s, %s\n", vars->luascript,
lua_tostring(vars->L, -1));
lua_close (vars->L);
return PLUG_STATUS_OK;
}
SHELL = /bin/sh
CC = @CC@
FLAGS= -W -Wmissing-prototypes -Wstrict-prototypes -fPIC -g3 -Wall $(CFLAGS)
all:
$(CC) $(CFLAGS) -fPIC -W -Wall -I../../ `@with_mysql_config@ --include` -c dbcommon.c
$(CC) $(CFLAGS) \
-shared -fPIC -o mysqlcdr.so mysqlcdr.c \
-I../../ \
`@with_mysql_config@ --libs --include` \
@with_glib2_flags@ \
-lconfig -lglib-2.0 \
dbcommon.o \
../../stmtexpldr.o ../../stmtexp.o ../../log.o
install:
cp mysqlcdr.so $(libdir)/xmlcdrd/
clean:
-rm -f *.o mysqlcdr.so
#include <stdio.h>
#include <syslog.h>
#include "dbcommon.h"
#include "string.h"
#include "log.h"
MYSQL *mysql_do_connect(char *host_name,
char *user_name, char *password, char *db_name,
unsigned long port_num, char *socket_name,
unsigned int flags)
{
MYSQL *conn; /* pointer to connection handler */
conn = mysql_init(NULL); /* allocate, initialize connection handler */
if (conn == NULL)
{
//fprintf (stderr, "mysql_init() failed\n");
syslog_error("mysql_init() failed");
return (NULL);
}
my_bool reconnect = 1;
mysql_options(conn, MYSQL_OPT_RECONNECT, &reconnect);
if (mysql_real_connect(conn, host_name, user_name, password,
db_name, port_num, socket_name, flags) == NULL)
{
fprintf (stderr, "mysql_real_connect() failed:\nError %u (%s)\n", mysql_errno (conn), mysql_error (conn));
//syslog_mysql_error(conn, "error. mysql_real_connect() failed");
return (NULL);
}
return (conn);
}
void mysql_do_disconnect(MYSQL *conn)
{
mysql_close(conn);
}
void mysql_print_error(MYSQL *conn, char *message)
{
if (conn != NULL)
{
syslog_msg(LOG_ALERT, 1, "MySQL connection error. '%s'. %u (%s)",
message, mysql_errno(conn), mysql_error(conn));
fprintf (stderr, "MySQL connection error. '%s'. %u (%s)",
message, mysql_errno(conn), mysql_error(conn));
}
else
{
fprintf (stderr, "MySQL connection error. \
'%s'. Can't get mysql_errno() because connection handler is invalid", message);
syslog_msg(LOG_ALERT, 0,
"MySQL connection error. \
'%s'. Can't get mysql_errno() because connection handler is invalid", message);
}
}
#ifndef DBCOMMON_H
#define DBCOMMON_H
#include <mysql.h>
MYSQL *mysql_do_connect (char *host_name,
char *user_name, char *password, char *db_name,
unsigned long port_num, char *socket_name, unsigned int flags);
void mysql_do_disconnect (MYSQL *conn);
void mysql_print_error (MYSQL *conn, char *message);
#endif
/*
plugin_init() accepts single option - absolute name of configuration file to parse.
*/
#include "plugcommon.h"
#include "plug.h"
#include "stmtexp.h"
#include "log.h"
#include <syslog.h>
#include <mysql.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libconfig.h>
#include <glib.h>
#define PLUGIN_NAME "mysql cdr"
#define PLUGIN_DESC "MySQL cdr logger"
#define STMT_RETRY_MAX 2
#define MYSQL_IPPORT 3306
/* Statement expansion */
#define VARSTART "$<"
#define VAREND ">"
#define VARSTART_LEN strlen (VARSTART)
#define VAREND_LEN strlen (VAREND)
#define VARID_LEN 512
#define TEMP_GSTRING_INIT_SIZE 1024
#define STMT_TEMPLATE_MAX_LEN 40960
typedef struct mysqlcdr_local_vars
{
unsigned int sql_insert_retry_max;
GString *temp;
MYSQL *conn;
char dbuserid [XCDR_PLUGIN_STRMAXLEN];
char dbpasswd [XCDR_PLUGIN_STRMAXLEN];
char dbschema [XCDR_PLUGIN_STRMAXLEN];
char dbipaddr [XCDR_PLUGIN_STRMAXLEN];
unsigned int dbipport;
unsigned long dbflags;
char stmt_template [STMT_TEMPLATE_MAX_LEN];
char *t;
int cfgres;
config_t cfg;
} MYSQLCDRVARS;
/*Local variables*/
MYSQLCDRVARS *vars;
int mysql_query_retry_on_fail (MYSQL *conn, const char *stmt,
unsigned int retrycount)
{
unsigned int rc = 0;
int res;
while (rc++ <= retrycount)
{
res = mysql_query (conn, stmt);
if (0 != res)
{
mysql_print_error (conn, "mysql_query() failed.");
if (-1 == mysql_ping(conn) )
fprintf (stderr, "Connection to db lost\n");
} else return res;
}
}
/*Returns NULL if escaping of string fails*/
const char *mysqlcdr_expand_str (MYSQL *conn, stmtexp_tab_t *vex,
const char *src, int srclen)
{
const char *s; //src
char *e; //end
char varid [VARID_LEN];
s = src;
g_string_set_size (vex->expanded, 0);
//fprintf (stderr, "mysqlcdr_expand_str '%s'\n", src);
while (s < src + srclen)
{
if (NULL != (e = strstr (s, VARSTART)) )
{
g_string_append_len (vex->expanded, s, e - s);
s = e++;
if (NULL != (e = strstr (s, VAREND)) )
{
/* Remove placeholders VARSTART and VAREND, then lookup */
memset (varid, 0x0, VARID_LEN);
strncpy (varid, s + VARSTART_LEN, (e - s) - VARSTART_LEN );
const char* ev = stmtexp_lookup_var (vex, varid);
//fprintf (stderr, "---%s\n", ev);
if (NULL != ev)
{
unsigned int ev_len = strlen(ev);
g_string_set_size (vars->temp, (ev_len * 2) + 1);
memset (vars->temp->str, 0x0, (ev_len * 2) + 1);
unsigned long res = mysql_real_escape_string (
conn,
vars->temp->str,
ev,
ev_len
);
/*if length of escaped string is less than input bail out*/
if (res < ev_len)
return NULL;
/*append expanded var to destination*/
g_string_append (vex->expanded, vars->temp->str);
}
else
{
/*variable was not found, skip it*/
}
s = e + 1;
//fprintf (stderr, "s: '%s'\n", s);
}
else /*no more signatures found, append the rest of the str*/
{
if (NULL != s)
g_string_append (vex->expanded, s);
break;
}
}
else /*no more signatures found, append the rest of the str*/
{
if (NULL != s)
g_string_append (vex->expanded, s);
break;
}
}//while (s < src + src_len)
return vex->expanded->str;
}
char * plugin_get_name ()
{
return PLUGIN_NAME;
}
char * plugin_get_description ()
{
return PLUGIN_DESC;
}
/**/
int plugin_init (const char* filename, const char *options, XCDR_PLUGSTATE *state)
{
vars = calloc (1, sizeof(MYSQLCDRVARS) );
state->local_vars = vars;
if (NULL == vars)
{
fprintf (stderr,
"%s plugin_init(). Can't allocate memory for state vars\n",
PLUGIN_NAME);
return PLUG_STATUS_ERROR;
}
fprintf (stderr, "%s plugin_init (%s) \n", PLUGIN_NAME, options);
vars->temp = g_string_sized_new (TEMP_GSTRING_INIT_SIZE);
config_init(&vars->cfg);
if (!config_read_file(&vars->cfg, options) )
{
fprintf (stderr, "%s plugin_init (%s). Error parsing: '%s'\n",
PLUGIN_NAME, options, options);
config_destroy(&vars->cfg);
return PLUG_STATUS_ERROR;
}
memset (vars->dbuserid, 0x0, XCDR_PLUGIN_STRMAXLEN);
memset (vars->dbpasswd, 0x0, XCDR_PLUGIN_STRMAXLEN);
memset (vars->dbipaddr, 0x0, XCDR_PLUGIN_STRMAXLEN);
memset (vars->dbschema, 0x0, XCDR_PLUGIN_STRMAXLEN);
memset (vars->stmt_template, 0x0, XCDR_PLUGIN_STRMAXLEN);
const char *t = NULL;
int it;
if (CONFIG_TRUE == config_lookup_string (&vars->cfg, "dbuserid", &t) )
snprintf (vars->dbuserid, XCDR_PLUGIN_STRMAXLEN, "%s", t);
if (CONFIG_TRUE == config_lookup_string (&vars->cfg, "dbpasswd", &t) )
snprintf (vars->dbpasswd, XCDR_PLUGIN_STRMAXLEN, "%s", t);
if (CONFIG_TRUE == config_lookup_string (&vars->cfg, "dbipaddr", &t))
snprintf (vars->dbipaddr, XCDR_PLUGIN_STRMAXLEN, "%s", t);
if (CONFIG_TRUE == config_lookup_string (&vars->cfg, "dbschema", &t))
snprintf (vars->dbschema, XCDR_PLUGIN_STRMAXLEN, "%s", t);
if (CONFIG_TRUE == config_lookup_string (&vars->cfg, "stmt_template", &t))
snprintf (vars->stmt_template, STMT_TEMPLATE_MAX_LEN, "%s", t);
if (CONFIG_TRUE != config_lookup_int (&vars->cfg, "dbipport", &vars->dbipport) )
vars->dbipport = MYSQL_IPPORT;
if (CONFIG_TRUE != config_lookup_int (&vars->cfg, "sql_insert_retry_max",
&vars->sql_insert_retry_max) )
vars->sql_insert_retry_max = STMT_RETRY_MAX;
if (0 >= vars->sql_insert_retry_max)
vars->sql_insert_retry_max = STMT_RETRY_MAX;
config_destroy(&vars->cfg);
fprintf (stderr, "%s plugin_init (%s). \
dbschema: %s, dbuserid: %s, dbpasswd: %s, dbipaddr: %s, \
dbipport: %i \r\n",
PLUGIN_NAME, options,
vars->dbschema, vars->dbuserid, vars->dbpasswd,
vars->dbipaddr, vars->dbipport);
vars->dbflags = 0;
vars->conn = (MYSQL *) mysql_do_connect (vars->dbipaddr,
vars->dbuserid, vars->dbpasswd,
vars->dbschema,
vars->dbipport, NULL, vars->dbflags);
if (vars->conn == NULL)
{
fprintf (stderr, "%s plugin_init (%s). Can't connect to db: '%s'",
PLUGIN_NAME, options, vars->dbschema);
syslog_msg (LOG_ALERT, 0, "%s plugin_init (%s). Can't connect to db: '%s'\n",
PLUGIN_NAME, options, vars->dbschema);
return PLUG_STATUS_ERROR;
}
return PLUG_STATUS_OK;
}
int plugin_free (XCDR_PLUGSTATE *state)
{
vars = state->local_vars;
mysql_close (vars->conn);
g_string_free (vars->temp, TRUE);
free (vars);
return PLUG_STATUS_OK;
}
int plugin_main (STMTEXP_TAB *vex, XCDR_PLUGSTATE *state)
{
vars = state->local_vars;
int retr = vars->sql_insert_retry_max;
int stmt_done = 0;
while (retr--)
{
const char* stmt = mysqlcdr_expand_str (vars->conn, vex, vars->stmt_template,
strlen(vars->stmt_template));
if (NULL == stmt)
{
fprintf (stderr, "mysqlcdr_expand_str() returned error. Retrying\n");
mysql_ping(vars->conn);
}
else
{
if (0 != mysql_query_retry_on_fail (vars->conn, stmt, STMT_RETRY_MAX))
fprintf (stderr, "Error. '%s' failed. Retrying.\n", stmt);
else
{
fprintf (stderr, "%s\n", stmt);
stmt_done = 1;
break;
}
}
}//~while (retr--)
if (!stmt_done)
{
//!FixMe - Failover action. Log to file ... e.t.c
}
return PLUG_STATUS_OK;
}
#include <stdio.h>
#include <syslog.h>
#include <pcre.h>
#include <string.h>
#include <libconfig.h>
#include "plugcommon.h"
#include "plugldr.h"
#include "log.h"
#define XCDR_FILE_PATH_MAX 1024
#define XCDR_STR_LEN_MAX 1024
int xcdr_plug_ldr_sort_plugins(XCDR_PLUGTAB *plugtab)
{
unsigned int a, b;
XCDR_PLUGTAG x;
for (a = 1; a < plugtab->tag_count; ++a)
{
for (b = plugtab->tag_count - 1; b >= a; --b)
{
if (plugtab->tags[b - 1].priority > plugtab->tags[b].priority)
{
x = plugtab->tags[b - 1];
plugtab->tags[b - 1] = plugtab->tags[b];
plugtab->tags[b] = x;
}
}
}
return 0;
}
int
xcdr_plugldr_load_plugins(XCDR_PLUGTAB *plugtab)
{
unsigned int i;
if (NULL == plugtab->tags || 0 >= plugtab->tag_count)
{
syslog_msg(LOG_ALERT, 1,
"xcdr_plugldr_load_plugins %s:%d No plugins configured",
__FILE__, __LINE__);
return -1;
}
for (i = 0; i < plugtab->tag_count; i++)
{
if (PLUG_STATUS_ERROR == plug_init(plugtab->tags[i].fname,
plugtab->tags[i].options,
&plugtab->tags[i].plug))
{
syslog_msg(LOG_ALERT, 1,
"plugldr_load_plugins %s:%d can't load plugin '%s'",
__FILE__, __LINE__, plugtab->tags[i].fname);
return -1;
}
fprintf(stderr, "plugin: '%s' loaded priority:'%d' options:'%s'\n",
plugtab->tags[i].fname, plugtab->tags[i].priority,
plugtab->tags[i].options);
}// ~for (i
if (1 < plugtab->tag_count)
xcdr_plug_ldr_sort_plugins(plugtab);
return 0;
}
int xcdr_plugldr_load_config(XCDR_PLUGTAB *plugtab, const char* config_file)
{
config_t cfg;
config_setting_t *setting;
config_init(&cfg);
fprintf (stderr, "xcdr_plugldr_load_config. Reading config: '%s'\n", config_file);
if (!config_read_file(&cfg, config_file))
{
fprintf(stderr, "%s:%d - %s\n",
config_file,
config_error_line(&cfg),
config_error_text(&cfg));
config_destroy(&cfg);
return -1;
}
const char *plugin_dir;
config_lookup_string (&cfg, "plugin_dir", &plugin_dir);
setting = config_lookup(&cfg, "Plugins");
if(setting != NULL)
{
int count = config_setting_length(setting);
int i;
plugtab->tags = NULL;
plugtab->tag_count = count;
plugtab->tags = (XCDR_PLUGTAG*)
calloc(plugtab->tag_count, sizeof (XCDR_PLUGTAG));
if (NULL == plugtab->tags)
{
config_destroy(&cfg);
return -1;
}
for(i = 0; i < count; ++i)
{
config_setting_t *plugin = config_setting_get_elem(setting, i);
const char *name, *options;
int priority;
if(!(config_setting_lookup_string(plugin, "name", &name)
&& config_setting_lookup_string(plugin, "options", &options)
&& config_setting_lookup_int(plugin, "priority", &priority)))
continue;
fprintf(stderr, " Plugin [%d] %s:\n", i, name);
snprintf(plugtab->tags[i].fname, XCDR_PLUGIN_STRMAXLEN - 1,
"%s/%s.so", plugin_dir, name);
snprintf(plugtab->tags[i].options, XCDR_PLUGIN_STRMAXLEN - 1,
"%s", options);
plugtab->tags[i].priority = priority;
fprintf(stderr, " %u plugin = '%s' options = '%s'\n",
plugtab->tags[i].priority,
plugtab->tags[i].fname,
plugtab->tags[i].options);
}
for(i = 0; i < count; ++i)
{
char metric_name [XCDR_STR_LEN_MAX];
snprintf (metric_name, XCDR_STR_LEN_MAX - 1, "Plugins.[%d].Metrics", i);
config_setting_t *setting_m = config_lookup(&cfg, metric_name);
if (NULL == setting_m)
continue;
int metric_count = config_setting_length(setting_m);
plugtab->tags[i].metrics.tag_count = metric_count;
plugtab->tags[i].metrics.tags =
(XCDR_METRTAG*) calloc(metric_count,
sizeof (XCDR_METRTAG));
int j;
const char *name, *regexp;
for (j = 0; j < metric_count; j++)
{
config_setting_t *metric = config_setting_get_elem(setting_m, j);
if(!(config_setting_lookup_string(metric, "metric", &name)
&& config_setting_lookup_string(metric, "regexp", &regexp)))
continue;
snprintf (plugtab->tags[i].metrics.tags[j].metric,
XCDR_METRIC_ID_MAX,
"%s",
name);
snprintf (plugtab->tags[i].metrics.tags[j].regexp,
XCDR_METRIC_REGEXP_MAX,
"%s",
regexp);
fprintf(stderr, " Loaded metric %s:%s:%d [%s] '%s'\n",
plugtab->tags[i].fname,
plugtab->tags[i].options,
plugtab->tags[i].priority,
name, regexp);
}
}
}
config_destroy(&cfg);
return 0;
}
void
xcdr_plugldr_free_plugins(XCDR_PLUGTAB *plugtab)
{
unsigned int i;
if (NULL == plugtab) return;
for (i = 0; i < plugtab->tag_count; i++)
if (NULL != plugtab->tags[i].fname)
{
plug_free(&plugtab->tags[i].plug);
free(plugtab->tags[i].metrics.tags);
fprintf(stderr, "plugldr_free_plugins %s\n", plugtab->tags[i].fname);
}
if (NULL != plugtab->tags)
{
free(plugtab->tags);
plugtab->tag_count = 0;
}
plugtab->tags = NULL;
fprintf(stderr, "plugldr_free_plugins done\r\n");
return;
}
/*
Returns non -negative value on success
Negative value on failure
*/
int xcdr_plugldr_match_regexp(const char *regexp,
const char *text, int text_len)
{
pcre *re;
const char *error;
int ovector[30];
int erroffset;
int res;
re = pcre_compile(regexp, 0, &error, &erroffset, NULL);
res = pcre_exec(re, NULL, text, text_len, 0, 0, ovector, 30);
pcre_free (re);
return res;
}
#ifndef PLUGLDR_H
#define PLUGLDR_H
#include "plug.h"
#define XCDR_PLUGLDR_PREPROCESSOR_PLUGIN_TOKEN "preprocessor_plugin"
#define XCDR_PLUGLDR_PROCESSOR_PLUGIN_TOKEN "processor_plugin"
#define XCDR_PLUGLDR_FALLBACK_PLUGIN_TOKEN "fallback_plugin"
#define XCDR_PLUGLDR_PLUGIN_DIR_TOKEN "plugin_dir"
#define XCDR_METRIC_ID_MAX 256
#define XCDR_METRIC_REGEXP_MAX 256
typedef struct xcdr_plugin_metric_tag
{
char metric [XCDR_METRIC_ID_MAX];
char regexp [XCDR_METRIC_REGEXP_MAX];
} XCDR_METRTAG, *PXCDR_METRTAG;
typedef struct xcdr_metric_table
{
XCDR_METRTAG *tags;
unsigned int tag_count;
} XCDR_METRTAB, *PXCDR_METRTAB;
typedef struct xcdr_plugin_tag
{
unsigned int id;
/*plugin priority in config table*/
unsigned int priority;
/*plugin file name*/
char fname [XCDR_PLUGIN_STRMAXLEN];
/*options passed to plugin*/
char options [XCDR_PLUGIN_STRMAXLEN];
/* plugin function pointers*/
XCDR_PLUGINFO plug;
/*table of plugin metrics*/
XCDR_METRTAB metrics;
} XCDR_PLUGTAG, *PXCDR_PLUGTAG;
typedef struct plugin_table
{
XCDR_PLUGTAG *tags;
unsigned int tag_count;
} XCDR_PLUGTAB, *PXCDR_PLUGTAB;
/*First configure PLUGTAB table*/
int xcdr_plugldr_load_config(XCDR_PLUGTAB *plugtab, const char* config_file);
/*Load plugins after successful configuration*/
int xcdr_plugldr_load_plugins (XCDR_PLUGTAB *plugtab);
/*int xcdr_plugldr_match_plugin (const PLUGINCALLINFO *plugci,
const XCDR_PLUGTAB *plugtab, XCDR_PLUGINFO **plug,
const int startpos);
*/
void xcdr_plugldr_free_plugins (XCDR_PLUGTAB *plugtab);
int xcdr_plug_ldr_sort_plugins (XCDR_PLUGTAB *plugtab);
int xcdr_plugldr_match_regexp (const char *regexp,
const char *text, int text_len);
#endif
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <glib.h>
#include "stmtexp.h"
#include "stmtexpldr.h"
#define VARSTART "$<"
#define VAREND ">"
#define VARSTART_LEN strlen (VARSTART)
#define VAREND_LEN strlen (VAREND)
#define VARID_LEN 512
int stmtexp_load_config (stmtexp_tab_t *vex, const char* config_file)
{
stmtexpldr_init (vex);
return stmtexpldr_load_config (vex, config_file);
}
void stmtexp_free (stmtexp_tab_t *vex)
{
stmtexpldr_clear (vex);
}
void stmtexp_assign_var (stmtexp_tab_t *vex,
const char *varid, const char *vartext)
{
stmtexp_key_t t;
memset (&t, 0x0, sizeof(stmtexp_key_t) );
snprintf (t.stmt_var, STMTEXPAND_STRLEN_MAX - 1, "%s", varid);
stmtexp_val_t *tv = g_hash_table_lookup (vex->ght, &t);
if (NULL == tv)
{
/*
fprintf (stderr,
"Index '%s' is not found. Can't assign var.\n",
varid);
*/
return;
}
if (NULL != tv->val)
{
/*
fprintf (stderr, "free old val %s\n", tv->val);
*/
free (tv->val);
tv->val = NULL;
}
tv->val = strdup (vartext);
}
const char* stmtexp_lookup_var (stmtexp_tab_t *vex, const char *varid)
{
stmtexp_key_t t;
memset (&t, 0x0, sizeof(stmtexp_key_t) );
snprintf (t.stmt_var, STMTEXPAND_STRLEN_MAX - 1, "%s", varid);
stmtexp_val_t *tv = g_hash_table_lookup (vex->ght, &t);
//fprintf (stderr, "stmtexp_lookup_var('%s')", varid);
if (NULL != tv)
return tv->val;
else return NULL;
}
void stmtexp_foreach_callback (stmtexp_tab_t *vex,
stmtexp_foreach_callback_t c,
void *data)
{
g_hash_table_foreach (vex->ght, (GHFunc)c, data);
}
const char *stmtexp_expand_str (stmtexp_tab_t *vex,
const char *src, int srclen)
{
const char *s; //src
char *e; //end
char varid [VARID_LEN];
s = src;
g_string_set_size (vex->expanded, 0);
while (s < src + srclen)
{
if (NULL != (e = strstr (s, VARSTART)) )
{
g_string_append_len (vex->expanded, s, e - s);
s = e++;
if (NULL != (e = strstr (s, VAREND)) )
{
/* Remove placeholders VARSTART and VAREND, then lookup */
memset (varid, 0x0, VARID_LEN);
strncpy (varid, s + VARSTART_LEN, (e - s) - VARSTART_LEN );
const char* ev = stmtexp_lookup_var (vex, varid);
if (NULL != ev)
{
/*append expanded var to destination*/
g_string_append (vex->expanded, ev);
}
else
{
/*variable was not found, skip it*/
}
s = e + 1;
//fprintf (stderr, "s: '%s'\n", s);
}
else /*no more signatures found, append the rest of the str*/
{
if (NULL != s)
g_string_append (vex->expanded, s);
break;
}
}
else /*no more signatures found, append the rest of the str*/
{
if (NULL != s)
g_string_append (vex->expanded, s);
break;
}
}//while (s < src + src_len)
return vex->expanded->str;
}
#ifndef STMTEXP_H
#define STMTEXP_H
#include "stmtexptab.h"
#include "stmtexpldr.h"
#include <glib.h>
/*
Very simple and slow variable expansion. No text escaping is provided.
No recursion checks, so if your expanded var contains variable definition
you're in trouble.
*/
/* Callback to modify each key and value */
typedef void (* stmtexp_foreach_callback_t) (stmtexp_key_t *key,
stmtexp_val_t *val,
void *userdata);
/*
Returns:
-1 if error occured, any other value on success
*/
int stmtexp_load_config (stmtexp_tab_t *vex, const char* config_file);
void stmtexp_free (stmtexp_tab_t *vex);
const char* stmtexp_lookup_var (stmtexp_tab_t *vex, const char *varid);
void stmtexp_foreach_callback (stmtexp_tab_t *vex,
stmtexp_foreach_callback_t c,
void *data);
void stmtexp_assign_var (stmtexp_tab_t *vex,
const char *varid, const char *vartext);
/*
@vex - variables to expand
Returns:
pointer to a static buffer which gets overwritten on next call to the func.
NULL on errror
*/
const char *stmtexp_expand_str (stmtexp_tab_t * vex,
const char *src, int srclen);
#endif
#include "stmtexptab.h"
#include "stmtexpldr.h"
#include <libconfig.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#define EXPANDED_STR_DEF_LEN 10240
gboolean stmtexpldr_equal (gconstpointer a, gconstpointer b);
guint stmtexpldr_str_hash (gconstpointer v);
void stmtexpldr_destroy_val (gpointer data);
void stmtexpldr_destroy_key (gpointer data);
gboolean stmtexpldr_equal (gconstpointer a, gconstpointer b)
{
const stmtexp_key_t* ta = (stmtexp_key_t *) a;
const stmtexp_key_t* tb = (stmtexp_key_t *) b;
return g_str_equal (ta->stmt_var, tb->stmt_var);
}
guint stmtexpldr_str_hash (gconstpointer v)
{
const stmtexp_key_t* tv = (stmtexp_key_t *) v;
return (g_str_hash(tv->stmt_var) );
}
void stmtexpldr_destroy_val (gpointer data)
{
if (NULL == data)
return;
stmtexp_val_t * val = (stmtexp_val_t*) data;
if (NULL != val->val)
free (val->val);
free (val);
}
void stmtexpldr_destroy_key (gpointer data)
{
if (NULL == data)
return;
stmtexp_key_t * key = (stmtexp_key_t*) data;
if (NULL != key)
free (key);
}
void stmtexpldr_init (stmtexp_tab_t *vex)
{
vex->ght = g_hash_table_new_full (g_str_hash, stmtexpldr_equal,
stmtexpldr_destroy_key, stmtexpldr_destroy_val);
vex->expanded = g_string_sized_new (EXPANDED_STR_DEF_LEN);
}
int stmtexpldr_load_config (stmtexp_tab_t *vex, const char* config_file)
{
int fret;
config_t cfg;
config_setting_t *setting;
config_init(&cfg);
if (!config_read_file(&cfg, config_file))
{
fprintf(stderr, "%s:%d - %s\n",
config_file,
config_error_line(&cfg),
config_error_text(&cfg));
config_destroy(&cfg);
return -1;
}
setting = config_lookup(&cfg, "Variables");
if(setting != NULL)
{
int count = config_setting_length(setting);
printf("%d configured variables:\n", count);
int i;
for(i = 0; i < count; ++i)
{
config_setting_t *var = config_setting_get_elem(setting, i);
const char *var_id, *xpath;
if(!(config_setting_lookup_string(var, "var_id",
&var_id)
&& config_setting_lookup_string(var, "xpath", &xpath))
)
continue;
stmtexp_key_t* sk = calloc (1, sizeof(stmtexp_key_t) );
if (NULL != sk)
{
fprintf(stderr, " Variable [%d] '%s':'%s'\n", i,
var_id, xpath );
snprintf (sk->stmt_var, STMTEXPAND_STRLEN_MAX - 1, "%s",
var_id);
snprintf (sk->xpath, STMTEXPAND_STRLEN_MAX - 1, "%s", xpath );
//add index and value
stmtexp_val_t *sv = calloc (1, sizeof(stmtexp_val_t) );
g_hash_table_replace (vex->ght, sk, sv);
} else
{
perror ("stmtexpldr_load_config() malloc error\n");
fret = -1;
break;
}
}
fret = 0;
}
config_destroy(&cfg);
return fret;
/*
cfg_t *cfg;
int res;
int fret = 0;
cfg = cfg_init(opts, 0);
res = cfg_parse(cfg, config_file);
printf("Parsing result == %d\n", res);
if(res == CFG_FILE_ERROR)
{
perror(config_file);
return -1;
} else if(res == CFG_PARSE_ERROR)
{
fprintf(stderr, "'%s' parse error\n", config_file);
return -1;
}
int n = cfg_size(cfg, "var");
printf("%d configured variables:\n", n);
int i;
for(i = 0; i < n; i++)
{
stmtexp_key_t* sk = calloc (1, sizeof(stmtexp_key_t) );
if (NULL != sk)
{
cfg_t *vars = cfg_getnsec(cfg, "var", i);
printf(" Variable [%d] %s:\n", i, cfg_title(vars) );
snprintf (sk->stmt_var, STMTEXPAND_STRLEN_MAX - 1,
"%s", cfg_getstr(vars, "var_placeholder") );
printf(" Var. Placeholder = %s\n", sk->stmt_var);
snprintf (sk->xpath, STMTEXPAND_STRLEN_MAX - 1,
"%s", cfg_getstr(vars, "xpath") );
printf(" Var. XPATH = %s\n", sk->xpath);
//add index and value
stmtexp_val_t *sv = calloc (1, sizeof(stmtexp_val_t) );
g_hash_table_replace (vex->ght, sk, sv);
} else
{
perror ("stmtexpldr_load_config() malloc error\n");
fret = -1;
break;
}
}
cfg_free(cfg);
return fret;
*/
}
void stmtexpldr_clear (stmtexp_tab_t *vex)
{
g_hash_table_remove_all (vex->ght);
}
void stmtexpldr_free (stmtexp_tab_t *vex)
{
g_hash_table_destroy (vex->ght);
g_string_free (vex->expanded, TRUE);
}
#ifndef STMTEXPLDR_H
#define STMTEXPLDR_H
#include "stmtexptab.h"
#define STMTEXPAND_STRLEN_MAX 512
typedef enum
{
STMTEXP_DB_DT_VARCHAR = 1,
STMTEXP_DB_DT_INT
} stmtexp_db_field_dt;
typedef struct
{
/*stmt_var - variable id inside a statement: $<SOMEVAR> */
char stmt_var [STMTEXPAND_STRLEN_MAX];
/*XPATH of value inside the XMLCDR hierarchy*/
char xpath [STMTEXPAND_STRLEN_MAX];
} stmtexp_key_t, *pstmtexp_key_t;
typedef struct
{
char *val;
} stmtexp_val_t, *pstmtexp_val_t;
void stmtexpldr_init (stmtexp_tab_t *vex);
/* Returns:
-1 if error occured*/
int stmtexpldr_load_config (stmtexp_tab_t *vex, const char* config_file);
void stmtexpldr_clear (stmtexp_tab_t *vex);
void stmtexpldr_free (stmtexp_tab_t *vex);
#endif
#ifndef STMTEXPTAB_H
#define STMTEXPTAB_H
#include <glib.h>
typedef struct
{
GHashTable *ght;
GString *expanded;
} stmtexp_tab_t, *pstmtexp_tab_t, STMTEXP_TAB, *PSTMTEXP_TAB;
#endif
<?xml version="1.0"?>
<cdr>
<variables>
<sip_received_ip>192.168.50.21</sip_received_ip>
<sip_received_port>39368</sip_received_port>
<sip_authorized>true</sip_authorized>
<sip_mailbox>1160</sip_mailbox>
<sip_auth_username>1160</sip_auth_username>
<sip_auth_realm>192.168.50.229</sip_auth_realm>
<mailbox>1160</mailbox>
<record_stereo>true</record_stereo>
<accountcode>1160</accountcode>
<user_context>default</user_context>
<effective_caller_id_name>Michael%20S%20Collins</effective_caller_id_name>
<effective_caller_id_number>5597993757</effective_caller_id_number>
<sip_from_user>1160</sip_from_user>
<sip_from_uri>1160%40192.168.50.229</sip_from_uri>
<sip_from_host>192.168.50.229</sip_from_host>
<sip_from_user_stripped>1160</sip_from_user_stripped>
<sip_from_tag>a360bd54</sip_from_tag>
<sofia_profile_name>internal</sofia_profile_name>
<sofia_profile_domain_name>192.168.50.229</sofia_profile_domain_name>
<sip_req_user>92137991400</sip_req_user>
<sip_req_uri>92137991400%40192.168.50.229</sip_req_uri>
<sip_req_host>192.168.50.229</sip_req_host>
<sip_to_user>92137991400</sip_to_user>
<sip_to_uri>92137991400%40192.168.50.229</sip_to_uri>
<sip_to_host>192.168.50.229</sip_to_host>
<sip_contact_user>1160</sip_contact_user>
<sip_contact_port>39368</sip_contact_port>
<sip_contact_uri>1160%40192.168.50.21%3A39368</sip_contact_uri>
<sip_contact_host>192.168.50.21</sip_contact_host>
<channel_name>sofia/internal/1160%40192.168.50.229</channel_name>
<sip_call_id>NzUyYzU2ZmU0NjQ0NmNkMGExYTNiZjIzMjIwMWNiODc.</sip_call_id>
<sip_via_host>192.168.50.21</sip_via_host>
<sip_via_port>39368</sip_via_port>
<sip_via_rport>39368</sip_via_rport>
<max_forwards>70</max_forwards>
<presence_id>1160%40192.168.50.229</presence_id>
<switch_r_sdp>v%3D0%0D%0Ao%3D-%206%202%20IN%20IP4%20192.168.50.21%0D%0As%3DCounterPath%20X-Lite%203.0%0D%0Ac%3DIN%20IP4%20192.168.50.21%0D%0At%3D0%200%0D%0Am%3Daudio%209140%20RTP/AVP%20107%20119%20100%20106%200%20105%2098%208%203%20101%0D%0Aa%3Drtpmap%3A107%20BV32/16000%0D%0Aa%3Drtpmap%3A119%20BV32-FEC/16000%0D%0Aa%3Drtpmap%3A100%20SPEEX/16000%0D%0Aa%3Drtpmap%3A106%20SPEEX-FEC/16000%0D%0Aa%3Drtpmap%3A105%20SPEEX-FEC/8000%0D%0Aa%3Drtpmap%3A98%20iLBC/8000%0D%0Aa%3Drtpmap%3A101%20telephone-event/8000%0D%0Aa%3Dfmtp%3A101%200-15%0D%0Aa%3Dalt%3A1%201%20%3A%20CV3qZAA1%209gFf2/Iz%20192.168.50.21%209140%0D%0A</switch_r_sdp>
<remote_media_ip>192.168.50.21</remote_media_ip>
<remote_media_port>9140</remote_media_port>
<write_codec>PCMU</write_codec>
<write_rate>8000</write_rate>
<open>true</open>
<use_profile>nat</use_profile>
<numbering_plan>US</numbering_plan>
<default_gateway>asterlink.com</default_gateway>
<default_area_code>559</default_area_code>
<user_name>default</user_name>
<domain_name>192.168.50.229</domain_name>
<local_media_ip>192.168.50.229</local_media_ip>
<local_media_port>9140</local_media_port>
<current_application>bridge</current_application>
<originate_disposition>SUCCESS</originate_disposition>
<bridge_channel>OpenZAP/1%3A23/2137991400</bridge_channel>
<bridge_uuid>e012ce96-7f9c-4194-87fe-5ba86a3930ca</bridge_uuid>
<signal_bond>e012ce96-7f9c-4194-87fe-5ba86a3930ca</signal_bond>
<sip_nat_detected>true</sip_nat_detected>
<endpoint_disposition>ANSWER</endpoint_disposition>
<sip_user_agent>X-Lite%20release%201100l%20stamp%2047546</sip_user_agent>
<sip_term_status>200</sip_term_status>
<sip_term_cause>16</sip_term_cause>
<hangup_cause>NORMAL_CLEARING</hangup_cause>
<start_stamp>2008-07-31%2011%3A35%3A38</start_stamp>
<profile_start_stamp>2008-07-31%2011%3A35%3A38</profile_start_stamp>
<answer_stamp>2008-07-31%2011%3A35%3A41</answer_stamp>
<progress_stamp>2008-07-31%2011%3A35%3A38</progress_stamp>
<progress_media_stamp>2008-07-31%2011%3A35%3A38</progress_media_stamp>
<end_stamp>2008-07-31%2011%3A36%3A17</end_stamp>
<start_epoch>1217529338</start_epoch>
<start_uepoch>1217529338212616</start_uepoch>
<profile_start_epoch>1217529338</profile_start_epoch>
<profile_start_uepoch>1217529338212616</profile_start_uepoch>
<answer_epoch>1217529338</answer_epoch>
<answer_uepoch>1217529338452698</answer_uepoch>
<end_epoch>1217529377</end_epoch>
<end_uepoch>1217529377795951</end_uepoch>
<last_app>bridge</last_app>
<last_arg>openzap/1/A/2137991400</last_arg>
<caller_id>%22Mikey%22%20%3C1160%3E</caller_id>
<duration>39</duration>
<billsec>36</billsec>
<progresssec>0</progresssec>
<progress_mediasec>0</progress_mediasec>
<flow_billsec>39</flow_billsec>
<mduration>39583</mduration>
<billmsec>36267</billmsec>
<progressmsec>238</progressmsec>
<progress_mediamsec>237955</progress_mediamsec>
<flow_billmsec>39583</flow_billmsec>
<uduration>39583335</uduration>
<billusec>36267529</billusec>
<progressusec>237955</progressusec>
<progress_mediausec>237955</progress_mediausec>
<flow_billusec>39583335</flow_billusec>
<read_codec>PCMU</read_codec>
<read_rate>8000</read_rate>
</variables>
<app_log>
<application app_name="set" app_data="open=true"></application>
<application app_name="set" app_data="use_profile=nat"></application>
<application app_name="set_user" app_data="default@192.168.50.229"></application>
<application app_name="db" app_data="insert/spymap/1160/6f32e2f8-38d1-43a7-b6ea-215bbfe6a314"></application>
<application app_name="db" app_data="insert/last_dial/1160/92137991400"></application>
<application app_name="db" app_data="insert/last_dial/global/6f32e2f8-38d1-43a7-b6ea-215bbfe6a314"></application>
<application app_name="record_session" app_data="/mnt/powervault/Databases/XMLCDR/6f32e2f8-38d1-43a7-b6ea-215bbfe6a314__1.wav"></application>
<application app_name="bridge" app_data="openzap/1/A/2137991400"></application>
</app_log>
<callflow dialplan="XML" profile_index="1">
<extension name="tod_example" number="92137991400">
<application app_name="set" app_data="open=true"></application>
<application app_name="set" app_data="use_profile=${cond(${acl(${network_addr} rfc1918)} == true ? nat : default)}"></application>
<application app_name="set_user" app_data="default@${domain}"></application>
<application app_name="db" app_data="insert/spymap/${caller_id_number}/${uuid}"></application>
<application app_name="db" app_data="insert/last_dial/${caller_id_number}/${destination_number}"></application>
<application app_name="db" app_data="insert/last_dial/global/${uuid}"></application>
<application app_name="record_session" app_data="/mnt/powervault/Databases/XMLCDR/${uuid}__1.wav"></application>
<application app_name="bridge" app_data="openzap/1/A/2137991400"></application>
</extension>
<caller_profile>
<username>1160</username>
<dialplan>XML</dialplan>
<caller_id_name>Mikey</caller_id_name>
<ani></ani>
<aniii></aniii>
<caller_id_number>1160</caller_id_number>
<network_addr>192.168.50.21</network_addr>
<rdnis></rdnis>
<destination_number>92137991400</destination_number>
<uuid>6f32e2f8-38d1-43a7-b6ea-215bbfe6a314</uuid>
<source>mod_sofia</source>
<context>default</context>
<chan_name>sofia/internal/1160@192.168.50.229</chan_name>
<originatee>
<originatee_caller_profile>
<username>1160</username>
<dialplan>XML</dialplan>
<caller_id_name>Michael S Collins</caller_id_name>
<ani></ani>
<aniii></aniii>
<caller_id_number>5597993757</caller_id_number>
<network_addr>192.168.50.21</network_addr>
<rdnis></rdnis>
<destination_number>1/A/2137991400</destination_number>
<uuid>e012ce96-7f9c-4194-87fe-5ba86a3930ca</uuid>
<source>mod_sofia</source>
<context>default</context>
<chan_name>OpenZAP/1:23/2137991400</chan_name>
</originatee_caller_profile>
</originatee>
</caller_profile>
<times>
<created_time>1217529338212616</created_time>
<profile_created_time>1217529338212616</profile_created_time>
<progress_time>1217529338450571</progress_time>
<progress_media_time>1217529338452698</progress_media_time>
<answered_time>1217529341528422</answered_time>
<hangup_time>1217529377795951</hangup_time>
<transfer_time>0</transfer_time>
</times>
</callflow>
</cdr>
#include <glib.h>
#include "urldecode.h"
const char * urldecode_expand_value (GString *url,
const char *key, int key_len,
int case_sensative,
GString *temp, int *status, GString *val)
{
const char *p;
char *end;
apr_size_t len;
if ( NULL == key )
{
*status = URLUTIL_STATUS_INVALID_PARAMS;
return NULL;
}
if (0 == strlen(key) || 0 == key_len)
{
*status = URLUTIL_STATUS_EMPTY_SRCH_KEY;
return NULL;
}
if (strlen((char*)url->str) < key_len )
{
*status = URLUTIL_STATUS_URL_STR_TOO_SHORT;
return NULL;
}
//convert key to urlencoded string,
//since we are searching for urlencoded keys
//max length of urlencoded key is 3 * key length
len = 3 * key_len + 1;
g_string_set_size(temp, len);
memset (temp->str, 0x0, len);
apreq_encode(temp->str, key, key_len );
//append '=' to the key_name
temp->str [strlen(temp->str)] = '=';
if (0 == case_sensative)
{
if (NULL == (p = strcasestr ((const char*) url->str, temp->str)) )
{
*status = URLUTIL_STATUS_SRCH_KEY_NOT_FOUND;
return NULL;
}
} else
{
if (NULL == (p = strstr ((const char*) url->str, temp->str)) )
{
*status = URLUTIL_STATUS_SRCH_KEY_NOT_FOUND;
return NULL;
}
} //~else case_sensative
//urlencoded key is found in cgi request string
if (NULL == (end = strchr (p, '=')) )
{
*status = URLUTIL_STATUS_URL_KEY_VAL_BROKEN;
return NULL;
}
//get value
//if terminating '&' is not found,
//then our value ends at the end of the @url string
p = ++end;
if (NULL == (end = strchr (p, '&')) )
end = url->str + strlen(url->str);
len = 3 * (end - p) + 1;
g_string_set_size(val, len);
memset (val->str, 0x0, len);
apreq_decode (val->str, &len, p, end - p);
return val->str;
}
#ifndef URLDECODE_H
#define URLDECODE_H
#include <apreq2/apreq_util.h>
#include <glib.h>
/*
Status codes
*/
#define URLUTIL_STATUS_OK 0
#define URLUTIL_STATUS_MEM_ALLOC_ERR -1
#define URLUTIL_STATUS_INVALID_PARAMS -2
#define URLUTIL_STATUS_EMPTY_SRCH_KEY -3
#define URLUTIL_STATUS_SRCH_KEY_NOT_FOUND -4
#define URLUTIL_STATUS_URL_STR_TOO_SHORT -5
#define URLUTIL_STATUS_URL_KEY_VAL_BROKEN -6
const char * urldecode_expand_value (GString *url,
const char *key, int key_len,
int case_sensative,
GString *temp, int *status, GString *val);
#endif
Markdown 格式
0% 或
您添加了 0 人 到此讨论。请谨慎行事。
请先完成此评论的编辑!
请 注册 或者 后发表评论