Add infrastructure for display filter functions.
authorGilbert Ramirez <gram@alumni.rice.edu>
Tue, 2 May 2006 14:26:17 +0000 (14:26 -0000)
committerGilbert Ramirez <gram@alumni.rice.edu>
Tue, 2 May 2006 14:26:17 +0000 (14:26 -0000)
Add upper() and lower() display filter functions for string fields.

svn path=/trunk/; revision=18071

29 files changed:
doc/README.developer
doc/ethereal-filter.pod.template
epan/dfilter/Makefile.am
epan/dfilter/Makefile.nmake
epan/dfilter/dfunctions.c [new file with mode: 0644]
epan/dfilter/dfunctions.h [new file with mode: 0644]
epan/dfilter/dfvm.c
epan/dfilter/dfvm.h
epan/dfilter/gencode.c
epan/dfilter/grammar.lemon
epan/dfilter/scanner.l
epan/dfilter/semcheck.c
epan/dfilter/sttype-function.c [new file with mode: 0644]
epan/dfilter/sttype-function.h [new file with mode: 0644]
epan/dfilter/syntax-tree.c
epan/dfilter/syntax-tree.h
epan/ftypes/ftype-bytes.c
epan/ftypes/ftype-double.c
epan/ftypes/ftype-guid.c
epan/ftypes/ftype-integer.c
epan/ftypes/ftype-ipv4.c
epan/ftypes/ftype-none.c
epan/ftypes/ftype-pcre.c
epan/ftypes/ftype-string.c
epan/ftypes/ftype-time.c
epan/ftypes/ftype-tvbuff.c
epan/ftypes/ftypes.c
epan/ftypes/ftypes.h
tools/dfilter-test.py

index abbd330298d216aa5dd3e5f55970fa6babc38c29..9b760648f13053337b86d1a3f7f472d4e3412272 100644 (file)
@@ -3209,6 +3209,70 @@ field_info structures that are interesting to the display filter.  This
 makes lookup of those field_info structures during the filtering process
 faster.
 
+5.4 Display Filter Functions
+
+You define a desplay filte function by adding an entry to
+the df_functions table in epan/dfilter/dfunctions.c. The record struct
+is defined in defunctions.h, and shown here:
+
+typedef struct {
+    char            *name;
+    DFFuncType      function;
+    ftenum_t        retval_ftype;
+    guint           min_nargs;
+    guint           max_nargs;
+    DFSemCheckType  semcheck_param_function;
+} df_func_def_t;
+
+name - the name of the function; this is how the user will call your
+    function in the display filter language
+
+function - this is the run-time processing of your function.
+
+retval_ftype - what type of FT_* type does your function return?
+
+min_nargs - minimum number of arguments your function accepts
+max_nargs - maximum number of arguments your function accepts
+
+semcheck_param_function - called during the semantic check of the
+    display filter string.
+
+DFFuncType function
+-------------------
+typedef gboolean (*DFFuncType)(GList *arg1list, GList *arg2list, GList **retval);
+
+The return value of your function is a gboolean; TRUE if processing went fine,
+or FALSE if there was some sort of exception.
+
+For now, display filter functions can accept a maximum of 2 arguments.
+The "arg1list" parameter is the GList for the first argument. The
+'arg2list" parameter is the GList for the second argument. All arguments
+to display filter functions are lists. This is because in the display
+filter language a protocol field may have multiple instances. For example,
+a field like "ip.addr" will exist more than once in a single frame. So
+when the user invokes this display filter:
+
+    somefunc(ip.addr) == TRUE
+
+even though "ip.addr" is a single argument, the "somefunc" function will
+receive a GList of *all* the values of "ip.addr" in the frame.
+
+Similarly, the return value of the function needs to be a GList, since all
+values in the display filter language are lists. The GList** retval argument
+is passed to your function so you can set the pointer to your return value.
+
+DFSemCheckType
+--------------
+typedef void (*DFSemCheckType)(int param_num, stnode_t *st_node);
+
+For each parameter in the syntax tree, this function will be called.
+"param_num" will indicate the number of the parameter, starting with 0.
+The "stnode_t" is the syntax-tree node representing that parameter.
+If everything is okay with the value of that stnode_t, your function
+does nothing --- it merely returns. If something is wrong, however,
+it should THROW a TypeError exception.
+
+
 
 6.0 Adding new capabilities.
 
index f4b295647451347a059de58f885abbe7560f1597..b560a8b3e4b2b32842483fbfbde27e697b933335 100644 (file)
@@ -93,6 +93,19 @@ have been compiled with the PCRE library. This can be checked by running:
 
 or selecting the "About Ethereal" item from the "Help" menu in B<Ethereal>.
 
+=head2 Functions
+
+The filter language has the following functions:
+
+    upper(string-field) - converts a string field to uppercase
+    lower(string-field) - converts a string field to lowercase
+
+upper() and lower() are useful for performing case-insensitive string
+comparisons. For example:
+
+    upper(ncp.nds_stream_name) contains "MACRO"
+    lower(mount.dump.hostname) == "angel"
+
 =head2 Protocol field types
 
 Each protocol field is typed. The types are:
index 139c5a661d1627ea650f25208366844d4dec67bd..7e1614320dc8ae884c5f67ff576d7ca05e30c5d9 100644 (file)
@@ -46,6 +46,8 @@ libdfilter_la_SOURCES = \
        dfilter.c               \
        dfilter.h               \
        dfilter-int.h           \
+       dfunctions.c    \
+       dfunctions.h    \
        dfvm.c                  \
        dfvm.h                  \
        drange.c                \
@@ -59,6 +61,8 @@ libdfilter_la_SOURCES = \
        scanner.c               \
        semcheck.c              \
        semcheck.h              \
+       sttype-function.c       \
+       sttype-function.h       \
        sttype-integer.c        \
        sttype-pointer.c        \
        sttype-range.c          \
index 8593e39dbeb800dcde04884f5ac1fea172612b31..38ac1d7c53ca879c3d7bf09c663af1e72d49721d 100644 (file)
@@ -20,6 +20,7 @@ CVARSDLL=-DWIN32 -DNULL=0 -D_MT -D_DLL
 
 OBJECTS = \
        dfilter.obj             \
+       dfunctions.obj  \
        dfvm.obj                \
        drange.obj              \
        gencode.obj             \
@@ -27,6 +28,7 @@ OBJECTS = \
        grammar.obj             \
        scanner.obj             \
        semcheck.obj            \
+       sttype-function.obj     \
        sttype-integer.obj      \
        sttype-pointer.obj      \
        sttype-range.obj        \
diff --git a/epan/dfilter/dfunctions.c b/epan/dfilter/dfunctions.c
new file mode 100644 (file)
index 0000000..1b949b2
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * $Id$
+ *
+ * Ethereal - Network traffic analyzer
+ * 
+ * Copyright 2006 Gilbert Ramirez <gram@alumni.rice.edu>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib.h>
+
+#include "dfunctions.h"
+#include "dfilter-int.h"
+
+#include <string.h>
+#include <ctype.h>
+
+#include <ftypes/ftypes.h>
+#include <epan/exceptions.h>
+
+/* lowercase an ASCII character.
+ * (thanks to Guy Harris for the function) */
+static gchar
+string_ascii_to_lower(gchar c)
+{
+    return ((c & 0x80) ? c : tolower(c));
+}
+
+/* uppercase an ASCII character. */
+static gchar
+string_ascii_to_upper(gchar c)
+{
+    return ((c & 0x80) ? c : toupper(c));
+}
+
+
+/* Convert an FT_STRING using a callback function */
+static gboolean
+string_walk(GList* arg1list, GList **retval, gchar(*conv_func)(gchar))
+{
+    GList       *arg1;
+    fvalue_t    *arg_fvalue;
+    fvalue_t    *new_ft_string;
+    char *s, *c;
+
+    arg1 = arg1list;
+    while (arg1) {
+        arg_fvalue = arg1->data; 
+        switch (fvalue_ftype(arg_fvalue)->ftype) {
+            case FT_STRING:
+                s = g_strdup(fvalue_get(arg1->data));
+                for (c = s; *c; c++) {
+                        /**c = string_ascii_to_lower(*c);*/
+                        *c = conv_func(*c);
+                }
+
+                new_ft_string = fvalue_new(FT_STRING);
+                fvalue_set(new_ft_string, s, TRUE);
+                *retval = g_list_append(*retval, new_ft_string);
+                break;
+
+            /* XXX - it would be nice to handle FT_TVBUFF, too */
+
+            default:
+                break;
+        } 
+        arg1 = arg1->next;
+    }
+
+    return TRUE;
+}
+
+/* dfilter function: lower() */
+static gboolean
+df_func_lower(GList* arg1list, GList *arg2junk _U_, GList **retval)
+{
+    return string_walk(arg1list, retval, string_ascii_to_lower);
+}
+
+/* dfilter function: upper() */
+static gboolean
+df_func_upper(GList* arg1list, GList *arg2junk _U_, GList **retval)
+{
+    return string_walk(arg1list, retval, string_ascii_to_upper);
+}
+
+/* For upper() and lower(), checks that the parameter passed to
+ * it is an FT_STRING */
+static void
+ul_semcheck_params(int param_num, stnode_t *st_node)
+{
+    sttype_id_t type;
+    ftenum_t    ftype;
+    header_field_info *hfinfo;
+
+    type = stnode_type_id(st_node);
+
+    if (param_num == 0) {
+        switch(type) {
+            case STTYPE_FIELD:
+                hfinfo = stnode_data(st_node);
+                ftype = hfinfo->type;
+                if (ftype != FT_STRING && ftype != FT_STRINGZ
+                        && ftype != FT_UINT_STRING) {
+                    dfilter_fail("Only strings can be used in upper() or lower()");
+                    THROW(TypeError);
+                }
+                break;
+            default:
+                dfilter_fail("Only string-type fields can be used in upper() or lower()");
+                THROW(TypeError);
+        }
+    }
+    else {
+        g_assert_not_reached();
+    }
+}
+
+/* The table of all display-filter functions */
+static df_func_def_t
+df_functions[] = {
+    { "lower", df_func_lower, FT_STRING, 1, 1, ul_semcheck_params },
+    { "upper", df_func_upper, FT_STRING, 1, 1, ul_semcheck_params },
+    { NULL, NULL, 0, 0, 0, NULL }
+};
+
+/* Lookup a display filter function record by name */
+df_func_def_t*
+df_func_lookup(char *name)
+{
+    df_func_def_t *func_def;
+
+    func_def = df_functions;
+    while (func_def->function != NULL) {
+        if (strcmp(func_def->name, name) == 0) {
+            return func_def;
+        }
+        func_def++;
+    }
+    return NULL;
+}
diff --git a/epan/dfilter/dfunctions.h b/epan/dfilter/dfunctions.h
new file mode 100644 (file)
index 0000000..3e7ca3f
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * $Id$
+ *
+ * Ethereal - Network traffic analyzer
+ * 
+ * Copyright 2006 Gilbert Ramirez <gram@alumni.rice.edu>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef DFUNCTIONS_H
+#define DFUNCTIONS_H
+
+#include <glib.h>
+#include <ftypes/ftypes.h>
+#include "syntax-tree.h"
+
+/* The run-time logic of the dfilter function */
+typedef gboolean (*DFFuncType)(GList *arg1list, GList *arg2list, GList **retval);
+
+/* The semantic check for the dfilter function */
+typedef void (*DFSemCheckType)(int param_num, stnode_t *st_node);
+
+/* If a function needs more args than this, increase
+ * this macro and add more arg members to the dfvm_insn_t
+ * struct in dfvm.h, and add some logic to dfw_append_function()
+ * and dfvm_apply() */
+#define DFUNCTION_MAX_NARGS 2
+
+/* This is a "function definition" record, holding everything
+ * we need to know about a function */
+typedef struct {
+    char            *name;
+    DFFuncType      function;
+    ftenum_t        retval_ftype;
+    guint           min_nargs;
+    guint           max_nargs;
+    DFSemCheckType  semcheck_param_function;
+} df_func_def_t;
+
+/* Return the function definition record for a function of named "name" */
+df_func_def_t* df_func_lookup(char *name);
+
+#endif
index eb1521e8e5a4c92a61b1f9ec77dbe34c5e2a7f40..ad3a467243164a826e2182e1967023766ed4ea1d 100644 (file)
@@ -118,6 +118,18 @@ dfvm_dump(FILE *f, GPtrArray *insns)
                                        arg2->value.numeric);
                                break;
 
+            case CALL_FUNCTION:
+                fprintf(f, "%05d CALL_FUNCTION\t%s (",
+                        id, arg1->value.funcdef->name);
+                if (arg3) {
+                    fprintf(f, "reg#%u", arg3->value.numeric);
+                }
+                if (arg4) {
+                    fprintf(f, ", reg#%u", arg4->value.numeric);
+                }
+                fprintf(f, ") --> reg#%u\n", arg2->value.numeric);
+                break;
+
                        case PUT_FVALUE:
                                value_str = fvalue_to_string_repr(arg1->value.fvalue,
                                        FTREPR_DFILTER, NULL);
@@ -373,8 +385,11 @@ dfvm_apply(dfilter_t *df, proto_tree *tree)
        dfvm_insn_t     *insn;
        dfvm_value_t    *arg1;
        dfvm_value_t    *arg2;
-       dfvm_value_t    *arg3;
+       dfvm_value_t    *arg3 = NULL;
+       dfvm_value_t    *arg4 = NULL;
        header_field_info       *hfinfo;
+    GList           *param1;
+    GList           *param2;
 
        g_assert(tree);
 
@@ -414,6 +429,21 @@ dfvm_apply(dfilter_t *df, proto_tree *tree)
                                                arg1->value.hfinfo, arg2->value.numeric);
                                break;
 
+                       case CALL_FUNCTION:
+                               arg3 = insn->arg3;
+                               arg4 = insn->arg4;
+                param1 = NULL;
+                param2 = NULL;
+                if (arg3) {
+                    param1 = df->registers[arg3->value.numeric];
+                }
+                if (arg4) {
+                    param2 = df->registers[arg4->value.numeric];
+                }
+                accum = arg1->value.funcdef->function(param1, param2,
+                    &df->registers[arg2->value.numeric]); 
+                               break;
+
                        case PUT_FVALUE:
                                accum = put_fvalue(df,
                                                arg1->value.fvalue, arg2->value.numeric);
index 862bb0a3133e0b6d5af92c0f8c827205b2ff790d..da773b77591b2d3006f6cbb03647b3dc5690adb2 100644 (file)
@@ -28,6 +28,7 @@
 #include "dfilter-int.h"
 #include "syntax-tree.h"
 #include "drange.h"
+#include "dfunctions.h"
 
 typedef enum {
        EMPTY,
@@ -36,7 +37,8 @@ typedef enum {
        INSN_NUMBER,
        REGISTER,
        INTEGER,
-       DRANGE
+       DRANGE,
+       FUNCTION_DEF
 } dfvm_value_type_t;
 
 typedef struct {
@@ -47,6 +49,7 @@ typedef struct {
                guint32                 numeric;
                drange                  *drange;
                header_field_info       *hfinfo;
+        df_func_def_t   *funcdef;
        } value;
 
 } dfvm_value_t;
@@ -70,13 +73,13 @@ typedef enum {
        ANY_BITWISE_AND,
        ANY_CONTAINS,
        ANY_MATCHES,
-       MK_RANGE
+       MK_RANGE,
+    CALL_FUNCTION
 
 } dfvm_opcode_t;
 
 typedef struct {
        int             id;
-       int             LHS;
        dfvm_opcode_t   op;
        dfvm_value_t    *arg1;
        dfvm_value_t    *arg2;
index c48329ba2f06c6a61b0a716c921e1a8b20eec978..7d3ef8c162206a64e8d665959a19fc5fcc81fd86 100644 (file)
 #include "syntax-tree.h"
 #include "sttype-range.h"
 #include "sttype-test.h"
+#include "sttype-function.h"
 #include "ftypes/ftypes.h"
 
 static void
 gencode(dfwork_t *dfw, stnode_t *st_node);
 
+static int
+gen_entity(dfwork_t *dfw, stnode_t *st_arg, dfvm_value_t **p_jmp);
+
 static void
 dfw_append_insn(dfwork_t *dfw, dfvm_insn_t *insn)
 {
@@ -155,58 +159,98 @@ dfw_append_mk_range(dfwork_t *dfw, stnode_t *node)
        return reg;
 }
 
+/* returns register number that the functions's result will be in. */
+static int
+dfw_append_function(dfwork_t *dfw, stnode_t *node, dfvm_value_t **p_jmp)
+{
+    GSList *params;
+    int i, num_params, reg;
+    dfvm_value_t **jmps;
+       dfvm_insn_t     *insn;
+       dfvm_value_t    *val1, *val2, *val;
+
+    params = sttype_function_params(node);
+    num_params = g_slist_length(params);
+
+    /* Array to hold the instructions that need to jump to
+     * an instruction if they fail. */
+    jmps = g_malloc(num_params * sizeof(dfvm_value_t*));
+
+    /* Create the new DFVM instruction */
+    insn = dfvm_insn_new(CALL_FUNCTION);
+    
+    val1 = dfvm_value_new(FUNCTION_DEF);
+    val1->value.funcdef = sttype_function_funcdef(node);
+    insn->arg1 = val1;
+       val2 = dfvm_value_new(REGISTER);
+       val2->value.numeric = dfw->next_register++;
+    insn->arg2 = val2;
+    insn->arg3 = NULL;
+    insn->arg4 = NULL;
+
+    i = 0;
+    while (params) {
+        jmps[i] = NULL;
+        reg = gen_entity(dfw, params->data, &jmps[i]);
+
+        val = dfvm_value_new(REGISTER);
+        val->value.numeric = reg;
+
+        switch(i) {
+            case 0:
+                insn->arg3 = val;
+                break;
+            case 1:
+                insn->arg4 = val;
+                break;
+            default:
+                g_assert_not_reached();
+        }
+
+        params = params->next;
+        i++;
+    }
+
+       dfw_append_insn(dfw, insn);
+
+    /* If any of our parameters failed, send them to
+     * our own failure instruction. This *has* to be done
+     * after we caled dfw_append_insn above so that
+     * we know what the next DFVM insruction is, via
+     * dfw->next_insn_id */
+    for (i = 0; i < num_params; i++) {
+        if (jmps[i]) {
+            jmps[i]->value.numeric = dfw->next_insn_id;
+        }
+    }
+
+    /* We need another instruction to jump to another exit
+     * place, if the call() of our function failed for some reaosn */
+    insn = dfvm_insn_new(IF_FALSE_GOTO);
+    g_assert(p_jmp);
+    *p_jmp = dfvm_value_new(INSN_NUMBER);
+    insn->arg1 = *p_jmp;
+    dfw_append_insn(dfw, insn);
+
+    g_free(jmps);
+    
+    return val2->value.numeric;
+}
+
 
 static void
 gen_relation(dfwork_t *dfw, dfvm_opcode_t op, stnode_t *st_arg1, stnode_t *st_arg2)
 {
-       sttype_id_t     type1, type2;
        dfvm_insn_t     *insn;
        dfvm_value_t    *val1, *val2;
        dfvm_value_t    *jmp1 = NULL, *jmp2 = NULL;
        int             reg1 = -1, reg2 = -1;
-       header_field_info       *hfinfo;
 
-       type1 = stnode_type_id(st_arg1);
-       type2 = stnode_type_id(st_arg2);
-
-       if (type1 == STTYPE_FIELD) {
-               hfinfo = stnode_data(st_arg1);
-               reg1 = dfw_append_read_tree(dfw, hfinfo);
-
-               insn = dfvm_insn_new(IF_FALSE_GOTO);
-               jmp1 = dfvm_value_new(INSN_NUMBER);
-               insn->arg1 = jmp1;
-               dfw_append_insn(dfw, insn);
-       }
-       else if (type1 == STTYPE_FVALUE) {
-               reg1 = dfw_append_put_fvalue(dfw, stnode_data(st_arg1));
-       }
-       else if (type1 == STTYPE_RANGE) {
-               reg1 = dfw_append_mk_range(dfw, st_arg1);
-       }
-       else {
-               g_assert_not_reached();
-       }
-
-       if (type2 == STTYPE_FIELD) {
-               hfinfo = stnode_data(st_arg2);
-               reg2 = dfw_append_read_tree(dfw, hfinfo);
-
-               insn = dfvm_insn_new(IF_FALSE_GOTO);
-               jmp2 = dfvm_value_new(INSN_NUMBER);
-               insn->arg1 = jmp2;
-               dfw_append_insn(dfw, insn);
-       }
-       else if (type2 == STTYPE_FVALUE) {
-               reg2 = dfw_append_put_fvalue(dfw, stnode_data(st_arg2));
-       }
-       else if (type2 == STTYPE_RANGE) {
-               reg2 = dfw_append_mk_range(dfw, st_arg2);
-       }
-       else {
-               g_assert_not_reached();
-       }
+    /* Create code for the LHS and RHS of the relation */
+    reg1 = gen_entity(dfw, st_arg1, &jmp1);
+    reg2 = gen_entity(dfw, st_arg2, &jmp2);
 
+    /* Then combine them in a DFVM insruction */
        insn = dfvm_insn_new(op);
        val1 = dfvm_value_new(REGISTER);
        val1->value.numeric = reg1;
@@ -216,6 +260,8 @@ gen_relation(dfwork_t *dfw, dfvm_opcode_t op, stnode_t *st_arg1, stnode_t *st_ar
        insn->arg2 = val2;
        dfw_append_insn(dfw, insn);
 
+    /* If either of the relation argumnents need an "exit" instruction
+     * to jump to (on failure), mark them */
        if (jmp1) {
                jmp1->value.numeric = dfw->next_insn_id;
        }
@@ -225,6 +271,45 @@ gen_relation(dfwork_t *dfw, dfvm_opcode_t op, stnode_t *st_arg1, stnode_t *st_ar
        }
 }
 
+/* Parse an entity, returning the reg that it gets put into.
+ * p_jmp will be set if it has to be set by the calling code; it should
+ * be set tothe place to jump to, to return to the calling code,
+ * if the load of a field from the proto_tree fails. */
+static int
+gen_entity(dfwork_t *dfw, stnode_t *st_arg, dfvm_value_t **p_jmp)
+{
+       sttype_id_t     e_type;
+       dfvm_insn_t     *insn;
+       header_field_info       *hfinfo;
+       e_type = stnode_type_id(st_arg);
+    int reg = -1;
+
+       if (e_type == STTYPE_FIELD) {
+               hfinfo = stnode_data(st_arg);
+               reg = dfw_append_read_tree(dfw, hfinfo);
+
+               insn = dfvm_insn_new(IF_FALSE_GOTO);
+        g_assert(p_jmp);
+               *p_jmp = dfvm_value_new(INSN_NUMBER);
+               insn->arg1 = *p_jmp;
+               dfw_append_insn(dfw, insn);
+       }
+       else if (e_type == STTYPE_FVALUE) {
+               reg = dfw_append_put_fvalue(dfw, stnode_data(st_arg));
+       }
+       else if (e_type == STTYPE_RANGE) {
+               reg = dfw_append_mk_range(dfw, st_arg);
+       }
+       else if (e_type == STTYPE_FUNCTION) {
+        reg = dfw_append_function(dfw, st_arg, p_jmp);
+    }
+       else {
+        printf("sttype_id is %u\n", e_type);
+               g_assert_not_reached();
+       }
+    return reg;
+}
+
 
 static void
 gen_test(dfwork_t *dfw, stnode_t *st_node)
index 08169369c23326fc32abb5437de6aee65cdd1db0..225dd73110b7784cca1cd79a2aa46d1a970269d9 100644 (file)
@@ -9,6 +9,7 @@
 #include "syntax-tree.h"
 #include "sttype-range.h"
 #include "sttype-test.h"
+#include "sttype-function.h"
 #include "drange.h"
 
 #include "grammar.h"
@@ -51,6 +52,9 @@
 %type          drnode_list     {GSList*}
 %destructor    drnode_list     {drange_node_free_list($$);}
 
+%type          funcparams      {GSList*}
+%destructor    funcparams      {st_funcparams_free($$);}
+
 /* This is called as soon as a syntax error happens. After that, 
 any "error" symbols are shifted, if possible. */
 %syntax_error {
@@ -85,6 +89,9 @@ any "error" symbols are shifted, if possible. */
                        hfinfo = stnode_data(TOKEN);
                        dfilter_fail("Syntax error near \"%s\".", hfinfo->abbrev);
                        break;
+               case STTYPE_FUNCTION:
+                       dfilter_fail("The function s was unexpected in this context.");
+                       break;
 
                /* These aren't handed to use as terminal tokens from
                   the scanner, so was can assert that we'll never
@@ -120,11 +127,6 @@ sentence ::= .             { dfw->st_root = NULL; }
 expr(X) ::= relation_test(R).  { X = R; }
 expr(X) ::= logical_test(L).   { X = L; }
 
-expr(X) ::= LPAREN expr(Y) RPAREN.
-{
-       X = Y;
-}
-
 
 /* Logical tests */
 logical_test(T) ::= expr(E) TEST_AND expr(F).
@@ -254,4 +256,35 @@ rel_op2(O) ::= TEST_CONTAINS.  { O = TEST_OP_CONTAINS; }
 rel_op2(O) ::= TEST_MATCHES.  { O = TEST_OP_MATCHES; }
 
 
+/* Functions */
+
+/* A function can have one or more parameters */
+entity(E) ::= FUNCTION(F) LPAREN funcparams(P) RPAREN.
+{
+    E = F;
+       sttype_function_set_params(E, P);
+}
+
+/* A function can have zero parameters. */
+entity(E) ::= FUNCTION(F) LPAREN RPAREN.
+{
+    E = F;
+}
+
+funcparams(P) ::= entity(E).
+{
+       P = g_slist_append(NULL, E);
+}
+
+funcparams(P) ::= funcparams(L) COMMA entity(E).
+{
+       P = g_slist_append(L, E);
+}
+
+
+/* Any expression inside parens is simply that expression */
+expr(X) ::= LPAREN expr(Y) RPAREN.
+{
+       X = Y;
+}
 
index a621292699cf1df1365b5c6282132bfddfcb7a7f..545c923c851aa29d44ff4da4093cf69d0bb418c8 100644 (file)
@@ -32,6 +32,7 @@
 #include "dfilter-int.h"
 #include "syntax-tree.h"
 #include "grammar.h"
+#include "dfunctions.h"
 
 /*
  * GLib 1.2[.x] doesn't define G_MAXINT32 or G_MININT32; if they're not
@@ -75,6 +76,7 @@ GString* quoted_string = NULL;
 
 "("                            return simple(TOKEN_LPAREN);
 ")"                            return simple(TOKEN_RPAREN);
+","                            return simple(TOKEN_COMMA);
 
 "=="                   return simple(TOKEN_TEST_EQ);
 "eq"                   return simple(TOKEN_TEST_EQ);
@@ -232,9 +234,10 @@ GString* quoted_string = NULL;
         return set_lval(TOKEN_UNPARSED, yytext);
 }
 
-[-\+[:alnum:]_.,:]+    {
+[-\+[:alnum:]_.:]+     {
        /* Is it a field name? */
        header_field_info *hfinfo;
+    df_func_def_t *df_func_def;
 
        hfinfo = proto_registrar_get_byname(yytext);
        if (hfinfo) {
@@ -242,8 +245,16 @@ GString* quoted_string = NULL;
                return set_lval(TOKEN_FIELD, hfinfo);
        }
        else {
-               /* No, so treat it as an unparsed string */
-               return set_lval(TOKEN_UNPARSED, yytext);
+        /* Is it a function name? */
+        df_func_def = df_func_lookup(yytext);
+        if (df_func_def) {
+            /* yes, it's a dfilter function */
+            return set_lval(TOKEN_FUNCTION, df_func_def);
+        }
+        else {
+            /* No, so treat it as an unparsed string */
+            return set_lval(TOKEN_UNPARSED, yytext);
+        }
        }
 }
 
@@ -300,10 +311,12 @@ set_lval(int token, gpointer data)
                case TOKEN_UNPARSED:
                        type_id = STTYPE_UNPARSED;
                        break;
+               case TOKEN_FUNCTION:
+                       type_id = STTYPE_FUNCTION;
+                       break;
                default:
                        g_assert_not_reached();
        }
-
        stnode_init(df_lval, type_id, data);
        return token;
 }
index b575be7a96adee371e5905df0b3809d095ccfbe0..9e91bff0e53c0e328cb950dc9d3348e799858c30 100644 (file)
@@ -31,6 +31,7 @@
 #include "syntax-tree.h"
 #include "sttype-range.h"
 #include "sttype-test.h"
+#include "sttype-function.h"
 
 #include <epan/exceptions.h>
 #include <epan/packet.h>
@@ -307,6 +308,13 @@ check_exists(stnode_t *st_arg1)
                        THROW(TypeError);
                        break;
 
+               case STTYPE_FUNCTION:
+            /* XXX - Maybe we should change functions so they can return fields,
+             * in which case the 'exist' should be fine. */
+                       dfilter_fail("You cannot test whether a function is present.");
+                       THROW(TypeError);
+                       break;
+
                case STTYPE_UNINITIALIZED:
                case STTYPE_TEST:
                case STTYPE_INTEGER:
@@ -751,6 +759,161 @@ check_relation_LHS_RANGE(const char *relation_string, FtypeCanFunc can_func _U_,
        }
 }
 
+static stnode_t*
+check_param_entity(stnode_t *st_node)
+{
+       sttype_id_t             e_type;
+       stnode_t                *new_st;
+       fvalue_t                *fvalue;
+    char *s;
+
+       e_type = stnode_type_id(st_node);
+    /* If there's an unparsed string, change it to an FT_STRING */
+    if (e_type == STTYPE_UNPARSED) {
+               s = stnode_data(st_node);
+        fvalue = fvalue_from_unparsed(FT_STRING, s, FALSE, dfilter_fail);
+               if (!fvalue) {
+                       THROW(TypeError);
+               }
+
+               new_st = stnode_new(STTYPE_FVALUE, fvalue);
+               stnode_free(st_node);
+        return new_st;
+    }
+
+    return st_node;
+}
+
+
+/* If the LHS of a relation test is a FUNCTION, run some checks
+ * and possibly some modifications of syntax tree nodes. */
+static void
+check_relation_LHS_FUNCTION(const char *relation_string, FtypeCanFunc can_func,
+               gboolean allow_partial_value,
+               stnode_t *st_node, stnode_t *st_arg1, stnode_t *st_arg2)
+{
+       stnode_t                *new_st;
+       sttype_id_t             type2;
+       header_field_info       *hfinfo2;
+       ftenum_t                ftype1, ftype2;
+       fvalue_t                *fvalue;
+       char                    *s;
+    int             param_i;
+       drange_node             *rn;
+    df_func_def_t   *funcdef;
+    guint             num_params;
+    GSList          *params;
+
+       type2 = stnode_type_id(st_arg2);
+
+    funcdef = sttype_function_funcdef(st_arg1);
+       ftype1 = funcdef->retval_ftype;
+
+    params = sttype_function_params(st_arg1);
+    num_params = g_slist_length(params);
+    if (num_params < funcdef->min_nargs) {
+        dfilter_fail("Function %s needs at least %u arguments.",
+                funcdef->name, funcdef->min_nargs);
+        THROW(TypeError);
+    }
+    else if (num_params > funcdef->max_nargs) {
+        dfilter_fail("Function %s can only accept %u arguments.",
+                funcdef->name, funcdef->max_nargs);
+        THROW(TypeError);
+    }
+
+    param_i = 0;
+    while (params) {
+        params->data = check_param_entity(params->data);
+        funcdef->semcheck_param_function(param_i, params->data);
+        params = params->next;
+    }
+
+       DebugLog(("    5 check_relation_LHS_FUNCTION(%s)\n", relation_string));
+
+       if (!can_func(ftype1)) {
+               dfilter_fail("Function %s (type=%s) cannot participate in '%s' comparison.",
+                               funcdef->name, ftype_pretty_name(ftype1),
+                               relation_string);
+               THROW(TypeError);
+       }
+
+       if (type2 == STTYPE_FIELD) {
+               hfinfo2 = stnode_data(st_arg2);
+               ftype2 = hfinfo2->type;
+
+               if (!compatible_ftypes(ftype1, ftype2)) {
+                       dfilter_fail("Function %s and %s are not of compatible types.",
+                                       funcdef->name, hfinfo2->abbrev);
+                       THROW(TypeError);
+               }
+               /* Do this check even though you'd think that if
+                * they're compatible, then can_func() would pass. */
+               if (!can_func(ftype2)) {
+                       dfilter_fail("%s (type=%s) cannot participate in specified comparison.",
+                                       hfinfo2->abbrev, ftype_pretty_name(ftype2));
+                       THROW(TypeError);
+               }
+       }
+       else if (type2 == STTYPE_STRING) {
+               s = stnode_data(st_arg2);
+               if (strcmp(relation_string, "matches") == 0) {
+                       /* Convert to a FT_PCRE */
+                       fvalue = fvalue_from_string(FT_PCRE, s, dfilter_fail);
+               } else {
+                       fvalue = fvalue_from_string(ftype1, s, dfilter_fail);
+               }
+               if (!fvalue) {
+                       THROW(TypeError);
+               }
+
+               new_st = stnode_new(STTYPE_FVALUE, fvalue);
+               sttype_test_set2_args(st_node, st_arg1, new_st);
+               stnode_free(st_arg2);
+       }
+       else if (type2 == STTYPE_UNPARSED) {
+               s = stnode_data(st_arg2);
+               if (strcmp(relation_string, "matches") == 0) {
+                       /* Convert to a FT_PCRE */
+                       fvalue = fvalue_from_unparsed(FT_PCRE, s, FALSE, dfilter_fail);
+               } else {
+                       fvalue = fvalue_from_unparsed(ftype1, s, allow_partial_value, dfilter_fail);
+               }
+               if (!fvalue) {
+                       THROW(TypeError);
+               }
+
+               new_st = stnode_new(STTYPE_FVALUE, fvalue);
+               sttype_test_set2_args(st_node, st_arg1, new_st);
+               stnode_free(st_arg2);
+       }
+       else if (type2 == STTYPE_RANGE) {
+               check_drange_sanity(st_arg2);
+               if (!is_bytes_type(ftype1)) {
+                       if (!ftype_can_slice(ftype1)) {
+                               dfilter_fail("Function \"%s\" is a %s and cannot be converted into a sequence of bytes.",
+                                               funcdef->name,
+                                               ftype_pretty_name(ftype1));
+                               THROW(TypeError);
+                       }
+
+                       /* Convert entire field to bytes */
+                       new_st = stnode_new(STTYPE_RANGE, NULL);
+
+                       rn = drange_node_new();
+                       drange_node_set_start_offset(rn, 0);
+                       drange_node_set_to_the_end(rn);
+                       /* st_arg1 is freed in this step */
+                       sttype_range_set1(new_st, st_arg1, rn);
+
+                       sttype_test_set2_args(st_node, new_st, st_arg2);
+               }
+       }
+       else {
+               g_assert_not_reached();
+       }
+}
+
 
 /* Check the semantics of any relational test. */
 static void
@@ -795,12 +958,16 @@ header_field_info   *hfinfo;
                        check_relation_LHS_UNPARSED(relation_string, can_func,
                                        allow_partial_value, st_node, st_arg1, st_arg2);
                        break;
+               case STTYPE_FUNCTION:
+                       check_relation_LHS_FUNCTION(relation_string, can_func,
+                                       allow_partial_value, st_node, st_arg1, st_arg2);
+                       break;
 
                case STTYPE_UNINITIALIZED:
                case STTYPE_TEST:
                case STTYPE_INTEGER:
                case STTYPE_FVALUE:
-               case STTYPE_NUM_TYPES:
+        default:
                        g_assert_not_reached();
        }
 }
diff --git a/epan/dfilter/sttype-function.c b/epan/dfilter/sttype-function.c
new file mode 100644 (file)
index 0000000..c6c8a5a
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * $Id$
+ *
+ * Copyright (c) 2006 by Gilbert Ramirez <gram@alumni.rice.edu>
+ *
+ * Ethereal - Network traffic analyzer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "syntax-tree.h"
+#include "sttype-function.h"
+
+typedef struct {
+       guint32         magic;
+    df_func_def_t *funcdef;
+    GSList *params;
+} function_t;
+
+#define FUNCTION_MAGIC 0xe10f0f99
+
+static gpointer
+function_new(gpointer funcdef)
+{
+       function_t              *stfuncrec;
+
+       g_assert(funcdef != NULL);
+
+       stfuncrec = g_new(function_t, 1);
+
+       stfuncrec->magic = FUNCTION_MAGIC;
+       stfuncrec->funcdef = funcdef;
+       stfuncrec->params = NULL;
+
+       return (gpointer) stfuncrec;
+}
+
+static void
+slist_stnode_free(gpointer data, gpointer user_data _U_)
+{
+    stnode_free(data);
+}
+
+void
+st_funcparams_free(GSList *params)
+{
+    g_slist_foreach(params, slist_stnode_free, NULL);
+    g_slist_free(params);
+}
+
+static void
+function_free(gpointer value)
+{
+       function_t      *stfuncrec = value;
+       assert_magic(stfuncrec, FUNCTION_MAGIC);
+    st_funcparams_free(stfuncrec->params);
+       g_free(stfuncrec);
+}
+
+
+/* Set the parameters for a function stnode_t. */
+void
+sttype_function_set_params(stnode_t *node, GSList *params)
+{
+
+       function_t      *stfuncrec;
+
+       stfuncrec = stnode_data(node);
+       assert_magic(stfuncrec, FUNCTION_MAGIC);
+
+       stfuncrec->params = params;
+}
+
+/* Get the function-definition record for a function stnode_t. */
+df_func_def_t*
+sttype_function_funcdef(stnode_t *node)
+{
+       function_t      *stfuncrec;
+
+       stfuncrec = stnode_data(node);
+       assert_magic(stfuncrec, FUNCTION_MAGIC);
+    return stfuncrec->funcdef;
+}
+
+/* Get the parameters for a function stnode_t. */
+GSList*
+sttype_function_params(stnode_t *node)
+{
+       function_t      *stfuncrec;
+
+       stfuncrec = stnode_data(node);
+       assert_magic(stfuncrec, FUNCTION_MAGIC);
+    return stfuncrec->params;
+}
+
+
+void
+sttype_register_function(void)
+{
+       static sttype_t function_type = {
+               STTYPE_FUNCTION,
+               "FUNCTION",
+               function_new,
+               function_free,
+       };
+
+       sttype_register(&function_type);
+}
+
diff --git a/epan/dfilter/sttype-function.h b/epan/dfilter/sttype-function.h
new file mode 100644 (file)
index 0000000..b93f2e3
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * $Id: sttype-test.h 11400 2004-07-18 00:24:25Z guy $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@zing.org>
+ * Copyright 2001 Gerald Combs
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef STTYPE_FUNCTION_H
+#define STTYPE_FUNCTION_H
+
+#include "dfunctions.h"
+
+/* Set the parameters for a function stnode_t. */
+void
+sttype_function_set_params(stnode_t *node, GSList *params);
+
+/* Get the function-definition record for a function stnode_t. */
+df_func_def_t* sttype_function_funcdef(stnode_t *node);
+
+/* Get the parameters for a function stnode_t. */
+GSList* sttype_function_params(stnode_t *node);
+
+/* Free the memory of a param list */
+void st_funcparams_free(GSList *params);
+
+#endif
index 2fef146adf3fb1db13bbc3ddbbcc0117d7ca3bee..62b54d97fe6331efd878a044576360b56858279b 100644 (file)
@@ -36,6 +36,7 @@ static sttype_t* type_list[STTYPE_NUM_TYPES];
 void
 sttype_init(void)
 {
+       sttype_register_function();
        sttype_register_integer();
        sttype_register_pointer();
        sttype_register_range();
index 5fd5dbbe14966ef6d575ba1380779a51b19a0b3d..d57c850f90928a4af89c7a9100072b1d1551701e 100644 (file)
@@ -35,6 +35,7 @@ typedef enum {
        STTYPE_FVALUE,
        STTYPE_INTEGER,
        STTYPE_RANGE,
+       STTYPE_FUNCTION,
        STTYPE_NUM_TYPES
 } sttype_id_t;
 
@@ -62,6 +63,7 @@ typedef struct {
 } stnode_t;
 
 /* These are the sttype_t registration function prototypes. */
+void sttype_register_function(void);
 void sttype_register_integer(void);
 void sttype_register_pointer(void);
 void sttype_register_range(void);
index 6de261635979a8657619b2e72c50ed26ed964f09..d67883cd53d5318e01eccc4f0b6d747be08fa5f5 100644 (file)
@@ -480,6 +480,7 @@ ftype_register_bytes(void)
 {
 
        static ftype_t bytes_type = {
+               FT_BYTES,                       /* ftype */
                "FT_BYTES",                     /* name */
                "sequence of bytes",            /* pretty_name */
                0,                              /* wire_size */
@@ -515,6 +516,7 @@ ftype_register_bytes(void)
        };
 
        static ftype_t uint_bytes_type = {
+               FT_UINT_BYTES,          /* ftype */
                "FT_UINT_BYTES",                /* name */
                "sequence of bytes",            /* pretty_name */
                0,                              /* wire_size */
@@ -550,6 +552,7 @@ ftype_register_bytes(void)
        };
 
        static ftype_t ether_type = {
+               FT_ETHER,                       /* ftype */
                "FT_ETHER",                     /* name */
                "Ethernet or other MAC address",/* pretty_name */
                ETHER_LEN,                      /* wire_size */
@@ -585,6 +588,7 @@ ftype_register_bytes(void)
        };
 
        static ftype_t ipv6_type = {
+               FT_IPv6,                        /* ftype */
                "FT_IPv6",                      /* name */
                "IPv6 address",                 /* pretty_name */
                IPv6_LEN,                       /* wire_size */
@@ -620,6 +624,7 @@ ftype_register_bytes(void)
        };
 
        static ftype_t oid_type = {
+               FT_OID,                 /* ftype */
                "OID",                  /* name */
                "OBJECT IDENTIFIER",                    /* pretty_name */
                0,                      /* wire_size */
index af45990cdc7560758d7abe0d63aa1551ced41586..460b4c5b13269d2092d76d523184a80d67be9561 100644 (file)
@@ -157,6 +157,7 @@ ftype_register_double(void)
 {
 
        static ftype_t float_type = {
+               FT_FLOAT,                       /* ftype */
                "FT_FLOAT",                     /* name */
                "floating point (single-precision)", /* pretty_name */
                0,                              /* wire_size */
@@ -192,6 +193,7 @@ ftype_register_double(void)
        };
 
        static ftype_t double_type = {
+               FT_DOUBLE,                      /* ftype */
                "FT_DOUBLE",                    /* name */
                "floating point (double-precision)", /* pretty_name */
                0,                              /* wire_size */
index 08104453c8113398b0415d6a9355b82609a5479c..4a5e9645d5064783eb185924291017a0cc6b73b5 100644 (file)
@@ -129,6 +129,7 @@ ftype_register_guid(void)
 {
 
     static ftype_t guid_type = {
+        FT_GUID,              /* ftype */
         "GUID",              /* name */
         "Globally Unique Identifier",            /* pretty_name */
         GUID_LEN,            /* wire_size */
index dc2954bb9f17fbad0c23167a53599f14a94be5e4..9656facbbf2d54a77d1578be82bec367b73a4260 100644 (file)
@@ -444,6 +444,7 @@ ftype_register_integers(void)
 {
 
        static ftype_t uint8_type = {
+               FT_UINT8,                       /* ftype */
                "FT_UINT8",                     /* name */
                "unsigned, 1 byte",             /* pretty name */
                1,                              /* wire_size */
@@ -478,6 +479,7 @@ ftype_register_integers(void)
                NULL,                           /* slice */
        };
        static ftype_t uint16_type = {
+               FT_UINT16,                      /* ftype */
                "FT_UINT16",                    /* name */
                "unsigned, 2 bytes",            /* pretty_name */
                2,                              /* wire_size */
@@ -512,6 +514,7 @@ ftype_register_integers(void)
                NULL,                           /* slice */
        };
        static ftype_t uint24_type = {
+               FT_UINT24,                      /* ftype */
                "FT_UINT24",                    /* name */
                "unsigned, 3 bytes",            /* pretty_name */
                3,                              /* wire_size */
@@ -546,6 +549,7 @@ ftype_register_integers(void)
                NULL,                           /* slice */
        };
        static ftype_t uint32_type = {
+               FT_UINT32,                      /* ftype */
                "FT_UINT32",                    /* name */
                "unsigned, 4 bytes",            /* pretty_name */
                4,                              /* wire_size */
@@ -580,6 +584,7 @@ ftype_register_integers(void)
                NULL,                           /* slice */
        };
        static ftype_t uint64_type = {
+               FT_UINT64,                      /* ftype */
                "FT_UINT64",                    /* name */
                "unsigned, 8 bytes",            /* pretty_name */
                8,                              /* wire_size */
@@ -614,6 +619,7 @@ ftype_register_integers(void)
                NULL,
        };
        static ftype_t int8_type = {
+               FT_INT8,                        /* ftype */
                "FT_INT8",                      /* name */
                "signed, 1 byte",               /* pretty_name */
                1,                              /* wire_size */
@@ -648,6 +654,7 @@ ftype_register_integers(void)
                NULL,                           /* slice */
        };
        static ftype_t int16_type = {
+               FT_INT16,                       /* ftype */
                "FT_INT16",                     /* name */
                "signed, 2 bytes",              /* pretty_name */
                2,                              /* wire_size */
@@ -682,6 +689,7 @@ ftype_register_integers(void)
                NULL,                           /* slice */
        };
        static ftype_t int24_type = {
+               FT_INT24,                       /* ftype */
                "FT_INT24",                     /* name */
                "signed, 3 bytes",              /* pretty_name */
                3,                              /* wire_size */
@@ -716,6 +724,7 @@ ftype_register_integers(void)
                NULL,                           /* slice */
        };
        static ftype_t int32_type = {
+               FT_INT32,                       /* ftype */
                "FT_INT32",                     /* name */
                "signed, 4 bytes",              /* pretty_name */
                4,                              /* wire_size */
@@ -750,6 +759,7 @@ ftype_register_integers(void)
                NULL,                           /* slice */
        };
        static ftype_t int64_type = {
+               FT_INT64,                       /* ftype */
                "FT_INT64",                     /* name */
                "signed, 8 bytes",              /* pretty_name */
                8,                              /* wire_size */
@@ -784,6 +794,7 @@ ftype_register_integers(void)
                NULL,
        };
        static ftype_t boolean_type = {
+               FT_BOOLEAN,                     /* ftype */
                "FT_BOOLEAN",                   /* name */
                "Boolean",                      /* pretty_name */
                0,                              /* wire_size */
@@ -819,6 +830,7 @@ ftype_register_integers(void)
        };
 
        static ftype_t ipxnet_type = {
+               FT_IPXNET,                      /* ftype */
                "FT_IPXNET",                    /* name */
                "IPX network number",           /* pretty_name */
                4,                              /* wire_size */
@@ -854,6 +866,7 @@ ftype_register_integers(void)
        };
 
        static ftype_t framenum_type = {
+               FT_FRAMENUM,                    /* ftype */
                "FT_FRAMENUM",                  /* name */
                "frame number",                 /* pretty_name */
                4,                              /* wire_size */
index 65b8961dc80ea24440fa9a7d50c32f93fd7e5085..d57894325c62e5c2d2d24a3225ac15bfaee9917a 100644 (file)
@@ -199,6 +199,7 @@ ftype_register_ipv4(void)
 {
 
        static ftype_t ipv4_type = {
+               FT_IPv4,                        /* ftype */
                "FT_IPv4",                      /* name */
                "IPv4 address",                 /* pretty_name */
                4,                              /* wire_size */
index 4eb037eed9a2542ff546de23203c96bee70d1ecd..471e0a4d2385f8ca81ce7c595bbdc2192399b7b7 100644 (file)
@@ -32,6 +32,7 @@ ftype_register_none(void)
 {
 
        static ftype_t none_type = {
+               FT_NONE,                        /* ftype */
                "FT_NONE",                      /* name */
                "label",                        /* pretty_name */
                0,                              /* wire_size */
index 05db17e28a0db48f0bf2de731274638f8c3c222e..82bcc196de254e65d6cb72695327a3c8858875be 100644 (file)
@@ -177,6 +177,7 @@ void
 ftype_register_pcre(void)
 {
        static ftype_t pcre_type = {
+               FT_PCRE,                /* ftype */
                "FT_PCRE",              /* name */
                "Compiled Perl-Compatible Regular Expression object", /* pretty_name */
                0,                      /* wire_size */
@@ -219,6 +220,7 @@ void
 ftype_register_pcre(void)
 {
        static ftype_t pcre_type = {
+               FT_PCRE,                /* ftype */
                "FT_PCRE",                      /* name */
                "Compiled Perl-Compatible Regular Expression object", /* pretty_name */
                0,                              /* wire_size */
index 70649b77b8e89989ec780a26337b5abf8eb9a14c..d4525fc27951d8c05ff35a4c2d5d59d8de25b9ed 100644 (file)
@@ -301,6 +301,7 @@ ftype_register_string(void)
 {
 
        static ftype_t string_type = {
+               FT_STRING,                      /* ftype */
                "FT_STRING",                    /* name */
                "character string",             /* pretty_name */
                0,                              /* wire_size */
@@ -335,6 +336,7 @@ ftype_register_string(void)
                slice,
        };
        static ftype_t stringz_type = {
+               FT_STRINGZ,                     /* ftype */
                "FT_STRINGZ",                   /* name */
                "character string",             /* pretty name */
                0,                              /* wire_size */
@@ -369,6 +371,7 @@ ftype_register_string(void)
                slice,
        };
        static ftype_t uint_string_type = {
+               FT_UINT_STRING,         /* ftype */
                "FT_UINT_STRING",               /* name */
                "character string",             /* pretty_name */
                0,                              /* wire_size */
index ed90960952652398b0aba0a9614efef3c6d48667..2427ccb5d5baa01b073b0dce349da4e6b4c2ae9f 100644 (file)
@@ -345,6 +345,7 @@ ftype_register_time(void)
 {
 
        static ftype_t abstime_type = {
+               FT_ABSOLUTE_TIME,               /* ftype */
                "FT_ABSOLUTE_TIME",             /* name */
                "date/time",                    /* pretty_name */
                0,                              /* wire_size */
@@ -379,6 +380,7 @@ ftype_register_time(void)
                NULL
        };
        static ftype_t reltime_type = {
+               FT_RELATIVE_TIME,               /* ftype */
                "FT_RELATIVE_TIME",             /* name */
                "time offset",                  /* pretty_name */
                0,                              /* wire_size */
index f4c84b5d6589af9442418daa8f4a8b4fbf911a97..8e4a7050597cc690aa19c1d9023091b0b775f510 100644 (file)
@@ -260,6 +260,7 @@ ftype_register_tvbuff(void)
 {
 
        static ftype_t protocol_type = {
+               FT_PROTOCOL,                    /* ftype */
                "FT_PROTOCOL",                  /* name */
                "protocol",                     /* pretty_name */
                0,                              /* wire_size */
index e40dfc4f0603c15e19f3fbf73b3efb1ebd42dee9..d48389496b8a0b87b4db8806eb96e873131b25be 100644 (file)
@@ -58,6 +58,7 @@ ftype_register(enum ftenum ftype, ftype_t *ft)
 {
        /* Check input */
        g_assert(ftype < FT_NUM_TYPES);
+    g_assert(ftype == ft->ftype);
 
        /* Don't re-register. */
        g_assert(type_list[ftype] == NULL);
@@ -268,6 +269,12 @@ fvalue_from_string(ftenum_t ftype, char *s, LogFunc logfunc)
        return NULL;
 }
 
+ftype_t*
+fvalue_ftype(fvalue_t *fv)
+{
+    return fv->ftype;
+}
+
 const char*
 fvalue_type_name(fvalue_t *fv)
 {
index 6a30a4b7b5a54aec082d22aeb0fd272759792aa9..a21feb52917d491616d3b2ff7df97ba6dcaacf9e 100644 (file)
@@ -196,6 +196,7 @@ typedef guint (*FvalueLen)(fvalue_t*);
 typedef void (*FvalueSlice)(fvalue_t*, GByteArray *, guint offset, guint length);
 
 struct _ftype_t {
+    ftenum_t        ftype;
        const char              *name;
        const char              *pretty_name;
        int                     wire_size;
@@ -288,6 +289,9 @@ fvalue_string_repr_len(fvalue_t *fv, ftrepr_t rtype);
 extern char *
 fvalue_to_string_repr(fvalue_t *fv, ftrepr_t rtype, char *buf);
 
+ftype_t*
+fvalue_ftype(fvalue_t *fv);
+
 const char*
 fvalue_type_name(fvalue_t *fv);
 
index 9dcae85dbc2b4b7fb5fdefd372b8cbd7eaa26761..f77319e3f284616ea7360690a45556f7bc9e81ec 100755 (executable)
@@ -1015,6 +1015,38 @@ class String(Test):
                return self.DFilterCount(pkt_http,
        'http.request.method contains 48:45:41:44"', 1) # "HEAD"
 
+       def ck_contains_fail_0(self):
+               return self.DFilterCount(pkt_http,
+                       'http.user_agent contains "update"', 0)
+
+       def ck_contains_fail_1(self):
+               return self.DFilterCount(pkt_http,
+                       'http.user_agent contains "UPDATE"', 0)
+
+       def ck_contains_upper_0(self):
+               return self.DFilterCount(pkt_http,
+                       'upper(http.user_agent) contains "UPDATE"', 1)
+
+       def ck_contains_upper_1(self):
+               return self.DFilterCount(pkt_http,
+                       'upper(http.user_agent) contains "update"', 0)
+
+       def ck_contains_upper_2(self):
+               return self.DFilterCount(pkt_http,
+                       'upper(tcp.seq) == 4', None)
+
+       def ck_contains_lower_0(self):
+               return self.DFilterCount(pkt_http,
+                       'lower(http.user_agent) contains "UPDATE"', 0)
+
+       def ck_contains_lower_1(self):
+               return self.DFilterCount(pkt_http,
+                       'lower(http.user_agent) contains "update"', 1)
+
+       def ck_contains_lower_2(self):
+               return self.DFilterCount(pkt_http,
+                       'lower(tcp.seq) == 4', None)
+
 
        tests = [
                ck_eq_1,
@@ -1047,6 +1079,14 @@ class String(Test):
                ck_contains_3,
                ck_contains_4,
                ck_contains_5,
+               ck_contains_fail_0,
+               ck_contains_fail_1,
+               ck_contains_upper_0,
+               ck_contains_upper_1,
+               ck_contains_upper_2,
+               ck_contains_lower_0,
+               ck_contains_lower_1,
+               ck_contains_lower_2,
                ]