/*
** Copyright (C) 2008-2010 by Carnegie Mellon University.
**
** @OPENSOURCE_HEADER_START@
**
** Use of the SILK system and related source code is subject to the terms
** of the following licenses:
**
** GNU Public License (GPL) Rights pursuant to Version 2, June 1991
** Government Purpose License Rights (GPLR) pursuant to DFARS 252.227.7013
**
** NO WARRANTY
**
** ANY INFORMATION, MATERIALS, SERVICES, INTELLECTUAL PROPERTY OR OTHER
** PROPERTY OR RIGHTS GRANTED OR PROVIDED BY CARNEGIE MELLON UNIVERSITY
** PURSUANT TO THIS LICENSE (HEREINAFTER THE "DELIVERABLES") ARE ON AN
** "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY
** KIND, EITHER EXPRESS OR IMPLIED AS TO ANY MATTER INCLUDING, BUT NOT
** LIMITED TO, WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE,
** MERCHANTABILITY, INFORMATIONAL CONTENT, NONINFRINGEMENT, OR ERROR-FREE
** OPERATION. CARNEGIE MELLON UNIVERSITY SHALL NOT BE LIABLE FOR INDIRECT,
** SPECIAL OR CONSEQUENTIAL DAMAGES, SUCH AS LOSS OF PROFITS OR INABILITY
** TO USE SAID INTELLECTUAL PROPERTY, UNDER THIS LICENSE, REGARDLESS OF
** WHETHER SUCH PARTY WAS AWARE OF THE POSSIBILITY OF SUCH DAMAGES.
** LICENSEE AGREES THAT IT WILL NOT MAKE ANY WARRANTY ON BEHALF OF
** CARNEGIE MELLON UNIVERSITY, EXPRESS OR IMPLIED, TO ANY PERSON
** CONCERNING THE APPLICATION OF OR THE RESULTS TO BE OBTAINED WITH THE
** DELIVERABLES UNDER THIS LICENSE.
**
** Licensee hereby agrees to defend, indemnify, and hold harmless Carnegie
** Mellon University, its trustees, officers, employees, and agents from
** all claims or demands made against them (and any related losses,
** expenses, or attorney's fees) arising out of, or relating to Licensee's
** and/or its sub licensees' negligent use or willful misuse of or
** negligent conduct or willful misconduct regarding the Software,
** facilities, or other rights or assistance granted by Carnegie Mellon
** University under this License, including, but not limited to, any
** claims of product liability, personal injury, death, damage to
** property, or violation of any laws or regulations.
**
** Carnegie Mellon University Software Engineering Institute authored
** documents are sponsored by the U.S. Department of Defense under
** Contract F19628-00-C-0003. Carnegie Mellon University retains
** copyrights in all material produced under this contract. The U.S.
** Government retains a non-exclusive, royalty-free license to publish or
** reproduce these documents, or allow others to do so, for U.S.
** Government purposes only pursuant to the copyright license under the
** contract clause at 252.227.7013.
**
** @OPENSOURCE_HEADER_END@
*/
#ifndef _SKPLUGIN_H
#define _SKPLUGIN_H

#include <silk/silk.h>

RCSIDENTVAR(rcsID_SKPLUGIN_H, "$SiLK: skplugin.h 15289 2010-02-11 21:09:29Z mwd $");

/*
**  skplugin.h
**
**
**
*/

#include <silk/skdllist.h>
#include <silk/rwrec.h>
#include <silk/skstream.h>
#include <silk/utils.h>

/*
 *  SK_PLUGIN_ADD_SUFFIX(name)
 *
 *    Adds the appropriate suffix to 'name' to get the file name that
 *    skplugin should attempt to dlopen().  'name' should be a string;
 *    we rely on CPP concatenation to add the suffix.
 */
#define SK_PLUGIN_ADD_SUFFIX(file_basename) (file_basename SILK_PLUGIN_SUFFIX)


/* Return value from most skplugin functions */
typedef enum {
    /* all is well */
    SKPLUGIN_OK,

    /* result passes filter */
    SKPLUGIN_FILTER_PASS,

    /* result passes filter immediately. Do not check any more plugin
     * filter or transform functions */
    SKPLUGIN_FILTER_PASS_NOW,

    /* result fails filter */
    SKPLUGIN_FILTER_FAIL,

    /* result is marked as neither pass nor fail.  Do not check any
     * more plugin filter or transform functions */
    SKPLUGIN_FILTER_IGNORE,

    /* all is not well */
    SKPLUGIN_ERR,

    /* serious corruption possible, abort now */
    SKPLUGIN_ERR_FATAL,

    /* plugin could not be loaded due to system errors */
    SKPLUGIN_ERR_SYSTEM,

    /* plugin did not register options because app did not support the
     * function mask  */
    SKPLUGIN_ERR_DID_NOT_REGISTER,

    /* version of library is too new for plugin */
    SKPLUGIN_ERR_VERSION_TOO_NEW

} skplugin_err_t;


/* Types of command-line switches (NO_ARG, REQUIRED_ARG, OPTIONAL_ARG,
 * from utils.h */
typedef int skplugin_arg_mode_t;


/* The plugin callback function bitfields */
typedef int skplugin_fn_mask_t;

#define SKPLUGIN_FN_ANY             (0)
#define SKPLUGIN_FN_REC_TO_BIN      (1)
#define SKPLUGIN_FN_ADD_REC_TO_BIN  (1 << 1)
#define SKPLUGIN_FN_BIN_TO_TEXT     (1 << 2)
#define SKPLUGIN_FN_REC_TO_TEXT     (1 << 3)
#define SKPLUGIN_FN_MERGE           (1 << 4)
#define SKPLUGIN_FN_COMPARE         (1 << 5)
#define SKPLUGIN_FN_INITIAL         (1 << 6)
#define SKPLUGIN_FN_FILTER          (1 << 7)
#define SKPLUGIN_FN_TRANSFORM       (1 << 8)

/* Plugin required fields for particular apps */
#define SKPLUGIN_APP_CUT            SKPLUGIN_FN_REC_TO_TEXT
#define SKPLUGIN_APP_SORT           SKPLUGIN_FN_REC_TO_BIN
#define SKPLUGIN_APP_GROUP          SKPLUGIN_FN_REC_TO_BIN
#define SKPLUGIN_APP_UNIQ_FIELD     (SKPLUGIN_FN_REC_TO_BIN     \
                                     | SKPLUGIN_FN_BIN_TO_TEXT)
#define SKPLUGIN_APP_UNIQ_VALUE     (SKPLUGIN_FN_ADD_REC_TO_BIN \
                                     | SKPLUGIN_FN_BIN_TO_TEXT  \
                                     | SKPLUGIN_FN_MERGE)
#define SKPLUGIN_APP_STATS_FIELD    (SKPLUGIN_FN_REC_TO_BIN     \
                                     | SKPLUGIN_FN_BIN_TO_TEXT)
#define SKPLUGIN_APP_STATS_VALUE    (SKPLUGIN_FN_ADD_REC_TO_BIN \
                                     | SKPLUGIN_FN_BIN_TO_TEXT  \
                                     | SKPLUGIN_FN_MERGE        \
                                     | SKPLUGIN_FN_COMPARE)
#define SKPLUGIN_APP_FILTER         SKPLUGIN_FN_FILTER
#define SKPLUGIN_APP_TRANSFORM      SKPLUGIN_FN_TRANSFORM


/* Version check result type */
typedef enum {
    SKPLUGIN_VERSION_OK,
    SKPLUGIN_VERSION_OLD,
    SKPLUGIN_VERSION_TOO_NEW
} skplugin_version_result_t;

/* filter identifier */
struct skp_filter_st;
typedef struct skp_filter_st skplugin_filter_t;

/* transformer identifier */
struct skp_transform_st;
typedef struct skp_transform_st skplugin_transform_t;

/* field identifier */
struct skp_field_st;
typedef struct skp_field_st skplugin_field_t;

/* field iterator */
typedef struct skplugin_field_iter_st {
    sk_dll_iter_t      list_iter;
    skplugin_fn_mask_t fn_mask;
    unsigned           all_fields : 1;
} skplugin_field_iter_t;


/*  Type signature of the function that skpinOpenDataInputStream()
 *  will call. */
typedef int (*open_data_input_fn_t)(
    skstream_t        **stream,
    skcontent_t         content_type,
    const char         *filename);





/*******************************/
/*** Plugin entry point type ***/
/*******************************/

/* The "entry point" of the plugin is the single function the plugin
 * exports, and which is found by dlsym(3).  All other functions and
 * global variables in the plugin should be static, unless the plugin
 * consists of more than one file. */

/* The name of the setup function that plugins export */
#define SKPLUGIN_SETUP_FN skplugin_init
#define TO_STR(a) _TO_STR(a)
#define _TO_STR(a) #a
#define SKPLUGIN_SETUP_FN_NAME TO_STR(SKPLUGIN_SETUP_FN)

/* The current version of the skplugin interface */
#define SKPLUGIN_INTERFACE_VERSION_MAJOR 1
#define SKPLUGIN_INTERFACE_VERSION_MINOR 0

/* Name of envar that if set will enable debugging output */
#define SKPLUGIN_DEBUG_ENVAR "SILK_PLUGIN_DEBUG"

/* Version number check  */
#define SKPLUGIN_VERSION_CHECK(protocol_major, protocol_minor,          \
                               plugin_major, plugin_minor)              \
    ((plugin_major < protocol_major) ? SKPLUGIN_VERSION_TOO_NEW :       \
     ((plugin_major > protocol_major) ? SKPLUGIN_VERSION_OLD :          \
      ((plugin_minor > protocol_minor) ? SKPLUGIN_VERSION_OLD :         \
       SKPLUGIN_VERSION_OK)))


/*
 *    Function prototype for the setup function that plugins export.
 *    'data' is an opaque type determined by the value 'version'.  In
 *    the current version (1.0), the 'data' is not used, and NULL will
 *    be passed as the 'data' argument.
 */
skplugin_err_t SKPLUGIN_SETUP_FN(
    uint16_t  major_version,
    uint16_t  minor_version,
    void     *data);


/*** SIMPLE FIELD REGISTRATION FUNCTIONS ***/

/*****************************************************************/
/*** Callback function types for simple registration functions ***/
/*****************************************************************/

/*
 *    Integer-based field callback.  Given an rwRec, should return an
 *    unsigned integer to associate with that record.  Used in
 *    skpinRegIntField, skpinRegTextField, skpinRegStringListField,
 *    skpinRegIntAggregator, skpinRegIntSumAggregator,
 *    skpinRegIntMinAggregator, and skpinRegIntMaxAggregator.
 */
typedef uint64_t (*skplugin_int_field_fn_t)(
    const rwRec *rec);

/*
 *    IPv4 address field callback.  Given an rwRec, should return an
 *    IPv4 address as a uint32_t (in host byte order) to associate
 *    with that record.  Used in skpinRegIPv4Field.
 */
typedef uint32_t (*skplugin_ipv4_field_fn_t)(
    const rwRec *rec);

/*
 *    IP address field callback.  Given an rwRec, should fill in the
 *    given skipaddr_t with an IP address to associate with that
 *    record.  Used in skpinRegIPAddressField.
 */
typedef void (*skplugin_ip_field_fn_t)(
    skipaddr_t  *dest,
    const rwRec *rec);

/*
 *    Text field callback.  Converts a uint64_t value to a text value
 *    in 'dest'.  The size of the 'dest' buffer is given by 'width'.
 *    The text value must be null-terminated.  Used in
 *    skpinRegTextField.
 */
typedef void (*skplugin_text_field_fn_t)(
    char     *dest,
    size_t    width,
    uint64_t  val);

/*
 *    Integer aggregation function callback.  Given a 'current' value,
 *    "adds" or "merges" the 'operand', and returns the new value.
 *    Used in skpinRegIntAggregator.
 */
typedef uint64_t (*skplugin_agg_fn_t)(
    uint64_t current,
    uint64_t operand);


/*******************************************/
/*** Simple field registration functions ***/
/*******************************************/

/*
 *   Registers a field whose value is an integer.
 *
 *   The field's name (and title) will be 'name'.  'min' is the
 *   minimum integer value for the field.  'max' is the maximum value
 *   of the field.  If 'max' is set to 0, 'max' is defaulted to
 *   UINT64_MAX.  'fn' is a function that takes an rwRec, and returns
 *   the integer associated with it.  'width' is the column width of
 *   the field.  If 'width' is set to 0, 'width' is defaulted to the
 *   textual width of 'max'.
 */
skplugin_err_t skpinRegIntField(
    const char              *name,
    uint64_t                 min,
    uint64_t                 max,
    skplugin_int_field_fn_t  fn,
    size_t                   width);

/*
 *   Registers a field whose value is an IPv4 address.
 *
 *   The field's name (and title) will be 'name'.  'fn' is a function
 *   that takes an rwRec, and returns the IPv4 address associated with
 *   it as a uint32_t in host byte order.  'width' is the column width
 *   of the field.  If 'width' is set to 0, 'width' is defaulted to
 *   15.
 */
skplugin_err_t skpinRegIPv4Field(
    const char               *name,
    skplugin_ipv4_field_fn_t  fn,
    size_t                    width);

/*
 *   Registers a field whose value is an IP address.
 *
 *   The field's name (and title) will be 'name'.  'fn' is a function
 *   that takes an rwRec, and fills in an IP address associated with
 *   it as a skipaddr_t.  'width' is the column width of the field.
 *   If 'width' is set to 0, 'width' is defaulted to 39 (15 if not
 *   SiLK is not compiled with IPv6 support.
 */
skplugin_err_t skpinRegIPAddressField(
    const char             *name,
    skplugin_ip_field_fn_t  fn,
    size_t                  width);

/*
 *   Registers a field whose value is text.
 *
 *   The field's name (and title) will be 'name'.  The field's text
 *   value is based on an intermediate integer value.  'min' is the
 *   minimum integer value for the field.  'max' is the maximum value
 *   of the field.  If 'max' is set to 0, 'max' is defaulted to
 *   UINT64_MAX.  'value_fn' is a function that takes an rwRec, and
 *   returns the integer associated with it.  'text_fn' is a function
 *   that takes a buffer, width, and integer, and fills the buffer
 *   with the text value associated with that integer, where the width
 *   is the size of the buffer.  'width' is the column width of the
 *   field.
 */
skplugin_err_t skpinRegTextField(
    const char               *name,
    uint64_t                  min,
    uint64_t                  max,
    skplugin_int_field_fn_t   value_fn,
    skplugin_text_field_fn_t  text_fn,
    size_t                    width);

/*
 *   Registers a field whose value is one of a list of strings.
 *
 *   The field's name (and title) will be 'name'.  'list' is a static
 *   list of strings.  The list should either be NULL-terminated, or
 *   'entries' should have a non-zero value.  'entries' should be the
 *   number of entries in the list.  If 'entries' is zero, the list is
 *   assumed to be NULL-terminated.  'fn' is a function that takes an
 *   rwRec, and returns an index into 'list'.  If the index value is
 *   greater than the number of entries in 'list', 'default_value'
 *   will be used instead.  'default_value' may be NULL.  'width' is
 *   the column width of the field.  If 'width' is set to 0, 'width'
 *   is defaulted to the width of the largest string in 'list' and
 *   'default_value'.
 */
skplugin_err_t skpinRegStringListField(
    const char               *name,
    const char              **list,
    size_t                    entries,
    const char               *default_value,
    skplugin_int_field_fn_t   fn,
    size_t                    width);

/*
 *   Registers an aggregate value field that maintains a running
 *   unsigned integer sum.
 *
 *   The field's name (and title) will be 'name'.  The maximum value
 *   of the field is 'max'.  If 'max' is zero, the maximum value is
 *   assumed to be UINT64_MAX.  'fn' is a function that takes an
 *   rwRec, and returns an integer value associated with that record.
 *   'width' is the column width of the field.  If 'width' is set to
 *   0, 'width' is defaulted to the textual width of 'max'.
 */
skplugin_err_t skpinRegIntSumAggregator(
    const char              *name,
    uint64_t                 max,
    skplugin_int_field_fn_t  fn,
    size_t                   width);

/*
 *   Registers an aggregate value field that keeps track of a minimum
 *   unsigned integer value.
 *
 *   The field's name (and title) will be 'name'.  The maximum value
 *   of the field is 'max'.  If 'max' is zero, the maximum value is
 *   assumed to be UINT64_MAX.  'fn' is a function that takes an
 *   rwRec, and returns an integer value associated with that record.
 *   'width' is the column width of the field.  If 'width' is set to
 *   0, 'width' is defaulted to the textual width of 'max'.
 */
skplugin_err_t skpinRegIntMinAggregator(
    const char              *name,
    uint64_t                 max,
    skplugin_int_field_fn_t  fn,
    size_t                   width);

/*
 *   Registers an aggregate value field that keeps track of a maximum
 *   unsigned integer value.
 *
 *   The field's name (and title) will be 'name'.  The maximum value
 *   of the field is 'max'.  If 'max' is zero, the maximum value is
 *   assumed to be UINT64_MAX.  'fn' is a function that takes an
 *   rwRec, and returns an integer value associated with that record.
 *   'width' is the column width of the field.  If 'width' is set to
 *   0, 'width' is defaulted to the textual width of 'max'.
 */
skplugin_err_t skpinRegIntMaxAggregator(
    const char              *name,
    uint64_t                 max,
    skplugin_int_field_fn_t  fn,
    size_t                   width);

/*
 *   Registers an unsigned integer aggregate value field.
 *
 *   The field's name (and title) will be 'name'.  The maximum value
 *   of the field is 'max'.  If 'max' is zero, the maximum value is
 *   assumed to be UINT64_MAX.  'fn' is a function that takes an
 *   rwRec, and returns an integer value associated with that record.
 *   'agg' is the aggregation function, which takes the current value
 *   of the field and a value returned by 'fn', and returns the new
 *   value of the field.  'initial' should be the initial value of the
 *   field.  'width' is the column width of the field.  If 'width' is
 *   set to 0, 'width' is defaulted to the textual width of 'max'.
 */
skplugin_err_t skpinRegIntAggregator(
    const char              *name,
    uint64_t                 max,
    skplugin_int_field_fn_t  fn,
    skplugin_agg_fn_t        agg,
    uint64_t                 initial,
    size_t                   width);


/*** LOW LEVEL PLUGIN FUNCTIONALITY ***/

/*
 *  EXTRA ARGUMENTS
 *
 *    Extra arguments are sets of extra information that can be passed
 *    to plugin functions on a per-SiLK Flow record (rwrec) basis.
 *    Extra arguments are named, and it is the responsibility of the
 *    application and plugin writers to agree on what type of data
 *    each name is associated with.
 *
 *    Extra arguments are meant to be used when a plugin can make use
 *    of extra information associated with an rwrec that is not in the
 *    rwrec itself.  Some plugins may actually require certain extra
 *    arguments in order to work.  An example: rwptoflow supports a
 *    transform function that requires the original packet data as
 *    context.
 *
 *    Extra arguments are meant to be used as follows:
 *
 *    a) The application registers the set of extra data it can supply
 *       with each record using skPluginSetAppExtraArgs().
 *
 *    b) The plugins get information about what extra arguments are
 *       available using skpinGetAppExtraArgs().
 *
 *    c) The plugins register their callback functions with the
 *       standard registration functions or the WithExtraArgsArray
 *       version of the registration functions.  Only extra arguments
 *       returned by skpinGetAppExtraArgs() may be used.
 *
 *       The normal registration functions take a list of characters
 *       pointers in the var-args style.  The final element of the
 *       list must be NULL.  This is similar to how ARGV is specified
 *       in execl(3).  If no extra arguments are to be used, pass a
 *       single NULL as the last argument.
 *
 *       The WithExtraArgsArray version takes an array of character
 *       pointers.  The final element in this array must be NULL.
 *       This is similar to how ARGV is specified in execv(3).
 *
 *    d) After plugins have been loaded, the application finds out
 *       what extra arguments are being requested by the plugins via
 *       skPluginGetPluginExtraArgs().
 *
 *    e) The application then registers what extra arguments it will
 *       send, and in what order, using the
 *       skPluginSetUsedAppExtraArgs() function.  This set must
 *       include the extra arguments returned by
 *       skPluginGetPluginExtraArgs().
 *
 *    f) The application will hand the extra arguments to calls of
 *       skPluginRunFilterFn() in the order registered.  (Can send
 *       NULL if no extra arguments registered).  The plugins will
 *       receive the extra arguments they asked for in the order
 *       requested by the application.  The application and its
 *       plugins can reduce the overhead in the skPlugin layer by
 *       specifying the same set of extra arguments in the same order.
 */


/*******************************************/
/*** Callback function types for plugins ***/
/*******************************************/

/*
 * In all the following function prototypes, 'cbdata' is callback data
 * provided by the plugin at callback registration time.  'extra' are
 * extra arguments as defined in Extra Arguments above.
 */

/*
 *    Type defininition for non-function-specific plugin cleanup
 *    functions.
 */
typedef void (*skplugin_cleanup_fn_t)(void);

/*
 *    Basic callback: used for startup/shutdown type code.
 */
typedef skplugin_err_t (*skplugin_callback_fn_t)(
    void *cbdata);

/*
 *    Argument processing callback: called to process a plugin
 *    command-line argument (switch).  Registered by skpinRegOption().
 *
 *    In cases where the plugin is only active when a command line
 *    argument is present, part of this function's duties will be to
 *    call skpinRegFilter() or skpinRegTransformer().
 */
typedef skplugin_err_t (*skplugin_option_fn_t)(
    const char *opt_arg,
    void       *cbdata);


/*
 *    Option help callback.  Meant to output option help to the given
 *    file handle.  Registered by skpinRegOptionWithHelpFn().  Called
 *    by skPluginOptionsUsage().
 */
typedef void (*skplugin_help_fn_t)(
    FILE                *fh,
    const struct option *option,
    void                *cbdata);

/*
 *    Filter callback to filter a record 'rec'.  If the function
 *    returns SKPLUGIN_FILTER_PASS, the record is accepted.  If it
 *    returns SKPLUGIN_FILTER_FAIL, it is rejected.  Resistered by
 *    skpinRegFilter().
 */
typedef skplugin_err_t (*skplugin_filter_fn_t)(
    const rwRec  *rec,
    void         *cbdata,
    void        **extra);

/*
 *    Transform callback.  Modifies 'rec' in place.  Registered by
 *    skpinRegTransformer().
 */
typedef skplugin_err_t (*skplugin_transform_fn_t)(
    rwRec  *rec,
    void   *cbdata,
    void  **extra);

/*
 *    Record to text callback.  Fills in 'dest' given 'rec'.  The
 *    function should write no more than 'width' characters into
 *    'dest'.  The value should be NUL-terminated.  Registered by
 *    skpinRegField().
 */
typedef skplugin_err_t (*skplugin_text_fn_t)(
    const rwRec  *rec,
    char         *dest,
    size_t        width,
    void         *cbdata,
    void        **extra);

/*
 *    Record to binary callback.  Fills in 'dest' given 'rec'.
 *    Registered by skpinRegField().  When used in an aggregate
 *    definition, 'dest' is presumed to contain the current binary
 *    value, which should be modified or replaced by the function.
 *    The function may assume that the 'dest' is large enough to hold
 *    'field_bin_width' bytes.
 */
typedef skplugin_err_t (*skplugin_bin_fn_t)(
    const rwRec  *rec,
    uint8_t      *dest,
    void         *cbdata,
    void        **extra);

/*
 *    Binary to text callback.  Just like record to text callback, but
 *    converts data from a binary value (as produced by a
 *    skplugin_bin_fn_t) to text.
 */
typedef skplugin_err_t (*skplugin_bin_to_text_fn_t)(
    const uint8_t *bin,
    char          *dest,
    size_t         width,
    void          *cbdata);

/*
 *    Binary value merge callback.  This function takes two binary
 *    values (as produced by a skplugin_bin_fn_t) in dest and src and
 *    merges them into dest.
 */
typedef skplugin_err_t (*skplugin_bin_merge_fn_t)(
    uint8_t        *dest,
    const uint8_t  *src,
    void           *cbdata);

/*
 *    Binary value comparison function.  Compares two binary values
 *    (as produced by a skplugin_bin_fn_t) in value_a and value_b and
 *    places a integer less than, equal to, or greater than zero in
 *    cmp depending on whether value_a is less than, equal, or greater
 *    than value_b.
 */
typedef skplugin_err_t (*skplugin_bin_cmp_fn_t)(
    int            *cmp,
    const uint8_t  *value_a,
    const uint8_t  *value_b,
    void           *cbdata);

/******************************************/
/*** Struct for registration functions  ***/
/******************************************/

/* Used as an argument to the skpinRegField() function.  It's members
 * are described in detail in the description of that function. */
typedef struct skplugin_callbacks_st {
    skplugin_callback_fn_t     init;
    skplugin_callback_fn_t     cleanup;
    size_t                     column_width;
    size_t                     bin_bytes;
    skplugin_text_fn_t         rec_to_text;
    skplugin_bin_fn_t          rec_to_bin;
    skplugin_bin_fn_t          add_rec_to_bin;
    skplugin_bin_to_text_fn_t  bin_to_text;
    skplugin_bin_merge_fn_t    bin_merge;
    skplugin_bin_cmp_fn_t      bin_compare;
    skplugin_filter_fn_t       filter;
    skplugin_transform_fn_t    transform;
    const uint8_t             *initial;
    const char               **extra;
} skplugin_callbacks_t;


/************************/
/*** Plugin functions ***/
/************************/

/* This set of functions are meant to be called by the plugins
 * themselves. */

/*
 *     Compares the version number of the plugin api supported by the
 *     plugin with the version reported by the application.  If
 *     sk_msg_fn_t is non-null, will print version mismatches via the
 *     error function.  Returns SKPLUGIN_OK if the versions "match",
 *     or a value that can be returned from the setup function (either
 *     SKPLUGIN_ERR or SKPLUGIN_ERR_VERSION_TOO_NEW).
 */
skplugin_err_t skpinSimpleCheckVersion(
    uint16_t protocol_major,
    uint16_t protocol_minor,
    uint16_t plugin_major,
    uint16_t plugin_minor,
    sk_msg_fn_t errfn);

/*
 *    Gets the applications list of extra arguments as a
 *    NULL-terminated list of strings.
 */
const char **skpinGetAppExtraArgs(void);

/*
 *      Create an skstream_t object using the specified 'content_type'
 *      and 'filename', open it, and fill the location pointed to by
 *      'stream' with the object.  If the application has called
 *      skPluginSetOpenInputFunction(), that function will be used if
 *      it is non-null.
 *  Inputs:
 *      location in which to return address of skstream_t object
 *      content_type of the filename
 *      name of file to open
 *  Outputs:
 *      Returns 0 if stream was successfully opened and should be
 *      used.  Returns -1 on error.  Returns 1 if the plug-in should
 *      ignore the file.
 *  Side Effects:
 *      'stream' is filled with address of skstream_t object.
 */
int skpinOpenDataInputStream(
    skstream_t        **stream,
    skcontent_t         content_type,
    const char         *filename);

/*
 *    Register an option (switch) for command-line processing with a
 *    simple help string.
 *
 *    'fn_mask' is the function type combination for which this option
 *    should be used.
 *
 *    'option_name' is the command line switch to create.
 *
 *    'mode' determines whether the switch takes an argument.  It
 *    should be one of NO_ARG, OPTIONAL_ARG, or REQUIRED_ARG.
 *
 *    'option_help' is the usage string to print when the user
 *    requests --help.
 *
 *    'opt' is a callback function.  'opt(opt_arg, cbdata)' will be
 *    called back when the 'option_name' is seen as an option.  If no
 *    argument is given to the switch, 'opt_arg' will be NULL.
 *
 *    'cbdata' will be passed back unchanged to the plugin as a
 *    parameter in the 'opt' callback function.
 *
 *    If the application does not support the combination in
 *    'fn_mask', this function will return
 *    SKPLUGIN_ERR_DID_NOT_REGISTER.
 */
skplugin_err_t skpinRegOption(
    skplugin_fn_mask_t    fn_mask,
    const char           *option_name,
    skplugin_arg_mode_t   mode,
    const char           *option_help,
    skplugin_option_fn_t  opt,
    void                 *cbdata);


/*
 *    Register an option (switch) for command-line processing with an
 *    associated help function.
 *
 *    'fn_mask' are the function types for which this option
 *    should be used.
 *
 *    'option_name' is the command line switch to create.
 *
 *    'mode' determines whether the switch takes an argument.  It
 *    should be one of NO_ARG, OPTIONAL_ARG, or REQUIRED_ARG.
 *
 *    'option_help' is a function which optionally prints a help
 *    message for the option.
 *
 *    'opt' is a callback function.  'opt(opt_arg, cbdata)' will be
 *    called back when the 'option_name' is seen as an option.  If no
 *    argument is given to the switch, 'opt_arg' will be NULL.
 *
 *    'cbdata' will be passed back unchanged to the plugin as a
 *    parameter in the 'opt' callback function.
 *
 *    If the application does not support the combination in
 *    'fn_mask', this function will return
 *    SKPLUGIN_ERR_DID_NOT_REGISTER.
 */
skplugin_err_t skpinRegOptionWithHelpFn(
    skplugin_fn_mask_t    fn_mask,
    const char           *option_name,
    skplugin_arg_mode_t   mode,
    skplugin_help_fn_t    option_help,
    skplugin_option_fn_t  opt,
    void                 *cbdata);


/*
 *    Register a new filter predicate to pass or fail records.
 *    Registering a filter in an application that doesn't filter is a
 *    no-op.
 *
 *    'filter' is a handle to the newly created filter.  (Can be
 *    NULL.)
 *
 *    'init' is a callback function.  'init(cbdata)' is called for all
 *    registered filter predicates.  It is called after argument
 *    processing and before processing of records.
 *
 *    'cleanup' is a callback function.  'cleanup(cbdata)' is called
 *    after all records have been processed.
 *
 *    'filter' is a callback function.  'filter(record, cbdata)' is
 *    called for each record.  If 'filter()' returns
 *    SKPLUGIN_FILTER_PASS, the record is accepted; if it returns
 *    SKPLUGIN_FILTER_FAIL, the record is rejected.
 *
 *    'cbdata' will be passed back unchanged to the plugin as a
 *    parameter in the various callback functions.
 */
skplugin_err_t skpinRegFilter(
    skplugin_filter_t         **filter,
    const skplugin_callbacks_t *regdata,
    void                       *cbdata);


/*
 *    Register a new transformer function to apply to all records.
 *    Registering a transformer function in an application that
 *    doesn't support transforms is a no-op.
 *
 *    'transformer' is a handle to the newly created transformer.
 *    (Can be NULL.)
 *
 *    'init' is a callback function.  'init(cbdata)' is called for all
 *    registered filter predicates.  It is called after argument
 *    processing and before processing of records.
 *
 *    'cleanup' is a callback function.  'cleanup(cbdata)' is called
 *    after all records have been processed.
 *
 *    'transform' is a callback function.  'transform(rec, cbdata)' is
 *    called for each record.  Any changes made by 'transform()' are
 *    seen by the application.
 *
 *    'cbdata' will be passed back unchanged to the plugin as a
 *    parameter in the various callback functions.
 */
skplugin_err_t skpinRegTransformer(
    skplugin_transform_t      **transformer,
    const skplugin_callbacks_t *regdata,
    void                       *cbdata);


/*
 *    Register a new derived field for record processing.  Registering
 *    a field in an application that doesn't work in terms of fields
 *    is a no-op.
 *
 *    'return_field' is a handle to the newly created field.  (Can be
 *    NULL.)
 *
 *    'name' is the string that is the primary name of the field, and
 *    by default will be the value returned by skPluginFieldTitle() to
 *    the application.
 *
 *    'description' is a textual description of the field.  It can be
 *    returned by skPluginFieldDescription().
 *
 *    'regdata' is a struct of type skplugin_callbacks_t, which should
 *    be filled out as follows:
 *
 *      'column_width' is the number of characters (not including
 *      trailing NULL) required to hold a string representation of the
 *      longest value of the field.  This value can be zero if not
 *      used, or if it will be set later using skpinSetFieldWidths().
 *
 *      'bin_bytes' is the number of bytes required to hold a binary
 *      representation of a value of the field.  This value can be
 *      zero if not used, or if it will be set later using
 *      skpinSetFieldWidths().
 *
 *      'init' is a callback function of type skplugin_cleanup_fn_t.
 *      'init(cbdata)' is called when this field will be used, before
 *      processing data.  It may be NULL.
 *
 *      'cleanup' is a callback function of type
 *      skplugin_callback_fn_t.  'cleanup(cbdata)' is called after all
 *      records have been processed.  It may be NULL.
 *
 *      'rec_to_text' is a callback function of type
 *      skplugin_text_fn_t.  'rec_to_bin(rec, dst, cbdata)' or
 *      'add_rec_to_bin(rec, dst, cbdata)' is called to fetch the textual
 *      value for a field given the SiLK Flow record 'rec'.
 *      'rec_to_text()' should write no more than 'column_width' bytes
 *      into 'dst'.
 *
 *      'rec_to_bin' is a callback function of type skplugin_bin_fn_t.
 *      'rec_to_bin(rec, dst, cbdata)' is called to fetch the binary
 *      value for this field given the SiLK Flow record 'rec'.
 *      'rec_to_bin' should write exactly 'bin_bytes' bytes into
 *      'dst'.  If an application requires a rec-to-binary function
 *      but 'rec_to_bin' is NULL and 'rec_to_text' is present,
 *      'rec_to_text' will be used instead, and 'column_width' will be
 *      used as the width for binary values (zeroing out the
 *      destination area before it is written to).
 *
 *      'add_rec_to_bin' is a callback function of type
 *      skplugin_bin_fn_t.  'rec_to_bin(rec, dst, cbdata)' is called
 *      to add to the binary value in 'dst' based on the SiLK Flow
 *      record given in 'rec'.  'rec_to_bin' should write exactly
 *      'bin_bytes' bytes into 'dst'.  This function is only used for
 *      aggregate value fields.
 *
 *      'bin_to_text' is a callback function of type
 *      skplugin_bin_to_text_fn_t.  'bin_to_text(bin, dst, width,
 *      cbdata)' is called to get a textual representation of the
 *      value in 'bin', where 'bin' was filled in by a call to
 *      'rec_to_bin'.  The 'bin_to_text' callback should write no more
 *      than 'width' characters into 'dst'.
 *
 *      'bin_merge' is a callback function. 'bin_merge(dst, src,
 *      cbdata)' is called to merge the binary aggregate values of
 *      'src' and 'dst' into 'dst'.
 *
 *      'bin_compare' is a callback function.  'bin_compare(val, a,
 *      b)' is will return in val whether a is less than, equal to, or
 *      greater than b.  If this function is NULL, memcmp will be used
 *      on the binary values instead.
 *
 *      'initial' represents the inital value of the binary aggregate
 *      value.  It's width should be exactly 'field_width_bin' bytes.
 *
 *      'extra' is a NULL-terminated constant array of strings
 *      representing "extra arguments".  Read the EXTRA ARGUMENTS
 *      section for information on these arguments.  It may be NULL.
 *
 *    'cbdata' will be passed back unchanged to the plugin as a
 *    parameter in the various callback functions.
 *
 *    NOTE: When sorting, the binary values provided by 'rec_to_bin()
 *    will be sorted using memcmp().  If the plugin wants to enforce a
 *    specific ordering, it should be sure to produce values that will
 *    sort correctly.
 */
skplugin_err_t skpinRegField(
    skplugin_field_t          **return_field,
    const char                 *name,
    const char                 *description,
    const skplugin_callbacks_t *regdata,
    void                       *cbdata);

/*
 *    Set the textual and binary widths for a field.  Meant to be used
 *    within an 'init' function.
 */
skplugin_err_t skpinSetFieldWidths(
    skplugin_field_t *field,
    size_t            field_width_text,
    size_t            field_width_bin);

/*
 *    Adds an alias (name) for a field.  Returns SKPLUGIN_ERR if the
 *    name already exists, SKPLUGIN_OK otherwise.
 */
skplugin_err_t skpinAddFieldAlias(
    skplugin_field_t *field,
    const char       *alias);

/*
 *    Sets the title for a field.
 */
skplugin_err_t skpinSetFieldTitle(
    skplugin_field_t *field,
    const char       *title);

/*
 *    Register a cleanup function for the plugin.  This will be called
 *    by skPluginRunCleanup() after all the function-specific cleanups
 *    are called.
 */
skplugin_err_t skpinRegCleanup(
    skplugin_cleanup_fn_t cleanup);


/*
 *    Declare this plugin to be non-safe.  This function should only
 *    be called when the plugin is active; otherwise the mere presence
 *    of the plug-in will prevent rwfilter from running with multiple
 *    threads.
 */
void skpinSetThreadNonSafe(void);


/************************************/
/*** Plugin application interface ***/
/************************************/

/* This set of functions is meant to be called by the application
 * which is loading and using plugins */

/*
 *    This is used to initialize the skplugin library.  'num_entries'
 *    is the number of function masks that will be passed to this
 *    function.  Each function mask should indicate a type of
 *    plugin functionality the application wants.
 */
void skPluginSetup(int num_entries, ...);

/*
 *    Unloads all plugins and frees all plugin data.  Does not call
 *    the 'cleanup' functions that the plugins have registered.  The
 *    'cleanup' functions are called by skPluginRunCleanup().
 */
void skPluginTeardown(void);

/*
 *    Sets the extra arguments that the application handles.  'extra'
 *    is a NULL terminated array of strings.  If 'extra' is NULL, no
 *    extra arguments are registered.  (This is the default).
 */
void skPluginSetAppExtraArgs(const char **extra);

/*
 *    Loads the plugin represented by the filename 'name'.  If
 *    complain_on_error is non-zero, error messages will be written to
 *    the error stream.
 */
skplugin_err_t skPluginLoadPlugin(
    const char *name,
    int         complain_on_error);

/*
 *    Gets the list of extra arguments of the application that the
 *    plugins support.  The returned array will be a NULL-terminated
 *    list of strings.
 */
const char **skPluginGetPluginExtraArgs(void);

/*
 *    Sets which extra arguments the application will actually use.
 *    'extra' is a NULL-terminated array of strings.  If 'extra' is
 *    NULL, no extra arguments are registered.
 */
void skPluginSetUsedAppExtraArgs(const char **extra);

/*
 *    Returns 1 if all loaded plugins can be safely be run in a
 *    threaded context, 0 otherwise.
 */
int skPluginIsThreadSafe(void);

/*
 *    Print, to 'fh', the usage information for the options which the
 *    plugins have registered through calls to skpinRegOption().
 */
skplugin_err_t skPluginOptionsUsage(FILE *fh);

/*
 *    Runs the 'init' routines for the functions and the activated
 *    fields requested.  If 'fn_mask' is non-zero, this will only
 *    initialize activated fields for whom 'fn_mask' is a subset of
 *    their callback functions.  If 'fn_mask' will run over activated
 *    fields, you should not run skPluginFieldRunInitialize() on the
 *    individual fields, unless you know the initialization functions
 *    will be idempotent.
 */
skplugin_err_t skPluginRunInititialize(
    skplugin_fn_mask_t fn_mask);

/*
 *    Runs a specific plugin field's initialization function.
 */
skplugin_err_t skPluginFieldRunInitialize(
    const skplugin_field_t *field);

/*
 *    Runs the cleanup routines for the activated and activated fields
 *    requested.  If 'fn_mask' is non-zero, this will only clean up
 *    activated fields for whom 'fn_mask' is a subset of their
 *    callback functions.  If 'fn_mask' will fun over activated
 *    fields, you should not run skPluginFieldRunCleanup() on the
 *    individual fields, unless you know the cleanup functions will be
 *    idempotent.
 */
skplugin_err_t skPluginRunCleanup(
    skplugin_fn_mask_t fn_mask);

/*
 *    Runs a specific plugin field's cleanup function.
 */
skplugin_err_t skPluginFieldRunCleanup(
    const skplugin_field_t *field);

/*
 *    Returns 1 if any filtering plugins are currently registered, 0
 *    if not.
 */
int skPluginFiltersRegistered(void);

/*
 *    Returns 1 if any transform plugins are currently registered, 0
 *    if not.
 */
int skPluginTransformsRegistered(void);

/*
 *    Runs the filter functions over the record 'rec'.  The 'extra'
 *    fields are determined by the current set of arguments registered
 *    by skPluginRegisterUsedAppExtraArgs().
 */
skplugin_err_t skPluginRunFilterFn(
    const rwRec    *rec,
    void          **extra);

/*
 *    Runs the transform functions over the record 'rec'.  The 'extra'
 *    fields are determined by the current set of arguments registered
 *    by skPluginRegisterUsedAppExtraArgs().
 */
skplugin_err_t skPluginRunTransformFn(
    rwRec  *rec,
    void  **extra);

/*
 *    Binds an iterator around all fields that contain information
 *    that matches the 'fn_mask'.  If 'all_fields' is false, will
 *    only iterate over "activated" fields.
 */
skplugin_err_t skPluginFieldIteratorBind(
    skplugin_field_iter_t *iter,
    skplugin_fn_mask_t     fn_mask,
    int                    all_fields);

/*
 *    Resets a field iterator so it can be iterated over again.
 */
skplugin_err_t skPluginFieldIteratorReset(
    skplugin_field_iter_t *iter);

/*
 *    Retrieves the field identifier for the next field.  Returns 1 on
 *    success, 0 on failure.
 */
int skPluginFieldIteratorNext(
    skplugin_field_iter_t  *iter,
    skplugin_field_t      **field);

/*
 *    Activate the field 'field'.  All fields start deactivated.
 *    Activating a field allows its 'init' and 'cleanup' functions to
 *    run.
 */
skplugin_err_t skPluginFieldActivate(
    const skplugin_field_t *field);

/*
 *    Deactivate the field 'field'.  All fields start deactivated.
 */
skplugin_err_t skPluginFieldDeactivate(
    const skplugin_field_t *field);

/*
 *    Retrieves a pointer to the constant names of a field (NULL
 *    terminated).
 */
skplugin_err_t skPluginFieldName(
    const skplugin_field_t  *field,
    const char            ***name);

/*
 *    Retrieves a pointer to the constant title of a field.  The
 *    caller should not modify this value.
 */
skplugin_err_t skPluginFieldTitle(
    const skplugin_field_t *field,
    const char            **title);

/*
 *    Retrieves a pointer to the constant description of a field.  The
 *    caller should not modify this value.  The description may be
 *    NULL.
 */
skplugin_err_t skPluginFieldDescription(
    const skplugin_field_t *field,
    const char            **description);

/*
 *    Retrieves a pointer to the constant path of the plugin which
 *    created the field.  The caller should not modify this value.
 */
skplugin_err_t skPluginFieldGetPluginName(
    const skplugin_field_t *field,
    const char            **plugin_name);

/*
 *    Retrieves the length of the binary representation for this
 *    field.  Returns SKPLUGIN_ERR if none.
 */
skplugin_err_t skPluginFieldGetLenBin(
    const skplugin_field_t *field,
    size_t                 *len);

/*
 *    Retrieves the maximum length of text fields (not including
 *    terminating NUL) for this field.  Returns SKPLUGIN_ERR if none.
 */
skplugin_err_t skPluginFieldGetLenText(
    const skplugin_field_t *field,
    size_t                 *len);

/*
 *    Retrieves the initial binary value for this field.
 */
skplugin_err_t skPluginFieldGetInitialValue(
    const skplugin_field_t *aggregate,
    uint8_t                *intial_value);


/*
 *    Given a SiLK Flow record 'rec', runs the function that computes
 *    a binary value for this field and puts the value into 'bin'.
 *    The required size of 'bin' can be determined by a call to
 *    skPluginFieldGetLenBin().  'extra' fields are determined by the
 *    current set of arguments registered by
 *    skPluginRegisterUsedAppExtraArgs().
 */
skplugin_err_t skPluginFieldRunRecToBinFn(
    const skplugin_field_t *field,
    uint8_t                *bin,
    const rwRec            *rec,
    void                  **extra);

/*
 *    Given a SiLK Flow record 'rec', runs the function that computes
 *    a binary value for this field and merges with (adds to) the
 *    value into currently in 'bin' into 'bin'.  The required size of
 *    'bin' can be determined by a call to skPluginFieldGetLenBin().
 *    'extra' fields are determined by the current set of arguments
 *    registered by skPluginRegisterUsedAppExtraArgs().
 */
skplugin_err_t skPluginFieldRunAddRecToBinFn(
    const skplugin_field_t *field,
    uint8_t                *bin,
    const rwRec            *rec,
    void                  **extra);

/*
 *    Runs the function that converts from a binary value to textual
 *    value for this field, putting the textual value into 'text', an
 *    array of 'width' characters.
 */
skplugin_err_t skPluginFieldRunBinToTextFn(
    const skplugin_field_t *field,
    char                   *text,
    size_t                  width,
    const uint8_t          *bin);

/*
 *    Given a SiLK Flow record 'rec', runs the function that computes
 *    a textual value for this field, putting the textual value into
 *    'text', an array of 'width' characters.  'extra' fields are
 *    determined by the current set of arguments registered by
 *    skPluginRegisterUsedAppExtraArgs().
 */
skplugin_err_t skPluginFieldRunRecToTextFn(
    const skplugin_field_t *field,
    char                   *text,
    size_t                  width,
    const rwRec            *rec,
    void                  **extra);


/*
 *    Runs the function that merges two binary values for this field.
 *    The binary value in 'src' is merged with 'dst', and the result
 *    is put back in 'dst'.
 */
skplugin_err_t skPluginFieldRunBinMergeFn(
    const skplugin_field_t *field,
    uint8_t                *dst,
    const uint8_t          *src);


/*
 *    Runs the function that compares two binary values for this
 *    field.  The binary value in 'a' is compared with 'b', and the
 *    result (less than zero, zero, greater than zero) is put in
 *    'val'.
 */
skplugin_err_t skPluginFieldRunBinCompareFn(
    const skplugin_field_t *field,
    int                    *val,
    const uint8_t          *a,
    const uint8_t          *b);


/*
 *    Returns the function mask for a field.
 */
skplugin_fn_mask_t skPluginFieldFnMask(
    const skplugin_field_t *field);


/*
 *    Sets the function that skpinOpenDataInputStream() should use for
 *    opening files to 'open_fn'.
 *
 *    If this function is not called or called with a NULL parameter,
 *    the sequence of functions skStreamCreate(), skStreamBind(),
 *    skStreamOpen() is called.
 */
void skPluginSetOpenInputFunction(open_data_input_fn_t open_fn);


/*
 *   OLD DEPRECATED CODE TO SUPPORT THE LEGACY dynlib.h
 */
/*
 *  A list of application types.  One of these should be passed to
 *  dynlibCreate().
 */
typedef enum dynlibSymbolId_en {
    DYNLIB_SETUP,               /* internal use -- must be first*/
    DYNLIB_TEARDOWN,            /* internal use */
    DYNLIB_VERSION,             /* internal use */
    DYNLIB_CONFIGURE,           /* internal use */
    DYNLIB_INITIALIZE,          /* internal use */
    DYNLIB_OPT_USAGE,           /* internal use */
    DYNLIB_SUPPORTS_THREADS,    /* internal use */
    DYNLIB_EXCL_FILTER,         /* rwfilter: augment other filter rules */
    DYNLIB_SHAR_FILTER,         /* rwfilter: augment other filter rules */
    DYNLIB_CUT,                 /* rwcut: output of data */
    DYNLIB_SORT,                /* rwsort: orders records by attributes */
    DYNLIB_UNIQ,                /* rwuniq: bin records by attribute(s) */
    DYNLIB_PTOFLOW,             /* rwptoflow: create flow from packet data */
    DYNLIB_VOID                 /* internal use -- must be last */
} dynlibSymbolId;

/*
 *    Loads the plugin represented by the filename 'name' using the
 *    skplugin infrastructure.  Will handle legacy dynlib-style
 *    plugins. If complain_on_error is non-zero, error messages will
 *    be written to the error stream.
 */
skplugin_err_t skPluginLoadPluginOrDynlib(
    const char     *name,
    dynlibSymbolId  appType,
    int             complain_on_error);

#endif /* _SKPLUGIN_H */

/*
** Local Variables:
** mode:c
** indent-tabs-mode:nil
** c-basic-offset:4
** End:
*/
