token.h 8.31 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.

#ifndef TOKEN_H
#define TOKEN_H

#include <exceptions/exceptions.h>
#include <dhcp/pkt.h>
#include <stack>

namespace isc {
namespace dhcp {

class Token;

/// @brief Pointer to a single Token
typedef boost::shared_ptr<Token> TokenPtr;

/// This is a structure that holds an expression converted to RPN
///
/// For example expression: option[123] == 'foo' will be converted to:
/// [0] = option[123] (TokenOption object)
/// [1] = 'foo' (TokenString object)
/// [2] = == operator (TokenEqual object)
typedef std::vector<TokenPtr> Expression;

38 39
typedef boost::shared_ptr<Expression> ExpressionPtr;

40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
/// Evaluated values are stored as a stack of strings
typedef std::stack<std::string> ValueStack;

/// @brief EvalStackError is thrown when more or less parameters are on the
///        stack than expected.
class EvalBadStack : public Exception {
public:
    EvalBadStack(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what) { };
};

/// @brief Base class for all tokens
///
/// It provides an interface for all tokens and storage for string representation
/// (all tokens evaluate to string).
///
/// This class represents a single token. Examples of a token are:
/// - "foo" (a constant string)
/// - option[123] (a token that extracts value of option 123)
/// - == (an operator that compares two other tokens)
/// - substring(a,b,c) (an operator that takes three arguments: a string,
61
///   first character and length)
62 63 64 65 66
class Token {
public:

    /// @brief This is a generic method for evaluating a packet.
    ///
67
    /// We need to pass the packet being evaluated and possibly previously
68
    /// evaluated values. Specific implementations may ignore the packet altogether
Tomek Mrugalski's avatar
Tomek Mrugalski committed
69
    /// and just put their own value on the stack (constant tokens), look at the
70 71 72 73 74 75
    /// packet and put some data extracted from it on the stack (option tokens),
    /// or pop arguments from the stack and put back the result (operators).
    ///
    /// The parameters passed will be:
    ///
    /// @param pkt - packet being classified
76
    /// @param values - stack of values with previously evaluated tokens
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
    virtual void evaluate(const Pkt& pkt, ValueStack& values) = 0;

    /// @brief Virtual destructor
    virtual ~Token() {}
};

/// @brief Token representing a constant string
///
/// This token holds value of a constant string, e.g. it represents
/// "MSFT" in expression option[vendor-class] == "MSFT"
class TokenString : public Token {
public:
    /// Value is set during token construction.
    ///
    /// @param str constant string to be represented.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
92
    TokenString(const std::string& str)
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
        :value_(str){
    }

    /// @brief Token evaluation (puts value of the constant string on the stack)
    ///
    /// @param pkt (ignored)
    /// @param values (represented string will be pushed here)
    void evaluate(const Pkt& pkt, ValueStack& values);

protected:
    std::string value_; ///< Constant value
};

/// @brief Token that represents a value of an option
///
/// This represents a reference to a given option, e.g. in the expression
/// option[vendor-class] == "MSFT", it represents option[vendor-class]
///
111
/// During the evaluation it tries to extract the value of the specified
112 113 114
/// option. If the option is not found, an empty string ("") is returned.
class TokenOption : public Token {
public:
115
    /// @brief Constructor that takes an option code as a parameter
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
    /// @param option_code code of the option
    ///
    /// Note: There is no constructor that takes option_name, as it would
    /// introduce complex dependency of the libkea-eval on libdhcpsrv.
    ///
    /// @param option_code code of the option to be represented.
    TokenOption(uint16_t option_code)
        :option_code_(option_code) {}

    /// @brief Evaluates the values of the option
    ///
    /// This token represents a value of the option, so this method attempts
    /// to extract the option from the packet and put its value on the stack.
    /// If the option is not there, an empty string ("") is put on the stack.
    ///
Tomek Mrugalski's avatar
Tomek Mrugalski committed
131
    /// @param pkt specified option will be extracted from this packet (if present)
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
    /// @param values value of the option will be pushed here (or "")
    void evaluate(const Pkt& pkt, ValueStack& values);

private:
    uint16_t option_code_; ///< code of the option to be extracted
};

/// @brief Token that represents equality operator (compares two other tokens)
///
/// For example in the expression option[vendor-class] == "MSFT" this token
/// represents the equal (==) sign.
class TokenEqual : public Token {
public:
    /// @brief Constructor (does nothing)
    TokenEqual() {}

    /// @brief Compare two values.
    ///
    /// Evaluation does not use packet information, but rather consumes the last
151
    /// two parameters. It does a simple string comparison and sets the value to
152 153 154
    /// either "true" or "false". It requires at least two parameters to be
    /// present on stack.
    ///
155
    /// @throw EvalBadStack if there are less than 2 values on stack
156
    ///
157 158
    /// @param pkt (unused)
    /// @param values - stack of values (2 arguments will be popped, 1 result
159 160 161 162
    ///        will be pushed)
    void evaluate(const Pkt& pkt, ValueStack& values);
};

163 164 165 166 167 168 169 170 171 172 173 174
/// @brief Token that represents the substring operator (returns a portion
/// of the supplied string)
///
/// This token represents substring(str, start, len)  An operator that takes three
/// arguments: a string, the first character and the length.
class TokenSubstring : public Token {
public:
    /// @brief Constructor (does nothing)
    TokenSubstring() {}

    /// @brief Extract a substring from a string
    ///
175 176 177 178 179 180 181
    /// Evaluation does not use packet information.  It requires at least
    /// three values to be present on the stack.  It will consume the top
    /// three values on the stack as parameters and push the resulting substring
    /// onto the stack.  From the top it expects the values on the stack as:
    /// -  len
    /// -  start
    /// -  str
182
    ///
183
    /// str is the string to extract a substring from.  If it is empty, an empty
184 185 186
    /// string is pushed onto the value stack.
    ///
    /// start is the postion from which the code starts extracting the substring.
187 188 189
    /// 0 is the first character and a negative number starts from the end, with
    /// -1 being the last character.  If the starting point is outside of the
    /// original string an empty string is pushed onto the value stack.
190 191 192 193
    ///
    /// length is the number of characters from the string to extract.
    /// "all" means all remaining characters from start to the end of string.
    /// A negative number means to go from start towards the beginning of
194
    /// the string, but doesn't include start.
195 196 197
    /// If length is longer than the remaining portion of string
    /// then the entire remaining portion is placed on the value stack.
    ///
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
    /// The following examples all use the base string "foobar", the first number
    /// is the starting position and the second is the length.  Note that
    /// a negative length only selects which characters to extract it does not
    /// indicate an attempt to reverse the string.
    /// -  0, all => "foobar"
    /// -  0,  6  => "foobar"
    /// -  0,  4  => "foob"
    /// -  2, all => "obar"
    /// -  2,  6  => "obar"
    /// - -1, all => "r"
    /// - -1, -4  => "ooba"
    ///
    /// @throw EvalBadStack if there are less than 3 values on stack
    ///
    /// @param pkt (unused)
    /// @param values - stack of values (3 arguments will be popped, 1 result
214 215 216 217
    ///        will be pushed)
    void evaluate(const Pkt& pkt, ValueStack& values);
};

218 219 220 221
}; // end of isc::dhcp namespace
}; // end of isc namespace

#endif