summaryrefslogtreecommitdiff
path: root/extensions/rt_ereg
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/rt_ereg')
-rw-r--r--extensions/rt_ereg/rtereg.c354
-rw-r--r--extensions/rt_ereg/rtereg.h11
-rw-r--r--extensions/rt_ereg/rtereg_conf.l4
-rw-r--r--extensions/rt_ereg/rtereg_conf.y143
4 files changed, 363 insertions, 149 deletions
diff --git a/extensions/rt_ereg/rtereg.c b/extensions/rt_ereg/rtereg.c
index be4db16..93a584d 100644
--- a/extensions/rt_ereg/rtereg.c
+++ b/extensions/rt_ereg/rtereg.c
@@ -2,7 +2,7 @@
* Software License Agreement (BSD License) *
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
* *
-* Copyright (c) 2013, WIDE Project and NICT *
+* Copyright (c) 2020, WIDE Project and NICT *
* All rights reserved. *
* *
* Redistribution and use of this software in source and binary forms, with or without modification, are *
@@ -33,16 +33,26 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
*********************************************************************************************************/
-/*
+/*
* This extension allows to perform some pattern-matching on an AVP
* and send the message to a server accordingly.
* See rt_ereg.conf.sample file for the format of the configuration file.
*/
+#include <pthread.h>
+#include <signal.h>
+
#include "rtereg.h"
+static pthread_rwlock_t rte_lock;
+
+#define MODULE_NAME "rt_ereg"
+
+static char *rt_ereg_config_file;
+
/* The configuration structure */
-struct rtereg_conf rtereg_conf;
+struct rtereg_conf *rtereg_conf;
+int rtereg_conf_size;
#ifndef HAVE_REG_STARTEND
static char * buf = NULL;
@@ -50,18 +60,41 @@ static size_t bufsz;
static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
#endif /* HAVE_REG_STARTEND */
-static int proceed(char * value, size_t len, struct fd_list * candidates)
+static int rtereg_init(void);
+static int rtereg_init_config(void);
+static void rtereg_fini(void);
+
+void rtereg_conf_free(struct rtereg_conf *config_struct, int config_size)
+{
+ int i, j;
+
+ /* Destroy the data */
+ for (j=0; j<config_size; j++) {
+ if (config_struct[j].rules) {
+ for (i = 0; i < config_struct[j].rules_nb; i++) {
+ free(config_struct[j].rules[i].pattern);
+ free(config_struct[j].rules[i].server);
+ regfree(&config_struct[j].rules[i].preg);
+ }
+ }
+ free(config_struct[j].avps);
+ free(config_struct[j].rules);
+ }
+ free(config_struct);
+}
+
+static int proceed(char * value, size_t len, struct fd_list * candidates, int conf)
{
int i;
-
- for (i = 0; i < rtereg_conf.rules_nb; i++) {
+
+ for (i = 0; i < rtereg_conf[conf].rules_nb; i++) {
/* Does this pattern match the value? */
- struct rtereg_rule * r = &rtereg_conf.rules[i];
+ struct rtereg_rule * r = &rtereg_conf[conf].rules[i];
int err = 0;
struct fd_list * c;
-
- TRACE_DEBUG(ANNOYING, "Attempt pattern matching of '%.*s' with rule '%s'", (int)len, value, r->pattern);
-
+
+ LOG_D("[rt_ereg] attempting pattern matching of '%.*s' with rule '%s'", (int)len, value, r->pattern);
+
#ifdef HAVE_REG_STARTEND
{
regmatch_t pmatch[1];
@@ -76,16 +109,16 @@ static int proceed(char * value, size_t len, struct fd_list * candidates)
err = regexec(&r->preg, value, 0, NULL, 0);
}
#endif /* HAVE_REG_STARTEND */
-
+
if (err == REG_NOMATCH)
continue;
-
+
if (err != 0) {
char * errstr;
size_t bl;
/* Error while compiling the regex */
- TRACE_DEBUG(INFO, "Error while executing the regular expression '%s':", r->pattern);
+ LOG_E("[rt_ereg] error while executing the regular expression '%s':", r->pattern);
/* Get the error message size */
bl = regerror(err, &r->preg, NULL, 0);
@@ -95,22 +128,17 @@ static int proceed(char * value, size_t len, struct fd_list * candidates)
/* Get the error message content */
regerror(err, &r->preg, errstr, bl);
- TRACE_DEBUG(INFO, "\t%s", errstr);
+ LOG_E("\t%s", errstr);
/* Free the buffer, return the error */
free(errstr);
-
+
return (err == REG_ESPACE) ? ENOMEM : EINVAL;
}
-
+
/* From this point, the expression matched the AVP value */
- TRACE_DEBUG(FULL, "[rt_ereg] Match: '%s' to value '%.*s' => '%s' += %d",
- r->pattern,
- (int)len,
- value,
- r->server,
- r->score);
-
+ LOG_D("[rt_ereg] Match: '%s' to value '%.*s' => '%s' += %d", r->pattern, (int)len, value, r->server, r->score);
+
for (c = candidates->next; c != candidates; c = c->next) {
struct rtd_candidate * cand = (struct rtd_candidate *)c;
@@ -120,106 +148,256 @@ static int proceed(char * value, size_t len, struct fd_list * candidates)
}
}
};
-
+
return 0;
}
-/* The callback called on new messages */
-static int rtereg_out(void * cbdata, struct msg ** pmsg, struct fd_list * candidates)
+static int find_avp(msg_or_avp *where, int conf_index, int level, struct fd_list * candidates)
{
- struct msg * msg = *pmsg;
- struct avp * avp = NULL;
-
- TRACE_ENTRY("%p %p %p", cbdata, msg, candidates);
-
- CHECK_PARAMS(msg && candidates);
-
- /* Check if it is worth processing the message */
- if (FD_IS_LIST_EMPTY(candidates)) {
- return 0;
+ struct dict_object *what;
+ struct dict_avp_data dictdata;
+ struct avp *nextavp = NULL;
+ struct avp_hdr *avp_hdr = NULL;
+
+ /* iterate over all AVPs and try to find a match */
+// for (i = 0; i<rtereg_conf[j].level; i++) {
+ if (level > rtereg_conf[conf_index].level) {
+ LOG_E("internal error, dug too deep");
+ return 1;
}
-
- /* Now search the AVP in the message */
- CHECK_FCT( fd_msg_search_avp ( msg, rtereg_conf.avp, &avp ) );
- if (avp != NULL) {
- struct avp_hdr * ahdr = NULL;
- CHECK_FCT( fd_msg_avp_hdr ( avp, &ahdr ) );
- if (ahdr->avp_value != NULL) {
+ what = rtereg_conf[conf_index].avps[level];
+
+ CHECK_FCT(fd_dict_getval(what, &dictdata));
+ CHECK_FCT(fd_msg_browse(where, MSG_BRW_FIRST_CHILD, (void *)&nextavp, NULL));
+ while (nextavp) {
+ CHECK_FCT(fd_msg_avp_hdr(nextavp, &avp_hdr));
+ if ((avp_hdr->avp_code == dictdata.avp_code) && (avp_hdr->avp_vendor == dictdata.avp_vendor)) {
+ if (level != rtereg_conf[conf_index].level - 1) {
+ LOG_D("[rt_ereg] found grouped AVP %d (vendor %d), digging deeper", avp_hdr->avp_code, avp_hdr->avp_vendor);
+ CHECK_FCT(find_avp(nextavp, conf_index, level+1, candidates));
+ } else {
+ struct dictionary * dict;
+ LOG_D("[rt_ereg] found AVP %d (vendor %d)", avp_hdr->avp_code, avp_hdr->avp_vendor);
+ CHECK_FCT(fd_dict_getdict(what, &dict));
+ CHECK_FCT_DO(fd_msg_parse_dict(nextavp, dict, NULL), /* nothing */);
+ if (avp_hdr->avp_value != NULL) {
+ LOG_A("avp_hdr->avp_value NOT NULL, matching");
#ifndef HAVE_REG_STARTEND
- int ret;
-
- /* Lock the buffer */
- CHECK_POSIX( pthread_mutex_lock(&mtx) );
-
- /* Augment the buffer if needed */
- if (ahdr->avp_value->os.len >= bufsz) {
- CHECK_MALLOC_DO( buf = realloc(buf, ahdr->avp_value->os.len + 1),
- { pthread_mutex_unlock(&mtx); return ENOMEM; } );
- }
-
- /* Copy the AVP value */
- memcpy(buf, ahdr->avp_value->os.data, ahdr->avp_value->os.len);
- buf[ahdr->avp_value->os.len] = '\0';
-
- /* Now apply the rules */
- ret = proceed(buf, ahdr->avp_value->os.len, candidates);
-
- CHECK_POSIX(pthread_mutex_unlock(&mtx));
-
- CHECK_FCT(ret);
+ int ret;
+
+ /* Lock the buffer */
+ CHECK_POSIX( pthread_mutex_lock(&mtx) );
+
+ /* Augment the buffer if needed */
+ if (avp_hdr->avp_value->os.len >= bufsz) {
+ char *newbuf;
+ CHECK_MALLOC_DO( newbuf = realloc(buf, avp_hdr->avp_value->os.len + 1),
+ { pthread_mutex_unlock(&mtx); return ENOMEM; } );
+ /* Update buffer and buffer size */
+ buf = newbuf;
+ bufsz = avp_hdr->avp_value->os.len + 1;
+ }
+
+ /* Copy the AVP value */
+ memcpy(buf, avp_hdr->avp_value->os.data, avp_hdr->avp_value->os.len);
+ buf[avp_hdr->avp_value->os.len] = '\0';
+
+ /* Now apply the rules */
+ ret = proceed(buf, avp_hdr->avp_value->os.len, candidates, conf_index);
+
+ CHECK_POSIX(pthread_mutex_unlock(&mtx));
+
+ CHECK_FCT(ret);
#else /* HAVE_REG_STARTEND */
- CHECK_FCT( proceed((char *) ahdr->avp_value->os.data, ahdr->avp_value->os.len, candidates) );
+ CHECK_FCT( proceed((char *) avp_hdr->avp_value->os.data, avp_hdr->avp_value->os.len, candidates, conf_index) );
#endif /* HAVE_REG_STARTEND */
+ }
+ }
}
+ CHECK_FCT(fd_msg_browse(nextavp, MSG_BRW_NEXT, (void *)&nextavp, NULL));
}
-
+
return 0;
}
+/* The callback called on new messages */
+static int rtereg_out(void * cbdata, struct msg ** pmsg, struct fd_list * candidates)
+{
+ msg_or_avp *where;
+ int j, ret;
+
+ LOG_A("[rt_ereg] rtereg_out arguments: %p %p %p", cbdata, *pmsg, candidates);
+
+ CHECK_PARAMS(pmsg && *pmsg && candidates);
+
+ if (pthread_rwlock_rdlock(&rte_lock) != 0) {
+ fd_log_notice("%s: read-lock failed, skipping handler", MODULE_NAME);
+ return 0;
+ }
+ ret = 0;
+ /* Check if it is worth processing the message */
+ if (!FD_IS_LIST_EMPTY(candidates)) {
+ /* Now search the AVPs in the message */
+
+ for (j=0; j<rtereg_conf_size; j++) {
+ where = *pmsg;
+ LOG_D("[rt_ereg] iterating over AVP group %d", j);
+ if ((ret=find_avp(where, j, 0, candidates)) != 0) {
+ break;
+ }
+ }
+ }
+ if (pthread_rwlock_unlock(&rte_lock) != 0) {
+ fd_log_notice("%s: read-unlock failed after rtereg_out, exiting", MODULE_NAME);
+ exit(1);
+ }
+
+ return ret;
+}
+
/* handler */
static struct fd_rt_out_hdl * rtereg_hdl = NULL;
+static volatile int in_signal_handler = 0;
+
+/* signal handler */
+static void sig_hdlr(void)
+{
+ struct rtereg_conf *old_config;
+ int old_config_size;
+
+ if (in_signal_handler) {
+ fd_log_error("%s: already handling a signal, ignoring new one", MODULE_NAME);
+ return;
+ }
+ in_signal_handler = 1;
+
+ if (pthread_rwlock_wrlock(&rte_lock) != 0) {
+ fd_log_error("%s: locking failed, aborting config reload", MODULE_NAME);
+ return;
+ }
+
+ /* save old config in case reload goes wrong */
+ old_config = rtereg_conf;
+ old_config_size = rtereg_conf_size;
+ rtereg_conf = NULL;
+ rtereg_conf_size = 0;
+
+ if (rtereg_init_config() != 0) {
+ fd_log_notice("%s: error reloading configuration, restoring previous configuration", MODULE_NAME);
+ rtereg_conf = old_config;
+ rtereg_conf_size = old_config_size;
+ } else {
+ rtereg_conf_free(old_config, old_config_size);
+ }
+
+ if (pthread_rwlock_unlock(&rte_lock) != 0) {
+ fd_log_error("%s: unlocking failed after config reload, exiting", MODULE_NAME);
+ exit(1);
+ }
+
+ fd_log_notice("%s: reloaded configuration, %d AVP group%s defined", MODULE_NAME, rtereg_conf_size, rtereg_conf_size != 1 ? "s" : "");
+
+ in_signal_handler = 0;
+}
+
/* entry point */
static int rtereg_entry(char * conffile)
{
- TRACE_ENTRY("%p", conffile);
-
+ LOG_A("[rt_ereg] started with conffile '%p'", conffile);
+
+ rt_ereg_config_file = conffile;
+
+ if (rtereg_init() != 0) {
+ return 1;
+ }
+
+ /* Register reload callback */
+ CHECK_FCT(fd_event_trig_regcb(SIGUSR1, MODULE_NAME, sig_hdlr));
+
+ fd_log_notice("%s: configured, %d AVP group%s defined", MODULE_NAME, rtereg_conf_size, rtereg_conf_size != 1 ? "s" : "");
+
+ return 0;
+}
+
+static int rtereg_init_config(void)
+{
/* Initialize the configuration */
- memset(&rtereg_conf, 0, sizeof(rtereg_conf));
-
+ if ((rtereg_conf=calloc(sizeof(*rtereg_conf), 1)) == NULL) {
+ LOG_E("[rt_ereg] malloc failured");
+ return 1;
+ }
+ rtereg_conf_size = 1;
+
/* Parse the configuration file */
- CHECK_FCT( rtereg_conf_handle(conffile) );
-
+ CHECK_FCT( rtereg_conf_handle(rt_ereg_config_file) );
+
+ return 0;
+}
+
+
+/* Load */
+static int rtereg_init(void)
+{
+ int ret;
+
+ pthread_rwlock_init(&rte_lock, NULL);
+
+ if (pthread_rwlock_wrlock(&rte_lock) != 0) {
+ fd_log_notice("%s: write-lock failed, aborting", MODULE_NAME);
+ return EDEADLK;
+ }
+
+ if ((ret=rtereg_init_config()) != 0) {
+ pthread_rwlock_unlock(&rte_lock);
+ return ret;
+ }
+
+ if (pthread_rwlock_unlock(&rte_lock) != 0) {
+ fd_log_notice("%s: write-unlock failed, aborting", MODULE_NAME);
+ return EDEADLK;
+ }
+
/* Register the callback */
CHECK_FCT( fd_rt_out_register( rtereg_out, NULL, 1, &rtereg_hdl ) );
-
+
/* We're done */
return 0;
}
/* Unload */
-void fd_ext_fini(void)
+static void rtereg_fini(void)
{
- int i;
- TRACE_ENTRY();
-
/* Unregister the cb */
CHECK_FCT_DO( fd_rt_out_unregister ( rtereg_hdl, NULL ), /* continue */ );
-
- /* Destroy the data */
- if (rtereg_conf.rules)
- for (i = 0; i < rtereg_conf.rules_nb; i++) {
- free(rtereg_conf.rules[i].pattern);
- free(rtereg_conf.rules[i].server);
- regfree(&rtereg_conf.rules[i].preg);
- }
- free(rtereg_conf.rules);
+
#ifndef HAVE_REG_STARTEND
free(buf);
+ buf = NULL;
+ bufsz = 0;
#endif /* HAVE_REG_STARTEND */
-
+
+ if (pthread_rwlock_wrlock(&rte_lock) != 0) {
+ fd_log_error("%s: write-locking failed in fini, giving up", MODULE_NAME);
+ return;
+ }
+ /* Destroy the data */
+ rtereg_conf_free(rtereg_conf, rtereg_conf_size);
+ rtereg_conf = NULL;
+ rtereg_conf_size = 0;
+
+ if (pthread_rwlock_unlock(&rte_lock) != 0) {
+ fd_log_error("%s: write-unlocking failed in fini", MODULE_NAME);
+ return;
+ }
+
/* Done */
return ;
}
-EXTENSION_ENTRY("rt_ereg", rtereg_entry);
+void fd_ext_fini(void)
+{
+ rtereg_fini();
+}
+
+EXTENSION_ENTRY(MODULE_NAME, rtereg_entry);
diff --git a/extensions/rt_ereg/rtereg.h b/extensions/rt_ereg/rtereg.h
index 495c82f..741c314 100644
--- a/extensions/rt_ereg/rtereg.h
+++ b/extensions/rt_ereg/rtereg.h
@@ -2,7 +2,7 @@
* Software License Agreement (BSD License) *
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
* *
-* Copyright (c) 2011, WIDE Project and NICT *
+* Copyright (c) 2019, WIDE Project and NICT *
* All rights reserved. *
* *
* Redistribution and use of this software in source and binary forms, with or without modification, are *
@@ -57,8 +57,11 @@ struct rtereg_rule {
extern struct rtereg_conf {
int rules_nb; /* Number of rules in the configuration */
struct rtereg_rule *rules; /* The array of rules */
+
+ int level; /* how many levels of AVPs we have to dig down into */
+ int finished; /* AVP fully configured, for configuration file reading */
+ struct dict_object **avps; /* cache the dictionary objects that we are searching */
- struct dict_object * avp; /* cache the dictionary object that we are searching */
-
-} rtereg_conf;
+} *rtereg_conf;
+extern int rtereg_conf_size;
diff --git a/extensions/rt_ereg/rtereg_conf.l b/extensions/rt_ereg/rtereg_conf.l
index 8a281a5..b0a6cb3 100644
--- a/extensions/rt_ereg/rtereg_conf.l
+++ b/extensions/rt_ereg/rtereg_conf.l
@@ -2,7 +2,7 @@
* Software License Agreement (BSD License) *
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
* *
-* Copyright (c) 2013, WIDE Project and NICT *
+* Copyright (c) 2019, WIDE Project and NICT *
* All rights reserved. *
* *
* Redistribution and use of this software in source and binary forms, with or without modification, are *
@@ -80,7 +80,7 @@ qstring \"[^\"\n]*\"
/* Match a quoted string. */
CHECK_MALLOC_DO( yylval->string = strdup(yytext+1),
{
- TRACE_DEBUG(INFO, "Unable to copy the string '%s': %s", yytext, strerror(errno));
+ LOG_E("[rt_ereg] unable to copy the string '%s': %s", yytext, strerror(errno));
return LEX_ERROR; /* trig an error in yacc parser */
} );
yylval->string[strlen(yytext) - 2] = '\0';
diff --git a/extensions/rt_ereg/rtereg_conf.y b/extensions/rt_ereg/rtereg_conf.y
index a213323..28174f8 100644
--- a/extensions/rt_ereg/rtereg_conf.y
+++ b/extensions/rt_ereg/rtereg_conf.y
@@ -2,7 +2,7 @@
* Software License Agreement (BSD License) *
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
* *
-* Copyright (c) 2013, WIDE Project and NICT *
+* Copyright (c) 2019, WIDE Project and NICT *
* All rights reserved. *
* *
* Redistribution and use of this software in source and binary forms, with or without modification, are *
@@ -37,14 +37,14 @@
*/
/* For development only : */
-%debug
+%debug
%error-verbose
/* The parser receives the configuration file filename as parameter */
%parse-param {char * conffile}
/* Keep track of location */
-%locations
+%locations
%pure-parser
%{
@@ -53,36 +53,89 @@
/* Forward declaration */
int yyparse(char * conffile);
+void rtereg_confrestart(FILE *input_file);
/* Parse the configuration file */
int rtereg_conf_handle(char * conffile)
{
extern FILE * rtereg_confin;
int ret;
-
- TRACE_ENTRY("%p", conffile);
-
- TRACE_DEBUG (FULL, "Parsing configuration file: %s...", conffile);
-
+
+ LOG_D("[rt_ereg] parsing configuration file '%s'", conffile);
+
rtereg_confin = fopen(conffile, "r");
if (rtereg_confin == NULL) {
ret = errno;
fd_log_debug("Unable to open extension configuration file %s for reading: %s", conffile, strerror(ret));
- TRACE_DEBUG (INFO, "Error occurred, message logged -- configuration file.");
+ LOG_E("[rt_ereg] error occurred, message logged -- configuration file.");
return ret;
}
+ rtereg_confrestart(rtereg_confin);
ret = yyparse(conffile);
fclose(rtereg_confin);
+ if (rtereg_conf[rtereg_conf_size-1].finished == 0) {
+ LOG_E("[rt_ereg] configuration invalid, AVP ended without OCTETSTRING AVP");
+ return EINVAL;
+ }
+
if (ret != 0) {
- TRACE_DEBUG (INFO, "Unable to parse the configuration file.");
+ LOG_E("[rt_ereg] unable to parse the configuration file.");
return EINVAL;
} else {
- TRACE_DEBUG(FULL, "[rt-ereg] Added %d rules successfully.", rtereg_conf.rules_nb);
+ int i, sum = 0;
+ for (i=0; i<rtereg_conf_size; i++) {
+ sum += rtereg_conf[i].rules_nb;
+ }
+ LOG_D("[rt-ereg] Added %d rules successfully.", sum);
+ }
+
+ return 0;
+}
+
+int avp_add(const char *name)
+{
+ void *ret;
+ int level;
+
+ if (rtereg_conf[rtereg_conf_size-1].finished) {
+ if ((ret = realloc(rtereg_conf, sizeof(*rtereg_conf)*(rtereg_conf_size+1))) == NULL) {
+ LOG_E("[rt_ereg] realloc failed");
+ return -1;
+ }
+ rtereg_conf_size++;
+ rtereg_conf = ret;
+ memset(&rtereg_conf[rtereg_conf_size-1], 0, sizeof(*rtereg_conf));
+ LOG_D("[rt_ereg] New AVP group found starting with %s", name);
+ }
+ level = rtereg_conf[rtereg_conf_size-1].level + 1;
+
+ if ((ret = realloc(rtereg_conf[rtereg_conf_size-1].avps, sizeof(*rtereg_conf[rtereg_conf_size-1].avps)*level)) == NULL) {
+ LOG_E("[rt_ereg] realloc failed");
+ return -1;
+ }
+ rtereg_conf[rtereg_conf_size-1].avps = ret;
+
+ CHECK_FCT_DO( fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME_ALL_VENDORS, name, &rtereg_conf[rtereg_conf_size-1].avps[level-1], ENOENT ),
+ {
+ LOG_E("[rt_ereg] Unable to find '%s' AVP in the loaded dictionaries.", name);
+ return -1;
+ } );
+
+ /* Now check the type */
+ {
+ struct dict_avp_data data;
+ CHECK_FCT( fd_dict_getval( rtereg_conf[rtereg_conf_size-1].avps[level-1], &data) );
+ if (data.avp_basetype == AVP_TYPE_OCTETSTRING) {
+ rtereg_conf[rtereg_conf_size-1].finished = 1;
+ } else if (data.avp_basetype != AVP_TYPE_GROUPED) {
+ LOG_E("[rt_ereg] '%s' AVP is not an OCTETSTRING nor GROUPED AVP (%d).", name, data.avp_basetype);
+ return -1;
+ }
}
-
+ rtereg_conf[rtereg_conf_size-1].level = level;
return 0;
}
@@ -92,8 +145,8 @@ int rtereg_conflex(YYSTYPE *lvalp, YYLTYPE *llocp);
/* Function to report the errors */
void yyerror (YYLTYPE *ploc, char * conffile, char const *s)
{
- TRACE_DEBUG(INFO, "Error in configuration parsing");
-
+ LOG_E("[rt_ereg] error in configuration parsing");
+
if (ploc->first_line != ploc->last_line)
fd_log_debug("%s:%d.%d-%d.%d : %s", conffile, ploc->first_line, ploc->first_column, ploc->last_line, ploc->last_column, s);
else if (ploc->first_column != ploc->last_column)
@@ -125,61 +178,41 @@ void yyerror (YYLTYPE *ploc, char * conffile, char const *s)
%%
/* The grammar definition */
-conffile: rules avp rules
+conffile: avp rules
+ | conffile avp rules
;
-
+
/* a server entry */
-avp: AVP '=' QSTRING ';'
- {
- if (rtereg_conf.avp != NULL) {
- yyerror(&yylloc, conffile, "Only one AVP can be specified");
- YYERROR;
- }
-
- CHECK_FCT_DO( fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, $3, &rtereg_conf.avp, ENOENT ),
- {
- TRACE_DEBUG(INFO, "Unable to find '%s' AVP in the loaded dictionaries.", $3);
- yyerror (&yylloc, conffile, "Invalid AVP value.");
- YYERROR;
- } );
-
- /* Now check the type */
- {
- struct dict_avp_data data;
- CHECK_FCT( fd_dict_getval( rtereg_conf.avp, &data) );
- CHECK_PARAMS_DO (data.avp_basetype == AVP_TYPE_OCTETSTRING,
- {
- TRACE_DEBUG(INFO, "'%s' AVP in not an OCTETSTRING AVP (%d).", $3, data.avp_basetype);
- yyerror (&yylloc, conffile, "AVP in not an OCTETSTRING type.");
- YYERROR;
- } );
- }
- }
+avp: AVP '=' avp_part ';'
+ ;
+
+avp_part: avp_part ':' QSTRING { if (avp_add($3) < 0) { YYERROR; } }
+ | QSTRING { if (avp_add($1) < 0) { YYERROR; } }
;
-
+
rules: /* empty OK */
| rules rule
;
-
+
rule: QSTRING ':' QSTRING '+' '=' INTEGER ';'
{
struct rtereg_rule * new;
int err;
-
+
/* Add new rule in the array */
- rtereg_conf.rules_nb += 1;
- CHECK_MALLOC_DO(rtereg_conf.rules = realloc(rtereg_conf.rules, rtereg_conf.rules_nb * sizeof(struct rtereg_rule)),
+ rtereg_conf[rtereg_conf_size-1].rules_nb += 1;
+ CHECK_MALLOC_DO(rtereg_conf[rtereg_conf_size-1].rules = realloc(rtereg_conf[rtereg_conf_size-1].rules, rtereg_conf[rtereg_conf_size-1].rules_nb * sizeof(struct rtereg_rule)),
{
yyerror (&yylloc, conffile, "Not enough memory to store the configuration...");
YYERROR;
} );
-
- new = &rtereg_conf.rules[rtereg_conf.rules_nb - 1];
-
+
+ new = &rtereg_conf[rtereg_conf_size-1].rules[rtereg_conf[rtereg_conf_size-1].rules_nb - 1];
+
new->pattern = $1;
new->server = $3;
new->score = $6;
-
+
/* Attempt to compile the regex */
CHECK_FCT_DO( err=regcomp(&new->preg, new->pattern, REG_EXTENDED | REG_NOSUB),
{
@@ -187,7 +220,7 @@ rule: QSTRING ':' QSTRING '+' '=' INTEGER ';'
size_t bl;
/* Error while compiling the regex */
- TRACE_DEBUG(INFO, "Error while compiling the regular expression '%s':", new->pattern);
+ LOG_E("[rt_ereg] error while compiling the regular expression '%s':", new->pattern);
/* Get the error message size */
bl = regerror(err, &new->preg, NULL, 0);
@@ -197,11 +230,11 @@ rule: QSTRING ':' QSTRING '+' '=' INTEGER ';'
/* Get the error message content */
regerror(err, &new->preg, buf, bl);
- TRACE_DEBUG(INFO, "\t%s", buf);
-
+ LOG_E("\t%s", buf);
+
/* Free the buffer, return the error */
free(buf);
-
+
yyerror (&yylloc, conffile, "Invalid regular expression.");
YYERROR;
} );