/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 |