option_int.h 8.75 KB
Newer Older
1
// Copyright (C) 2012-2019 Internet Systems Consortium, Inc. ("ISC")
2
//
3 4 5
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6

7 8
#ifndef OPTION_INT_H
#define OPTION_INT_H
9

Marcin Siodelski's avatar
Marcin Siodelski committed
10 11 12
#include <dhcp/libdhcp++.h>
#include <dhcp/option.h>
#include <dhcp/option_data_types.h>
13
#include <dhcp/option_space.h>
Marcin Siodelski's avatar
Marcin Siodelski committed
14 15
#include <util/io_utilities.h>

16
#include <stdint.h>
17
#include <sstream>
18 19 20 21

namespace isc {
namespace dhcp {

22 23 24
template<typename T>
class OptionInt;

25
/// @defgroup option_int_defs Typedefs for OptionInt class.
26 27 28 29 30 31 32 33 34 35 36 37
///
/// @brief Classes that represent options comprising an integer.
///
/// @{
typedef OptionInt<uint8_t> OptionUint8;
typedef boost::shared_ptr<OptionUint8> OptionUint8Ptr;
typedef OptionInt<uint16_t> OptionUint16;
typedef boost::shared_ptr<OptionUint16> OptionUint16Ptr;
typedef OptionInt<uint32_t> OptionUint32;
typedef boost::shared_ptr<OptionUint32> OptionUint32Ptr;
/// @}

38
/// This template class represents DHCP option with single value.
39 40 41 42 43 44 45 46 47
/// This value is of integer type and can be any of the following:
/// - uint8_t,
/// - uint16_t,
/// - uint32_t,
/// - int8_t,
/// - int16_t,
/// - int32_t.
///
/// @param T data field type (see above).
48
template<typename T>
49
class OptionInt: public Option {
50 51
private:

52
    /// @brief Pointer to the option object for a specified type T.
53
    typedef boost::shared_ptr<OptionInt<T> > OptionIntTypePtr;
54 55

public:
56 57
    /// @brief Constructor.
    ///
58
    /// @param u universe (V4 or V6)
59 60
    /// @param type option type.
    /// @param value option value.
61 62 63
    ///
    /// @throw isc::dhcp::InvalidDataType if data field type provided
    /// as template parameter is not a supported integer type.
64
    /// @todo Extend constructor to set encapsulated option space name.
65 66
    OptionInt(Option::Universe u, uint16_t type, T value)
        : Option(u, type), value_(value) {
67
        if (!OptionDataTypeTraits<T>::integer_type) {
68
            isc_throw(dhcp::InvalidDataType, "non-integer type");
69
        }
70
        setEncapsulatedSpace(u == Option::V4 ? DHCP4_OPTION_SPACE : DHCP6_OPTION_SPACE);
71 72
    }

73 74
    /// @brief Constructor.
    ///
75
    /// This constructor creates option from a buffer. This constructor
76 77 78
    /// may throw exception if \ref unpack function throws during buffer
    /// parsing.
    ///
79
    /// @param u universe (V4 or V6)
80 81 82 83
    /// @param type option type.
    /// @param begin iterator to first byte of option data.
    /// @param end iterator to end of option data (first byte after option end).
    ///
84
    /// @throw isc::OutOfRange if provided buffer is shorter than data size.
85 86
    /// @throw isc::dhcp::InvalidDataType if data field type provided
    /// as template parameter is not a supported integer type.
87
    /// @todo Extend constructor to set encapsulated option space name.
88
    OptionInt(Option::Universe u, uint16_t type, OptionBufferConstIter begin,
89
               OptionBufferConstIter end)
90
        : Option(u, type) {
91
        if (!OptionDataTypeTraits<T>::integer_type) {
92
            isc_throw(dhcp::InvalidDataType, "non-integer type");
93
        }
94
        setEncapsulatedSpace(u == Option::V4 ? DHCP4_OPTION_SPACE : DHCP6_OPTION_SPACE);
95 96 97
        unpack(begin, end);
    }

98
    /// @brief Copies this option and returns a pointer to the copy.
99 100 101 102
    virtual OptionPtr clone() const {
        return (cloneInternal<OptionInt<T> >());
    }

103 104 105
    /// Writes option in wire-format to buf, returns pointer to first unused
    /// byte after stored option.
    ///
106 107
    /// @param [out] buf buffer (option will be stored here)
    ///
108 109 110
    /// @throw isc::dhcp::InvalidDataType if size of a data field type is not
    /// equal to 1, 2 or 4 bytes. The data type is not checked in this function
    /// because it is checked in a constructor.
111
    void pack(isc::util::OutputBuffer& buf) const {
112 113
        // Pack option header.
        packHeader(buf);
114 115 116
        // Depending on the data type length we use different utility functions
        // writeUint16 or writeUint32 which write the data in the network byte
        // order to the provided buffer. The same functions can be safely used
117
        // for either unsigned or signed integers so there is not need to create
118
        // special cases for intX_t types.
119
        switch (OptionDataTypeTraits<T>::len) {
120 121 122 123 124 125 126 127 128 129
        case 1:
            buf.writeUint8(value_);
            break;
        case 2:
            buf.writeUint16(value_);
            break;
        case 4:
            buf.writeUint32(value_);
            break;
        default:
130
            isc_throw(dhcp::InvalidDataType, "non-integer type");
131
        }
132
        packOptions(buf);
133 134 135 136 137 138 139 140 141
    }

    /// @brief Parses received buffer
    ///
    /// Parses received buffer and returns offset to the first unused byte after
    /// parsed option.
    ///
    /// @param begin iterator to first byte of option data
    /// @param end iterator to end of option data (first byte after option end)
142 143
    ///
    /// @throw isc::OutOfRange if provided buffer is shorter than data size.
144 145 146
    /// @throw isc::dhcp::InvalidDataType if size of a data field type is not
    /// equal to 1, 2 or 4 bytes. The data type is not checked in this function
    /// because it is checked in a constructor.
147 148
    virtual void unpack(OptionBufferConstIter begin, OptionBufferConstIter end) {
        if (distance(begin, end) < sizeof(T)) {
149
            isc_throw(OutOfRange, "OptionInt " << getType() << " truncated");
150
        }
151 152
        // @todo consider what to do if buffer is longer than data type.

153 154 155
        // Depending on the data type length we use different utility functions
        // readUint16 or readUint32 which read the data laid in the network byte
        // order from the provided buffer. The same functions can be safely used
156
        // for either unsigned or signed integers so there is not need to create
157
        // special cases for intX_t types.
158
        int data_size_len = OptionDataTypeTraits<T>::len;
159
        switch (data_size_len) {
160 161 162 163
        case 1:
            value_ = *begin;
            break;
        case 2:
164 165
            value_ = isc::util::readUint16(&(*begin),
                                           std::distance(begin, end));
166 167
            break;
        case 4:
168 169
            value_ = isc::util::readUint32(&(*begin),
                                           std::distance(begin, end));
170 171
            break;
        default:
172
            isc_throw(dhcp::InvalidDataType, "non-integer type");
173
        }
174
        // Use local variable to set a new value for this iterator.
175
        // When using OptionDataTypeTraits<T>::len directly some versions
176
        // of clang complain about unresolved reference to
177
        // OptionDataTypeTraits structure during linking.
178
        begin += data_size_len;
179
        unpackOptions(OptionBuffer(begin, end));
180 181
    }

182 183 184
    /// @brief Set option value.
    ///
    /// @param value new option value.
185 186
    void setValue(T value) { value_ = value; }

187 188 189
    /// @brief Return option value.
    ///
    /// @return option value.
190 191 192 193 194 195 196
    T getValue() const { return value_; }

    /// @brief returns complete length of option
    ///
    /// Returns length of this option, including option header and suboptions
    ///
    /// @return length of this option
197
    virtual uint16_t len() const {
198
        // Calculate the length of the header.
199
        uint16_t length = (getUniverse() == Option::V4) ? OPTION4_HDR_LEN : OPTION6_HDR_LEN;
200 201
        // The data length is equal to size of T.
        length += sizeof(T);;
202
        // length of all suboptions
203
        for (OptionCollection::const_iterator it = options_.begin();
204 205 206 207 208 209 210
             it != options_.end();
             ++it) {
            length += (*it).second->len();
        }
        return (length);
    }

211 212 213 214 215 216
    /// @brief Returns option carrying an integer value in the textual
    /// format.
    ///
    /// The returned value also includes the suboptions if present.
    ///
    /// @param indent Number of spaces to be inserted before the text.
217
    virtual std::string toText(int indent = 0) const {
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
        std::stringstream output;
        output << headerToText(indent) << ": ";

        // For 1 byte long data types we need to cast to the integer
        // because they are usually implemented as "char" types, in
        // which case the character rather than number would be printed.
        if (OptionDataTypeTraits<T>::len == 1) {
            output << static_cast<int>(getValue());
        } else {
            output << getValue();
        }

        // Append data type name.
        output << " ("
               << OptionDataTypeUtil::getDataTypeName(OptionDataTypeTraits<T>::type)
               << ")";

        // Append suboptions.
        output << suboptionsToText(indent + 2);

        return (output.str());
    }

241 242
private:

243
    T value_;  ///< Value conveyed by the option.
244 245 246 247 248
};

} // isc::dhcp namespace
} // isc namespace

249
#endif // OPTION_INT_H