//===========================================================================
//  @(#) $Name: cflowd-2-1-b1 $
//  @(#) $Id: CflowdFlowFilter.hh,v 1.9 1998/12/12 10:06:37 dwm Exp $
//===========================================================================
//  CAIDA Copyright Notice
//
//  By accessing this software, cflowd++, you are duly informed
//  of and agree to be bound by the conditions described below in this
//  notice:
//
//  This software product, cflowd++, is developed by Daniel W. McRobb, and
//  copyrighted(C) 1998 by the University of California, San Diego
//  (UCSD), with all rights reserved.  UCSD administers the CAIDA grant,
//  NCR-9711092, under which part of this code was developed.
//
//  There is no charge for cflowd++ software. You can redistribute it
//  and/or modify it under the terms of the GNU General Public License,
//  v.  2 dated June 1991 which is incorporated by reference herein.
//  cflowd++ is distributed WITHOUT ANY WARRANTY, IMPLIED OR EXPRESS, OF
//  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE or that the use
//  of it will not infringe on any third party's intellectual property
//  rights.
//
//  You should have received a copy of the GNU GPL along with cflowd++.
//  Copies can also be obtained from:
//
//    http://www.gnu.org/copyleft/gpl.html
//
//  or by writing to:
//
//    University of California, San Diego
//
//    SDSC/CAIDA
//    9500 Gilman Dr., MS-0505
//    La Jolla, CA 92093 - 0505  USA
//
//  Or contact:
//
//    info@caida.org
//===========================================================================

#ifndef _CFLOWDFLOWFILTER_HH_
#define _CFLOWDFLOWFILTER_HH_

#include <string>
#include <vector>

#include "CflowdRawFlow.hh"

extern int          flowfiltparse (void);
extern int          flowfiltparseval;

//---------------------------------------------------------------------------
//  pre-declare the CflowdFlowFilter class so we can prototype some
//  global functions that use it.
//---------------------------------------------------------------------------
class CflowdFlowFilter;

//===========================================================================
//  Declare some external global functions that support the
//  CflowdFlowFilter class.  These should not be called directly by
//  an application, but are prototyped here because they're used by
//  CflowdFlowFilter.  They provide an interface to our lexer/parser
//  code.
//===========================================================================

//-------------------------------------------------------------------------
//    extern int
//    CompileExpression(const char *expression,          
//                      CflowdFlowFilter & flowFilter)
//.........................................................................
//  Compiles expression into a CflowdFlowFilter that can be used by
//  the parser.  Returns 0 on success, -1 on failure.
//-------------------------------------------------------------------------
extern int
CompileExpression(const char *expression,
                  CflowdFlowFilter & flowFilter);

//-------------------------------------------------------------------------
//        extern void SetFlowPointer(const CflowdRawFlow *flowPtr)
//.........................................................................
//  Sets the flow pointer used in the parser.
//-------------------------------------------------------------------------
extern void SetFlowPointer(const CflowdRawFlow *flowPtr);

//-------------------------------------------------------------------------
//         extern void
//         SetFlowFilter(const CflowdFlowFilter * flowFilter)
//.........................................................................
//  Sets the CflowdFlowFilter to be used in the parser's lexer
//  (flowfiltlex() in FlowFilterLex.cc).
//-------------------------------------------------------------------------
extern void
SetFlowFilter(const CflowdFlowFilter * flowFilter);

//-------------------------------------------------------------------------
//                     extern void RewindFlowFilter()
//.........................................................................
//  Resets the flow filter.  This just repoints the iterator used to
//  walk the tokens in the CflowdFlowFilter.  It is called at the start
//  of CflowdFlowFilter::Matches().
//-------------------------------------------------------------------------
extern void RewindFlowFilter();

//-------------------------------------------------------------------------
//  CflowdFlowFilterLexedToken
//-------------------------------------------------------------------------
//  This is the class we use to hold a token for the parser (i.e. the result
//  of s single call to the filter expression string lexer).
//---------------------------------------------------------------------------
class CflowdFlowFilterLexedToken
{
public:
  int                        lexToken;
  CflowdRawFlow::index_type  fieldMask;
  uint32_t                   value;

  //-------------------------------------------------------------------------
  //       inline CflowdFlowFilterLexedToken &                   
  //       operator = (const CflowdFlowFilterLexedToken & lexedToken) 
  //.........................................................................
  //  
  //-------------------------------------------------------------------------
  inline CflowdFlowFilterLexedToken &
  operator = (const CflowdFlowFilterLexedToken & lexedToken)
  {
    this->lexToken = lexedToken.lexToken;
    this->fieldMask = lexedToken.fieldMask;
    this->value = lexedToken.value;
    return(*this);
  }
};

//-------------------------------------------------------------------------
//  class CflowdFlowFilter : public vector<CflowdFlowFilterLexedToken>
//-------------------------------------------------------------------------
//  This class can be used to select flows matching a filter expression.
//  This works much like libpcap; you set the compiled version of the
//  filter using Compile(), and then use Matches() on CflowdRawFlow
//  objects.
//
//  The way this works internally... Compile() calls out to a lexer
//  (CompileExpression() in filtexpr.lex) that will build a vector of
//  tokens.  This is generally a slow process, since we're lexing a
//  string.  When you call Matches(), you're really calling a bison
//  parser that will use the vector of tokens built by Compile().
//  Obviously the bison parser wants a yylex()-like function to pop the
//  tokens; this is provided by the flowfiltlex() function in
//  FlowFilterLex.cc.
//
//  Things are done this way currently to avoid lexing a filter
//  expression string more than once for a given filter.  The old method
//  of filtering (where we re-lexed the filter expression every time you
//  checked for a match against the filter) was very slow.  The new
//  implementation is considerably faster (working with the pre-parsed
//  token vector is much cheaper than re-lexing the filter expression
//  string).
//
//  This still isn't blazingly fast.  However, it was fairly easy to
//  implement and is fairly easy to extend to cover new flow fields,
//  keywords and operators.  In the future I may use the BPF engine
//  for filtering.
//-------------------------------------------------------------------------
class CflowdFlowFilter : public vector<CflowdFlowFilterLexedToken>
{
public:
  //-------------------------------------------------------------------------
  //                  int Compile(const char *expression);                  
  //.........................................................................
  //  Compiles expression into our CflowdFlowFilter.  Returns 0 on
  //  sucess, -1 on failure.
  //-------------------------------------------------------------------------
  int Compile(const char *expression);
  
  //-------------------------------------------------------------------------
  //            bool Matches(const CflowdRawFlow *rawFlow) const;
  //.........................................................................
  //  Returns true if rawFlow matches our filter, else returns false.
  //-------------------------------------------------------------------------
  inline bool Matches(const CflowdRawFlow *rawFlow) const
  {
    ::SetFlowFilter(this);
    ::SetFlowPointer(rawFlow);
    int rc = flowfiltparse();
    if (rc) {
      return(false);
    }
    if (flowfiltparseval) {
      return(true);
    }
    return(false);
  }
};

#endif  // _CFLOWDFLOWFILTER_HH_
