123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319 |
- // Copyright (C) 2014 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 OPAQUE_DATA_TUPLE_H
- #define OPAQUE_DATA_TUPLE_H
- #include <util/buffer.h>
- #include <util/io_utilities.h>
- #include <iostream>
- #include <iterator>
- #include <string>
- #include <vector>
- namespace isc {
- namespace dhcp {
- /// @brief Exception to be thrown when the operation on @c OpaqueDataTuple
- /// object results in an error.
- class OpaqueDataTupleError : public Exception {
- public:
- OpaqueDataTupleError(const char* file, size_t line, const char* what) :
- isc::Exception(file, line, what) { };
- };
- /// @brief Represents a single instance of the opaque data preceded by length.
- ///
- /// Some of the DHCP options, such as Vendor Class option (16) in DHCPv6 or
- /// V-I Vendor Class option (124) in DHCPv4 may carry multiple pairs of
- /// opaque-data preceded by its length. Such pairs are called tuples. This class
- /// represents a single instance of the tuple in the DHCPv4 or DHCPv6 option.
- ///
- /// Although, the primary purpose of this class is to represent data tuples in
- /// Vendor Class options, there may be other options defined in the future that
- /// may have similar structure and this class can be used to represent the data
- /// tuples in these new options too.
- ///
- /// This class exposes a set of convenience methods to assign and retrieve the
- /// opaque data from the tuple. It also implements a method to render the tuple
- /// data into a wire format, as well as a method to create an instance of the
- /// tuple from the wire format.
- class OpaqueDataTuple {
- public:
- /// @brief Size of the length field in the tuple.
- ///
- /// In the wire format, the tuple consists of the two fields: one holding
- /// a length of the opaque data size, second holding opaque data. The first
- /// field's size may be equal to 1 or 2 bytes. Usually, the tuples carried
- /// in the DHCPv6 options have 2 byte long length fields, the tuples carried
- /// in DHCPv4 options have 1 byte long length fields.
- enum LengthFieldType {
- LENGTH_1_BYTE,
- LENGTH_2_BYTES
- };
- /// @brief Defines a type of the data buffer used to hold the opaque data.
- typedef std::vector<uint8_t> Buffer;
- /// @brief Default constructor.
- ///
- /// @param length_field_type Indicates a length of the field which holds
- /// the size of the tuple.
- OpaqueDataTuple(LengthFieldType length_field_type);
- /// @brief Constructor
- ///
- /// Creates a tuple from on-wire data. It calls @c OpaqueDataTuple::unpack
- /// internally.
- ///
- /// @param length_field_type Indicates the length of the field holding the
- /// opaque data size.
- /// @param begin Iterator pointing to the beginning of the buffer holding
- /// wire data.
- /// @param end Iterator pointing to the end of the buffer holding wire data.
- /// @tparam InputIterator Type of the iterators passed to this function.
- /// @throw It may throw an exception if the @c unpack throws.
- template<typename InputIterator>
- OpaqueDataTuple(LengthFieldType length_field_type, InputIterator begin,
- InputIterator end)
- : length_field_type_(length_field_type) {
- unpack(begin, end);
- }
- /// @brief Appends data to the tuple.
- ///
- /// This function appends the data of the specified length to the tuple.
- /// If the specified buffer length is greater than the size of the buffer,
- /// the behavior of this function is undefined.
- ///
- /// @param data Iterator pointing to the beginning of the buffer being
- /// appended. The source buffer may be an STL object or an array of
- /// characters. In the latter case, the pointer to the beginning of this
- /// array should be passed.
- /// @param len Length of the source buffer.
- /// @tparam InputIterator Type of the iterator pointing to the beginning of
- /// the source buffer.
- template<typename InputIterator>
- void append(InputIterator data, const size_t len) {
- data_.insert(data_.end(), data, data + len);
- }
- /// @brief Appends string to the tuple.
- ///
- /// In most cases, the tuple will carry a string. This function appends the
- /// string to the tuple.
- ///
- /// @param text String to be appended in the tuple.
- void append(const std::string& text);
- /// @brief Assigns data to the tuple.
- ///
- /// This function replaces existing data in the tuple with the new data.
- /// If the speficified buffer length is greater than the size of the buffer,
- /// the behavior of this function is undefined.
- /// @param data Iterator pointing to the beginning of the buffer being
- /// assigned. The source buffer may be an STL object or an array of
- /// characters. In the latter case, the pointer to the beginning of this
- /// array should be passed.
- /// @param len Length of the source buffer.
- /// @tparam InputIterator Type of the iterator pointing to the beginning of
- /// the source buffer.
- template<typename InputIterator>
- void assign(InputIterator data, const size_t len) {
- data_.assign(data, data + len);
- }
- /// @brief Assigns string data to the tuple.
- ///
- /// In most cases, the tuple will carry a string. This function sets the
- /// string to the tuple.
- ///
- /// @param text String to be assigned to the tuple.
- void assign(const std::string& text);
- /// @brief Removes the contents of the tuple.
- void clear();
- /// @brief Checks if the data carried in the tuple match the string.
- ///
- /// @param other String to compare tuple data against.
- bool equals(const std::string& other) const;
- /// @brief Returns tuple length data field type.
- LengthFieldType getLengthFieldType() const {
- return (length_field_type_);
- }
- /// @brief Returns the length of the data in the tuple.
- size_t getLength() const {
- return (data_.size());
- }
- /// @brief Returns a total size of the tuple, including length field.
- size_t getTotalLength() const {
- return (getDataFieldSize() + getLength());
- }
- /// @brief Returns a reference to the buffer holding tuple data.
- ///
- /// @warning The returned reference is valid only within the lifetime
- /// of the object which returned it. The use of the returned reference
- /// after the object has been destroyed yelds undefined behavior.
- const Buffer& getData() const {
- return (data_);
- }
- /// @brief Return the tuple data in the textual format.
- std::string getText() const;
- /// @brief Renders the tuple to a buffer in the wire format.
- ///
- /// This function creates the following wire representation of the tuple:
- /// - 1 or 2 bytes holding a length of the data.
- /// - variable number of bytes holding data.
- /// and writes it to the specified buffer. The new are appended to the
- /// buffer, so as data existing in the buffer is preserved.
- ///
- /// The tuple is considered malformed if one of the follwing occurs:
- /// - the size of the data is 0 (tuple is empty),
- /// - the size of the data is greater than 255 and the size of the length
- /// field is 1 byte (see @c LengthFieldType).
- /// - the size of the data is greater than 65535 and the size of the length
- /// field is 2 bytes (see @c LengthFieldType).
- ///
- /// Function will throw an exception if trying to render malformed tuple.
- ///
- /// @param [out] buf Buffer to which the data is rendered.
- ///
- /// @throw OpaqueDataTupleError if failed to render the data to the
- /// buffer because the tuple is malformed.
- void pack(isc::util::OutputBuffer& buf) const;
- /// @brief Parses wire data and creates a tuple from it.
- ///
- /// This function parses on-wire data stored in the provided buffer and
- /// stores it in the tuple object. The wire data must include at least the
- /// data field of the length matching the specified @c LengthFieldType.
- /// The remaining buffer length (excluding the length field) must be equal
- /// or greater than the length carried in the length field. If any of these
- /// two conditions is not met, an exception is thrown.
- ///
- /// This function allows opaque data with the length of 0.
- ///
- /// @param begin Iterator pointing to the beginning of the buffer holding
- /// wire data.
- /// @param end Iterator pointing to the end of the buffer holding wire data.
- /// @tparam InputIterator Type of the iterators passed to this function.
- template<typename InputIterator>
- void unpack(InputIterator begin, InputIterator end) {
- Buffer buf(begin, end);
- // The buffer must at least hold the size of the data.
- if (std::distance(begin, end) < getDataFieldSize()) {
- isc_throw(OpaqueDataTupleError,
- "unable to parse the opaque data tuple, the buffer"
- " length is " << std::distance(begin, end)
- << ", expected at least " << getDataFieldSize());
- }
- // Read the data length from the length field, depending on the
- // size of the data field (1 or 2 bytes).
- size_t len = getDataFieldSize() == 1 ? *begin :
- isc::util::readUint16(&(*begin), std::distance(begin, end));
- // Now that we have the expected data size, let's check that the
- // reminder of the buffer is long enough.
- begin += getDataFieldSize();
- if (std::distance(begin, end) < len) {
- isc_throw(OpaqueDataTupleError,
- "unable to parse the opaque data tuple, the buffer"
- " length is " << std::distance(begin, end)
- << ", but the length of the tuple in the length field"
- " is " << len);
- }
- // The buffer length is long enough to read the desired amount of data.
- assign(begin, len);
- }
- /// @name Assignment and comparison operators.
- //{@
- /// @brief Assignment operator.
- ///
- /// This operator assigns the string data to the tuple.
- ///
- /// @param other string to be assigned to the tuple.
- /// @return Tuple object after assignment.
- OpaqueDataTuple& operator=(const std::string& other);
- /// @brief Equality operator.
- ///
- /// This operator compares the string given as an argument to the data
- /// carried in the tuple in the textual format.
- ///
- /// @param other String to compare the tuple against.
- /// @return true if data carried in the tuple is equal to the string.
- bool operator==(const std::string& other) const;
- /// @brief Inequality operator.
- ///
- /// This operator compares the string given as an argument to the data
- /// carried in the tuple for inequality.
- ///
- /// @param other String to compare the tuple against.
- /// @return true if the data carried in the tuple is unequal the given
- /// string.
- bool operator!=(const std::string& other);
- //@}
- /// @brief Returns the size of the tuple length field.
- ///
- /// The returned value depends on the @c LengthFieldType set for the tuple.
- int getDataFieldSize() const;
- private:
- /// @brief Buffer which holds the opaque tuple data.
- Buffer data_;
- /// @brief Holds a type of tuple size field (1 byte long or 2 bytes long).
- LengthFieldType length_field_type_;
- };
- /// @brief Pointer to the @c OpaqueDataTuple object.
- typedef boost::shared_ptr<OpaqueDataTuple> OpaqueDataTuplePtr;
- /// @brief Inserts the @c OpaqueDataTuple as a string into stream.
- ///
- /// This operator gets the tuple data in the textual format and inserts it
- /// into the output stream.
- ///
- /// @param os Stream object on which insertion is performed.
- /// @param tuple Object encapsulating a tuple which data in the textual format
- /// is inserted into the stream.
- /// @return Reference to the same stream but after insertion operation.
- std::ostream& operator<<(std::ostream& os, const OpaqueDataTuple& tuple);
- /// @brief Inserts data carried in the stream into the tuple.
- ///
- /// this operator inserts data carried in the input stream and inserts it to
- /// the @c OpaqueDataTuple object. The existing data is replaced with new data.
- ///
- /// @param is Input stream from which the data will be inserted.
- /// @param tuple @c OpaqueDataTuple object to which the data will be inserted.
- /// @return Input stream after insertion to the tuple is performed.
- std::istream& operator>>(std::istream& is, OpaqueDataTuple& tuple);
- } // namespace isc::dhcp
- } // namespace isc
- #endif
|