Coverage Report

Created: 2026-06-30 07:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/kea/src/lib/dhcp/opaque_data_tuple.h
Line
Count
Source
1
// Copyright (C) 2014-2024 Internet Systems Consortium, Inc. ("ISC")
2
//
3
// This Source Code Form is subject to the terms of the Mozilla Public
4
// License, v. 2.0. If a copy of the MPL was not distributed with this
5
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7
#ifndef OPAQUE_DATA_TUPLE_H
8
#define OPAQUE_DATA_TUPLE_H
9
10
#include <dhcp/option.h>
11
#include <util/buffer.h>
12
13
#include <iostream>
14
#include <iterator>
15
#include <string>
16
#include <vector>
17
18
namespace isc {
19
namespace dhcp {
20
21
/// @brief Exception to be thrown when the operation on @c OpaqueDataTuple
22
/// object results in an error.
23
class OpaqueDataTupleError : public Exception {
24
public:
25
    OpaqueDataTupleError(const char* file, size_t line, const char* what) :
26
7.44k
        isc::Exception(file, line, what) { }
27
};
28
29
30
/// @brief Represents a single instance of the opaque data preceded by length.
31
///
32
/// Some of the DHCP options, such as Vendor Class option (16) in DHCPv6 or
33
/// V-I Vendor Class option (124) in DHCPv4 may carry multiple pairs of
34
/// opaque-data preceded by its length. Such pairs are called tuples. This class
35
/// represents a single instance of the tuple in the DHCPv4 or DHCPv6 option.
36
///
37
/// Although, the primary purpose of this class is to represent data tuples in
38
/// Vendor Class options, there may be other options defined in the future that
39
/// may have similar structure and this class can be used to represent the data
40
/// tuples in these new options too.
41
///
42
/// This class exposes a set of convenience methods to assign and retrieve the
43
/// opaque data from the tuple. It also implements a method to render the tuple
44
/// data into a wire format, as well as a method to create an instance of the
45
/// tuple from the wire format.
46
class OpaqueDataTuple {
47
public:
48
49
    /// @brief Size of the length field in the tuple.
50
    ///
51
    /// In the wire format, the tuple consists of the two fields: one holding
52
    /// a length of the opaque data size, second holding opaque data. The first
53
    /// field's size may be equal to 1 or 2 bytes. Usually, the tuples carried
54
    /// in the DHCPv6 options have 2 byte long length fields, the tuples carried
55
    /// in DHCPv4 options have 1 byte long length fields.
56
    enum LengthFieldType {
57
        LENGTH_EMPTY = -1,
58
        LENGTH_1_BYTE,
59
        LENGTH_2_BYTES
60
    };
61
62
    /// @brief Defines a type of the data buffer used to hold the opaque data.
63
    using Buffer = std::vector<uint8_t>;
64
    using InputIterator = Buffer::const_iterator;
65
66
    /// @brief Default constructor.
67
    ///
68
    /// @param length_field_type Indicates a length of the field which holds
69
    /// the size of the tuple.
70
    OpaqueDataTuple(LengthFieldType length_field_type);
71
72
    /// @brief Constructor
73
    ///
74
    /// Creates a tuple from on-wire data. It calls @c OpaqueDataTuple::unpack
75
    /// internally.
76
    ///
77
    /// @param length_field_type Indicates the length of the field holding the
78
    /// opaque data size.
79
    /// @param begin Iterator pointing to the beginning of the buffer holding
80
    /// wire data.
81
    /// @param end Iterator pointing to the end of the buffer holding wire data.
82
    /// @throw It may throw an exception if the @c unpack throws.
83
    OpaqueDataTuple(LengthFieldType length_field_type,
84
                    InputIterator begin,
85
                    InputIterator end)
86
11.7M
        : length_field_type_(length_field_type) {
87
11.7M
        unpack(begin, end);
88
11.7M
    }
89
90
    /// @brief Appends data to the tuple.
91
    ///
92
    /// This function appends the data of the specified length to the tuple.
93
    /// If the specified buffer length is greater than the size of the buffer,
94
    /// the behavior of this function is undefined.
95
    ///
96
    /// @param data Iterator pointing to the beginning of the buffer being
97
    /// appended. The source buffer may be an STL object or an array of
98
    /// characters. In the latter case, the pointer to the beginning of this
99
    /// array should be passed.
100
    /// @param len Length of the source buffer.
101
    /// @tparam InputIterator Type of the iterator pointing to the beginning of
102
    /// the source buffer.
103
0
    void append(const char* data, const size_t len) {
104
0
        data_.insert(data_.end(), data, data + len);
105
0
    }
106
881
    void append(const uint8_t* data, const size_t len) {
107
881
        data_.insert(data_.end(), data, data + len);
108
881
    }
109
4.36k
    void append(InputIterator data, const size_t len) {
110
4.36k
        data_.insert(data_.end(), data, data + len);
111
4.36k
    }
112
113
    /// @brief Appends string to the tuple.
114
    ///
115
    /// In most cases, the tuple will carry a string. This function appends the
116
    /// string to the tuple.
117
    ///
118
    /// @param text String to be appended in the tuple.
119
    void append(const std::string& text);
120
121
    /// @brief Assigns data to the tuple.
122
    ///
123
    /// This function replaces existing data in the tuple with the new data.
124
    /// If the specified buffer length is greater than the size of the buffer,
125
    /// the behavior of this function is undefined.
126
    /// @param data Iterator pointing to the beginning of the buffer being
127
    /// assigned. The source buffer may be an STL object or an array of
128
    /// characters. In the latter case, the pointer to the beginning of this
129
    /// array should be passed.
130
    /// @param len Length of the source buffer.
131
0
    void assign(const char* data, const size_t len) {
132
0
        data_.assign(data, data + len);
133
0
    }
134
12.3M
    void assign(InputIterator data, const size_t len) {
135
12.3M
        data_.assign(data, data + len);
136
12.3M
    }
137
138
    /// @brief Assigns string data to the tuple.
139
    ///
140
    /// In most cases, the tuple will carry a string. This function sets the
141
    /// string to the tuple.
142
    ///
143
    /// @param text String to be assigned to the tuple.
144
    void assign(const std::string& text);
145
146
    /// @brief Removes the contents of the tuple.
147
    void clear();
148
149
    /// @brief Checks if the data carried in the tuple match the string.
150
    ///
151
    /// @param other String to compare tuple data against.
152
    bool equals(const std::string& other) const;
153
154
    /// @brief Returns tuple length data field type.
155
11.6M
    LengthFieldType getLengthFieldType() const {
156
11.6M
        return (length_field_type_);
157
11.6M
    }
158
159
    /// @brief Returns the length of the data in the tuple.
160
12.8M
    size_t getLength() const {
161
12.8M
        return (data_.size());
162
12.8M
    }
163
164
    /// @brief Returns a total size of the tuple, including length field.
165
12.0M
    size_t getTotalLength() const {
166
12.0M
        return (getDataFieldSize() + getLength());
167
12.0M
    }
168
169
    /// @brief Returns a reference to the buffer holding tuple data.
170
    ///
171
    /// @warning The returned reference is valid only within the lifetime
172
    /// of the object which returned it. The use of the returned reference
173
    /// after the object has been destroyed yelds undefined behavior.
174
567k
    const Buffer& getData() const {
175
567k
        return (data_);
176
567k
    }
177
178
    /// @brief Return the tuple data in the textual format.
179
    std::string getText() const;
180
181
    /// @brief Renders the tuple to a buffer in the wire format.
182
    ///
183
    /// This function creates the following wire representation of the tuple:
184
    /// - 1 or 2 bytes holding a length of the data.
185
    /// - variable number of bytes holding data.
186
    /// and writes it to the specified buffer. The new are appended to the
187
    /// buffer, so as data existing in the buffer is preserved.
188
    ///
189
    /// The tuple is considered malformed if one of the following occurs:
190
    /// - the size of the data is 0 (tuple is empty),
191
    /// - the size of the data is greater than 255 and the size of the length
192
    /// field is 1 byte (see @c LengthFieldType).
193
    /// - the size of the data is greater than 65535 and the size of the length
194
    /// field is 2 bytes (see @c LengthFieldType).
195
    ///
196
    /// Function will throw an exception if trying to render malformed tuple.
197
    ///
198
    /// @param [out] buf Buffer to which the data is rendered.
199
    ///
200
    /// @throw OpaqueDataTupleError if failed to render the data to the
201
    /// buffer because the tuple is malformed.
202
    void pack(isc::util::OutputBuffer& buf) const;
203
204
    /// @brief Parses wire data and creates a tuple from it.
205
    ///
206
    /// This function parses on-wire data stored in the provided buffer and
207
    /// stores it in the tuple object. The wire data must include at least the
208
    /// data field of the length matching the specified @c LengthFieldType.
209
    /// The remaining buffer length (excluding the length field) must be equal
210
    /// or greater than the length carried in the length field. If any of these
211
    /// two conditions is not met, an exception is thrown.
212
    ///
213
    /// This function allows opaque data with the length of 0.
214
    ///
215
    /// @param begin Iterator pointing to the beginning of the buffer holding
216
    /// wire data.
217
    /// @param end Iterator pointing to the end of the buffer holding wire data.
218
    /// @tparam InputIterator Type of the iterators passed to this function.
219
    void unpack(InputIterator begin, InputIterator end);
220
221
    /// @name Assignment and comparison operators.
222
    //{@
223
224
    /// @brief Assignment operator.
225
    ///
226
    /// This operator assigns the string data to the tuple.
227
    ///
228
    /// @param other string to be assigned to the tuple.
229
    /// @return Tuple object after assignment.
230
    OpaqueDataTuple& operator=(const std::string& other);
231
232
    /// @brief Equality operator.
233
    ///
234
    /// This operator compares the string given as an argument to the data
235
    /// carried in the tuple in the textual format.
236
    ///
237
    /// @param other String to compare the tuple against.
238
    /// @return true if data carried in the tuple is equal to the string.
239
    bool operator==(const std::string& other) const;
240
241
    /// @brief Inequality operator.
242
    ///
243
    /// This operator compares the string given as an argument to the data
244
    /// carried in the tuple for inequality.
245
    ///
246
    /// @param other String to compare the tuple against.
247
    /// @return true if the data carried in the tuple is unequal the given
248
    /// string.
249
    bool operator!=(const std::string& other);
250
    //@}
251
252
    /// @brief Returns the size of the tuple length field.
253
    ///
254
    /// The returned value depends on the @c LengthFieldType set for the tuple.
255
    int getDataFieldSize() const;
256
257
private:
258
259
    /// @brief Buffer which holds the opaque tuple data.
260
    Buffer data_;
261
262
    /// @brief Holds a type of tuple size field (1 byte long or 2 bytes long).
263
    LengthFieldType length_field_type_;
264
};
265
266
/// @brief Pointer to the @c OpaqueDataTuple object.
267
typedef boost::shared_ptr<OpaqueDataTuple> OpaqueDataTuplePtr;
268
269
/// @brief Inserts the @c OpaqueDataTuple as a string into stream.
270
///
271
/// This operator gets the tuple data in the textual format and inserts it
272
/// into the output stream.
273
///
274
/// @param os Stream object on which insertion is performed.
275
/// @param tuple Object encapsulating a tuple which data in the textual format
276
/// is inserted into the stream.
277
/// @return Reference to the same stream but after insertion operation.
278
std::ostream& operator<<(std::ostream& os, const OpaqueDataTuple& tuple);
279
280
/// @brief Inserts data carried in the stream into the tuple.
281
///
282
/// this operator inserts data carried in the input stream and inserts it to
283
/// the @c OpaqueDataTuple object. The existing data is replaced with new data.
284
///
285
/// @param is Input stream from which the data will be inserted.
286
/// @param tuple @c OpaqueDataTuple object to which the data will be inserted.
287
/// @return Input stream after insertion to the tuple is performed.
288
std::istream& operator>>(std::istream& is, OpaqueDataTuple& tuple);
289
290
} // namespace isc::dhcp
291
} // namespace isc
292
293
#endif