MAJOR: pattern/map: Extends the map edition system in the patterns
This patch add the following socket command line options:
show acl [<id>]
clear acl <id>
get acl <id> <pattern>
del acl <id> <pattern>
add acl <id> <pattern>
The system used for maps is backported in the pattern functions.
diff --git a/src/pattern.c b/src/pattern.c
index a00aa2b..f03c8fc 100644
--- a/src/pattern.c
+++ b/src/pattern.c
@@ -157,6 +157,9 @@
/* this struct is used to return information */
static struct pattern static_pattern;
+/* This is the root of the list of all pattern_ref avalaibles. */
+struct list pattern_reference = LIST_HEAD_INIT(pattern_reference);
+
/*
*
* The following functions are not exported and are used by internals process
@@ -1000,13 +1003,6 @@
LIST_INIT(&expr->patterns);
}
-void pattern_init_expr(struct pattern_expr *expr)
-{
- LIST_INIT(&expr->patterns);
- expr->pattern_tree = EB_ROOT_UNIQUE;
- expr->pattern_tree_2 = EB_ROOT_UNIQUE;
-}
-
/*
*
* The following functions are used for the pattern indexation
@@ -1606,15 +1602,177 @@
free(pat->pat.smp);
free(pat);
}
+}
+
+void pattern_init_expr(struct pattern_expr *expr)
+{
+ LIST_INIT(&expr->patterns);
+ expr->pattern_tree = EB_ROOT_UNIQUE;
+ expr->pattern_tree_2 = EB_ROOT_UNIQUE;
+}
+
+void pattern_init_head(struct pattern_head *head)
+{
+ LIST_INIT(&head->head);
+}
+
+/* The following functions are relative to the management of the reference
+ * lists. These lists are used to store the original pattern and associated
+ * value as string form.
+ *
+ * This is used with modifiable ACL and MAPS
+ */
+
+/* This function lookup for reference. If the reference is found, they return
+ * pointer to the struct pat_ref, else return NULL.
+ */
+struct pat_ref *pat_ref_lookup(const char *reference)
+{
+ struct pat_ref *ref;
+
+ list_for_each_entry(ref, &pattern_reference, list)
+ if (strcmp(reference, ref->reference) == 0)
+ return ref;
+ return NULL;
+}
+
+/* This function remove all pattern match <key> from the the reference
+ * and from each expr member of the reference. This fucntion returns 1
+ * if the deletion is done and return 0 is the entry is not found.
+ */
+int pat_ref_delete(struct pat_ref *ref, const char *key)
+{
+ struct pattern_expr *expr;
+ struct pat_ref_elt *elt, *safe;
+ int found = 0;
+
+ /* delete pattern from reference */
+ list_for_each_entry_safe(elt, safe, &ref->head, list) {
+ if (strcmp(key, elt->pattern) == 0) {
+ LIST_DEL(&elt->list);
+ free(elt->sample);
+ free(elt->pattern);
+ free(elt);
+ found = 1;
+ }
+ }
+
+ if (!found)
+ return 0;
+
+ list_for_each_entry(expr, &ref->pat, listr)
+ pattern_delete(key, expr, NULL);
+
+ return 1;
+}
+
+/* This function modify the sample of the first pattern that match the <key>. */
+int pat_ref_set(struct pat_ref *ref, const char *key, const char *value)
+{
+ struct pattern_expr *expr;
+ struct pat_ref_elt *elt;
+ struct sample_storage **smp;
+ char *sample;
+ int found = 0;
+
+ /* modify pattern from reference */
+ list_for_each_entry(elt, &ref->head, list) {
+ if (strcmp(key, elt->pattern) == 0) {
+ sample = strdup(value);
+ if (!sample)
+ return 0;
+ free(elt->sample);
+ elt->sample = sample;
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ return 0;
+
+ list_for_each_entry(expr, &ref->pat, listr) {
+ smp = pattern_find_smp(key, expr, NULL);
+ if (smp && expr->pat_head->parse_smp)
+ if (!expr->pat_head->parse_smp(value, *smp))
+ *smp = NULL;
+ }
+
+ return 1;
+}
+
+/* This function create new reference. <ref> is the reference name.
+ * <flags> are PAT_REF_*. /!\ The reference is not checked, and must
+ * be unique. The user must check the reference with "pat_ref_lookup()"
+ * before calling this function. If the fucntion fail, it return NULL,
+ * else return new struct pat_ref.
+ */
+struct pat_ref *pat_ref_new(const char *reference, unsigned int flags)
+{
+ struct pat_ref *ref;
+
+ ref = malloc(sizeof(*ref));
+ if (!ref)
+ return NULL;
+
+ ref->reference = strdup(reference);
+ if (!ref->reference) {
+ free(ref);
+ return NULL;
+ }
+
+ ref->flags = flags;
+ LIST_INIT(&ref->head);
+ LIST_INIT(&ref->pat);
+
+ LIST_ADDQ(&pattern_reference, &ref->list);
+
+ return ref;
+}
+
+/* This function adds entry to <ref>. It can failed with memory error.
+ * If the function fails, it returns 0.
+ */
+int pat_ref_append(struct pat_ref *ref, char *pattern, char *sample, int line)
+{
+ struct pat_ref_elt *elt;
+
+ elt = malloc(sizeof(*elt));
+ if (!elt)
+ return 0;
+
+ elt->line = line;
+
+ elt->pattern = strdup(pattern);
+ if (!elt->pattern) {
+ free(elt);
+ return 0;
+ }
+
+ if (sample) {
+ elt->sample = strdup(sample);
+ if (!elt->sample) {
+ free(elt->pattern);
+ free(elt);
+ return 0;
+ }
+ }
+ else
+ elt->sample = NULL;
+
+ LIST_ADDQ(&ref->head, &elt->list);
+
+ return 1;
}
/* return 1 if the process is ok
* return -1 if the parser fail. The err message is filled.
* return -2 if out of memory
*/
-int pattern_register(struct pattern_expr *expr, const char *arg,
- struct sample_storage *smp,
- int patflags, char **err)
+static inline
+int pattern_add(struct pattern_expr *expr, const char *arg,
+ struct sample_storage *smp,
+ int patflags, char **err)
{
int ret;
struct pattern pattern;
@@ -1625,30 +1783,247 @@
pattern.smp = smp;
/* parse pattern */
- ret = expr->parse(arg, &pattern, err);
+ ret = expr->pat_head->parse(arg, &pattern, err);
if (!ret)
return 0;
/* index pattern */
- if (!expr->index(expr, &pattern, err))
+ if (!expr->pat_head->index(expr, &pattern, err))
+ return 0;
+
+ return 1;
+}
+
+/* This function create sample found in <elt>, parse the pattern also
+ * found in <elt> and insert it in <expr>. The function copy <patflags>
+ * in <expr>. If the function fails, it returns0 and <err> is filled.
+ * In succes case, the function returns 1.
+ */
+static inline
+int pat_ref_push(struct pat_ref_elt *elt, struct pattern_expr *expr,
+ int patflags, char **err)
+{
+ int ret;
+ struct sample_storage *smp;
+
+ /* Create sample */
+ if (elt->sample && expr->pat_head->parse_smp) {
+ /* New sample. */
+ smp = malloc(sizeof(*smp));
+ if (!smp)
+ return 0;
+
+ /* Parse value. */
+ if (!expr->pat_head->parse_smp(elt->sample, smp)) {
+ memprintf(err, "unable to parse '%s'", elt->sample);
+ free(smp);
+ return 0;
+ }
+
+ }
+ else
+ smp = NULL;
+
+ /* Index value */
+ ret = pattern_add(expr, elt->pattern, smp, patflags, err);
+ if (ret != 1) {
+ free(smp);
+ if (ret == -2)
+ memprintf(err, "out of memory");
return 0;
+ }
return 1;
}
+/* This function adds entry to <ref>. It can failed with memory error.
+ * The new entry is added at all the pattern_expr registered in this
+ * reference. The function stop on the first error encountered. It
+ * returns 0 and err is filled.
+ *
+ * If an error is encountered, The complete add operation is cancelled.
+ */
+int pat_ref_add(struct pat_ref *ref,
+ const char *pattern, const char *sample,
+ char **err)
+{
+ struct pat_ref_elt *elt;
+ struct pattern_expr *expr;
+
+ elt = malloc(sizeof(*elt));
+ if (!elt) {
+ memprintf(err, "out of memory error");
+ return 0;
+ }
+
+ elt->line = -1;
+
+ elt->pattern = strdup(pattern);
+ if (!elt->pattern) {
+ free(elt);
+ memprintf(err, "out of memory error");
+ return 0;
+ }
+
+ if (sample) {
+ elt->sample = strdup(sample);
+ if (!elt->sample) {
+ free(elt->pattern);
+ free(elt);
+ memprintf(err, "out of memory error");
+ return 0;
+ }
+ }
+ else
+ elt->sample = NULL;
+
+ LIST_ADDQ(&ref->head, &elt->list);
+
+ list_for_each_entry(expr, &ref->pat, listr) {
+ if (!pat_ref_push(elt, expr, 0, err)) {
+ /* Try to delete all the added entries. */
+ pat_ref_delete(ref, pattern);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/* This function prune all entries of <ref>. This function
+ * prune the associated pattern_expr.
+ */
+void pat_ref_prune(struct pat_ref *ref)
+{
+ struct pat_ref_elt *elt, *safe;
+ struct pattern_expr *expr;
+
+ list_for_each_entry_safe(elt, safe, &ref->head, list) {
+ LIST_DEL(&elt->list);
+ free(elt->pattern);
+ free(elt->sample);
+ free(elt);
+ }
+
+ list_for_each_entry(expr, &ref->pat, listr)
+ expr->pat_head->prune(expr);
+}
+
+/* This function browse <ref> and try to index each entries in the <expr>.
+ * If the flag <soe> (stop on error) is set, this function stop on the first
+ * error, <err> is filled and return 0. If is not set, the function try to
+ * load each entries and 1 is always returned.
+ */
+int pat_ref_load(struct pat_ref *ref, struct pattern_expr *expr,
+ int patflags, int soe, char **err)
+{
+ struct pat_ref_elt *elt;
+
+ list_for_each_entry(elt, &ref->head, list) {
+ if (soe && !pat_ref_push(elt, expr, patflags, err)) {
+ if (elt->line > 0)
+ memprintf(err, "%s at line %d of file '%s'",
+ *err, elt->line, ref->reference);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/* This function lookup for existing reference <ref> in pattern_head <head>. */
+struct pattern_expr *pattern_lookup_expr(struct pattern_head *head, struct pat_ref *ref)
+{
+ struct pattern_expr *expr;
+
+ list_for_each_entry(expr, &head->head, listh)
+ if (expr->ref == ref)
+ return expr;
+ return NULL;
+}
+
+/* This function create new pattern_expr associated to the reference <ref>.
+ * <ref> can be NULL. If an error is occured, the function returns NULL and
+ * <err> is filled. Otherwise, the function returns new pattern_expr linked
+ * with <head> and <ref>.
+ */
+struct pattern_expr *pattern_new_expr(struct pattern_head *head, struct pat_ref *ref, char **err)
+{
+ struct pattern_expr *expr;
+
+ /* A lot of memory. */
+ expr = malloc(sizeof(*expr));
+ if (!expr) {
+ memprintf(err, "out of memory");
+ return NULL;
+ }
+
+ pattern_init_expr(expr);
+
+ /* Link with the pattern_head. */
+ LIST_ADDQ(&head->head, &expr->listh);
+ expr->pat_head = head;
+
+ /* Link with ref, or to self to facilitate LIST_DEL() */
+ if (ref)
+ LIST_ADDQ(&ref->pat, &expr->listr);
+ else
+ LIST_INIT(&expr->listr);
+
+ expr->ref = ref;
+ return expr;
+}
+
+/* return 1 if the process is ok
+ * return -1 if the parser fail. The err message is filled.
+ * return -2 if out of memory
+ */
+int pattern_register(struct pattern_head *head,
+ char *reference, int refflags,
+ const char *arg,
+ struct sample_storage *smp,
+ int patflags, char **err)
+{
+ struct pattern_expr *expr;
+ struct pat_ref *ref;
+
+ /* If reference is set, look up for existing reference. If the
+ * reference is not found, create it.
+ */
+ if (reference) {
+ ref = pat_ref_lookup(reference);
+ if (!ref) {
+ ref = pat_ref_new(reference, refflags);
+ if (!ref) {
+ memprintf(err, "out of memory");
+ return 0;
+ }
+ }
+ }
+ else
+ ref = NULL;
+
+ /* look for reference or create it */
+ expr = pattern_lookup_expr(head, ref);
+ if (!expr) {
+ expr = pattern_new_expr(head, ref, err);
+ if (!expr)
+ return 0;
+ }
+
+ /* Index value. */
+ return pattern_add(expr, arg, smp, patflags, err);
+}
+
/* Reads patterns from a file. If <err_msg> is non-NULL, an error message will
* be returned there on errors and the caller will have to free it.
*/
-int pattern_read_from_file(struct pattern_expr *expr,
- const char *filename, int patflags,
- char **err)
+int pat_ref_read_from_file(struct pat_ref *ref, const char *filename, char **err)
{
FILE *file;
char *c;
char *arg;
int ret = 0;
int line = 0;
- int code;
file = fopen(filename, "r");
if (!file) {
@@ -1682,15 +2057,10 @@
if (c == arg)
continue;
- code = pattern_register(expr, arg, NULL, patflags, err);
- if (code == -2) {
+ if (!pat_ref_append(ref, arg, NULL, line)) {
memprintf(err, "out of memory when loading patterns from file <%s>", filename);
goto out_close;
}
- else if (code < 0) {
- memprintf(err, "%s when loading patterns from file <%s>", *err, filename);
- goto out_close;
- }
}
ret = 1; /* success */
@@ -1700,15 +2070,59 @@
return ret;
}
+int pattern_read_from_file(struct pattern_head *head, unsigned int refflags,
+ const char *filename, int patflags,
+ char **err)
+{
+ struct pat_ref *ref;
+ struct pattern_expr *expr;
+
+ /* Look for existing reference. If the reference doesn't exists,
+ * create it and load file.
+ */
+ ref = pat_ref_lookup(filename);
+ if (!ref) {
+ ref = pat_ref_new(filename, refflags);
+ if (!ref) {
+ memprintf(err, "out of memory");
+ return 0;
+ }
+
+ if (!pat_ref_read_from_file(ref, filename, err))
+ return 0;
+ }
+
+ /* Now, we can loading patterns from the reference. */
+
+ /* Lookup for existing reference in the head. If the reference
+ * doesn't exists, create it.
+ */
+ expr = pattern_lookup_expr(head, ref);
+ if (!expr) {
+ expr = pattern_new_expr(head, ref, err);
+ if (!expr)
+ return 0;
+ }
+
+ /* Load reference content in expression. */
+ if (!pat_ref_load(ref, expr, patflags, 1, err))
+ return 0;
+
+ return 1;
+}
+
/* This function executes a pattern match on a sample. It applies pattern <expr>
* to sample <smp>. The function returns NULL if the sample dont match. It returns
* non-null if the sample match. If <fill> is true and the sample match, the
* function returns the matched pattern. In many cases, this pattern can be a
* static buffer.
*/
-struct pattern *pattern_exec_match(struct pattern_expr *expr, struct sample *smp, int fill)
+struct pattern *pattern_exec_match(struct pattern_head *head, struct sample *smp, int fill)
{
- if (!expr->match) {
+ struct pattern_expr *expr;
+ struct pattern *pat;
+
+ if (!head->match) {
if (fill) {
static_pattern.smp = NULL;
static_pattern.flags = 0;
@@ -1717,13 +2131,26 @@
}
return &static_pattern;
}
+
+ list_for_each_entry(expr, &head->head, listh) {
+ pat = head->match(smp, expr, fill);
+ if (pat)
+ return pat;
+ }
- return expr->match(smp, expr, fill);
+ return NULL;
}
/* This function prune the pattern expression. */
-void pattern_prune(struct pattern_expr *expr)
+void pattern_prune(struct pattern_head *head)
{
- expr->prune(expr);
+ struct pattern_expr *expr, *safe;
+
+ list_for_each_entry_safe(expr, safe, &head->head, listh) {
+ LIST_DEL(&expr->listh);
+ LIST_DEL(&expr->listr);
+ head->prune(expr);
+ free(expr);
+ }
}
/* This function lookup for a pattern matching the <key> and return a
@@ -1735,9 +2162,9 @@
{
struct pattern pattern;
- if (!expr->parse(key, &pattern, err))
+ if (!expr->pat_head->parse(key, &pattern, err))
return NULL;
- return expr->find_smp(expr, &pattern);
+ return expr->pat_head->find_smp(expr, &pattern);
}
/* This function search all the pattern matching the <key> and delete it.
@@ -1748,8 +2175,8 @@
{
struct pattern pattern;
- if (!expr->parse(key, &pattern, err))
+ if (!expr->pat_head->parse(key, &pattern, err))
return 0;
- expr->delete(expr, &pattern);
+ expr->pat_head->delete(expr, &pattern);
return 1;
}