// snf_HeaderFinder.hpp
// Copyright (C) 2007 - 2009 ARM Research Labs, LLC.
// See www.armresearch.com for the copyright terms.
//
// SNF Header Finder used for identifying headers in a message. A header match
// is defined by the name of the header, it's ordinal, and some string that is
// contained in that header. If the pattern is matched then one or more bits
// are set in a 32 bit status flag. Usually, one bit at a time. Other matchers
// that intend to set the same bits as are already set are turned off to save
// cycles.
//
// The initial implementation of this engine is for turning off GBUdb learning
// when one of the defined headers is matched. Other uses are likely to be
// developed. This engine will have to evolve as that occurrs.
//
// The evaluation of the status flag is defined by the application.

#ifndef snf_HeaderFinder_included
#define snf_HeaderFinder_included

#include <string>
#include <set>
#include <map>
#include <vector>

using namespace std;

struct HeaderFinderPattern {                                                    // Input pattern for header finder.
    string Header;                                                              // Header name to match.
    int Ordinal;                                                                // Which instance to match.
    int Context;                                                                // Context link (for pairing patterns).
    string Contains;                                                            // What to find in the header.
    unsigned long int Directive;                                                // What directive to present.

    HeaderFinderPattern():                                                      // When constructing a finder parttern
      Header(""),Ordinal(0),Context(0),Contains(""),Directive(0){}              // initialize it like this.

    HeaderFinderPattern(const HeaderFinderPattern& P);                          // Copy constructor.

    void clear();                                                               // Do this to make fresh and clean.

    HeaderFinderPattern& operator=(const HeaderFinderPattern& R);               // Assignment operator.
    const bool operator<(const HeaderFinderPattern& R) const;                   // Comparator for set<> living.
};

typedef set<HeaderFinderPattern> HeaderDirectiveSet;                            // Convenient set typedef.
typedef set<HeaderFinderPattern>::iterator HeaderDirectiveIterator;             // Convenient iterator typedef.

typedef map<const string, int> NameOrdinalMap;                                  // Header Ordinal Count Map.

// Upon construction the HeaderFinder scans the headers for matching directives
// and leaves the composite results ready for inspection via the () operator.
// UnfoldHeaders() strips and unfolds the headers then passes them to
// MatchHeaders() which tracks the ordinals for matching directives and passes
// those headers to CheckContent() to see if the required patterns are found.
// CheckContent() then updates the Directives if the appropriate content is
// found.

class snfScanData;                                                              // Yes, this does exist.

class HeaderFinder {                                                            // Header Finder Object.
  private:

    const HeaderDirectiveSet& HeaderDirectives;                                 // Handle for the directives/patterns.
    unsigned long int Directives;                                               // Composite result given this message.

    set<int> ActivatedContexts;                                                 // Set of activated contexts.

    const unsigned char* Bfr;                                                   // Message buffer.
    const int Len;                                                              // Message length.

    snfScanData* ScanData;                                                      // Scanner control data.

    vector<bool> ImpossibleBytes;                                               // Cache of known impossible bytes.
    NameOrdinalMap Ordinals;                                                    // Map of current header ordinals.

    void CheckContent(string& Header, const HeaderFinderPattern& P);            // Check for a match in the header.
    void MatchHeaders(string& Header);                                          // Check that the header matches.
    bool ByteIsImpossible(unsigned char b);                                     // Is b not first byte of any pattern?
    void UnfoldHeaders();                                                       // Unfold and check headers.

  public:
    HeaderFinder(                                                               // The constructor reads the message.
      snfScanData* EngineScanData,                                              // -- Scanner control data ptr.
      const HeaderDirectiveSet& Patterns,                                       // -- this is the set of patterns.
      const unsigned char* MessageBuffer,                                       // -- this is the message buffer.
      const int MessageLength                                                   // -- this is the length of the buffer.
    );

    const unsigned long int operator()() const;                                 // How to read the composite directives.
    string EstablishedSourceIP;                                                 // Source IP from directive if any.
};

#include "snf_HeaderFinder.inline.hpp"

#endif
