ipaddress 1.2.0
Loading...
Searching...
No Matches
errors.hpp
Go to the documentation of this file.
1/**
2 * @file errors.hpp
3 * @brief Declares error codes and exceptions for IP address operations
4 * @author Vladimir Shaleev
5 * @copyright MIT License
6 *
7 * This header file is part of an IP address processing library and is responsible
8 * for defining error codes and exceptions that represent various failure states
9 * encountered during IP address parsing and processing. It includes an enumeration
10 * of error codes that cover a range of issues from syntactical errors in IP address
11 * strings to logical inconsistencies in network operations. Additionally, the file
12 * declares a base exception class tailored to encapsulate these error codes along
13 * with descriptive messages, facilitating precise error handling and reporting.
14 *
15 * The error codes are categorized into general parsing errors, IPv4-specific errors,
16 * IPv6-specific errors, and logical errors, each with a brief description of the
17 * condition they represent. The base exception class, `error`, inherits from the
18 * standard `std::runtime_error` and is constructed with an error code and a message,
19 * allowing exceptions to carry both a machine-readable identifier and a human-readable
20 * explanation.
21 *
22 * The file also includes a function template that converts an error code into an
23 * exception, streamlining the process of throwing exceptions upon encountering
24 * errors during IP address operations. This design ensures that all potential error
25 * conditions are accounted for and can be handled gracefully by client code using
26 * the library.
27 */
28
29#ifndef IPADDRESS_ERRORS_HPP
30#define IPADDRESS_ERRORS_HPP
31
32#include "config.hpp"
33
34namespace IPADDRESS_NAMESPACE {
35
36/**
37 * Enumeration of error codes for IP address parsing and validation.
38 *
39 * This enumeration defines a set of error codes used to represent various error conditions
40 * that can occur during the parsing and validation of IP addresses. These error codes are
41 * used to provide detailed feedback about the nature of the error encountered, allowing
42 * for more precise error handling and troubleshooting.
43 *
44 * The error codes are divided into several categories:
45 * - General errors related to the overall format and structure of the IP address.
46 * - IPv4-specific errors that address the unique syntactical requirements of IPv4 addresses.
47 * - IPv6-specific errors that address the unique syntactical requirements of IPv6 addresses.
48 * - Logical errors that represent inconsistencies or invalid operations in network calculations.
49 *
50 * Each error code is accompanied by a brief comment explaining the specific error condition it represents.
51 */
53 no_error = 0, /**< Indicates the absence of any errors. */
54 empty_address, /**< The IP address string is empty when it should contain a valid address. */
55 empty_netmask, /**< The netmask portion of the address is empty when it should specify a valid netmask. */
56 invalid_netmask, /**< The provided netmask is not valid according to standard netmask formatting rules. */
57 netmask_pattern_mixes_zeroes_and_ones, /**< The netmask contains an invalid pattern of zeroes and ones. */
58 has_host_bits_set, /**< The address has host bits set when they are expected to be clear. */
59 only_one_slash_permitted, /**< Only one slash character is permitted, used to separate the address from the netmask. */
60 string_is_too_long, /**< Input string is too long. */
61 unexpected_symbol, /**< The input string contains an unexpected character. */
62 wrong_encoding_sequence, /**< Incorrect byte sequence in Unicode encoding. */
63
64 // ipv4 errors
65 empty_octet, /**< An octet in the IPv4 address is empty when it should contain a numeric value. */
66 expected_4_octets, /**< The IPv4 address does not contain the expected four octets. */
67 leading_0_are_not_permitted, /**< Leading zeroes are not permitted in any octet of the IPv4 address. */
68 octet_more_3_characters, /**< An octet contains more than three characters, exceeding the maximum allowed. */
69 octet_has_invalid_symbol, /**< An octet contains characters other than digits, which are invalid. */
70 octet_exceeded_255, /**< An octet's value exceeds the maximum allowed value of 255. */
71
72 // ipv6 errors
73 least_3_parts, /**< The IPv6 address contains fewer than the minimum required parts. */
74 most_8_colons_permitted, /**< The IPv6 address contains more than the maximum allowed number of colons. */
75 part_is_more_4_chars, /**< A part of the IPv6 address contains more than four characters. */
76 part_has_invalid_symbol, /**< A part of the IPv6 address contains invalid characters. */
77 most_one_double_colon_permitted, /**< More than one double colon is present in the IPv6 address. */
78 leading_colon_only_permitted_as_part_of_double_colon, /**< A leading colon is only permitted as part of a double colon. */
79 trailing_colon_only_permitted_as_part_of_double_colon, /**< A trailing colon is only permitted as part of a double colon. */
80 expected_at_most_7_other_parts_with_double_colon, /**< With a double colon present, at most seven other parts are expected. */
81 exactly_8_parts_expected_without_double_colon, /**< Without a double colon, exactly eight parts are expected. */
82 scope_id_is_too_long, /**< The scope ID in the IPv6 address exceeds the maximum length. */
83 invalid_scope_id, /**< The scope ID in the IPv6 address is invalid. If for some reason you need to add whitespace support to the scope id, add the following definition IPADDRESS_SCOPE_ID_SUPPORT_SPACES */
84
85 // logic errors
86 invalid_version, /**< The IP address version does not match the expected version. */
87 invalid_prefixlen_diff, /**< The difference in prefix length is invalid for the operation being performed. */
88 new_prefix_must_be_shorter, /**< The new prefix length must be shorter for the operation being performed. */
89 new_prefix_must_be_longer, /**< The new prefix length must be longer for the operation being performed. */
90 cannot_set_prefixlen_diff_and_new_prefix, /**< Both prefix length difference and new prefix cannot be set simultaneously. */
91 not_contained_network, /**< The network is not a subnet of the other network as expected. */
92 last_address_must_be_greater_than_first /**< The last IP address in the range must be greater than the first IP address. */
93};
94
95/**
96 * The primary exception class used by the IP address library.
97 *
98 * This class extends the standard `std::runtime_error` and serves as the base exception
99 * type for the library. It is designed to be thrown when an error condition is encountered
100 * during the processing of IP addresses, such as parsing errors or logical inconsistencies.
101 *
102 * The `error` class encapsulates an `error_code` value representing the specific error
103 * that occurred, along with a descriptive message that provides context about the error.
104 * This design allows for precise and informative error reporting, aiding in debugging
105 * and error handling.
106 *
107 * Overall, the `error` class is a critical component of the library's error management
108 * system, providing a standardized way to handle exceptions throughout the library.
109 *
110 * @sa parse_error
111 * @sa logic_error
112 */
113IPADDRESS_EXPORT class error : public std::runtime_error {
114public:
115 /**
116 * Constructs an error with a code and a concatenated message from multiple arguments.
117 *
118 * @tparam FirstArg The type of the first argument passed to the constructor.
119 * @tparam Args The types of the additional arguments passed to the constructor.
120 * @param[in] code The error code associated with the exception.
121 * @param[in] arg The first argument describing the error.
122 * @param[in] args Additional arguments describing the error.
123 */
124 template <typename FirstArg, typename... Args>
125 explicit error(error_code code, const FirstArg& arg, const Args&... args) : std::runtime_error(concatenate(arg, args...)), _code(code) {
126 }
127
128 /**
129 * Constructs an error with a code and a message string.
130 *
131 * @param[in] code The error code associated with the exception.
132 * @param[in] message A detailed description of the error.
133 */
134 explicit error(error_code code, const std::string& message) : std::runtime_error(message), _code(code) {
135 }
136
137 /**
138 * Constructs an error with a code and a message C-string.
139 *
140 * @param[in] code The error code associated with the exception.
141 * @param[in] message A detailed description of the error.
142 */
143 explicit error(error_code code, const char* message) : std::runtime_error(message), _code(code) {
144 }
145
146 /**
147 * Returns the error code associated with this error.
148 *
149 * @return The error code that represents the specific error condition.
150 */
152 return _code;
153 }
154
155 struct symbol {
156 uint32_t value;
157 };
158
159private:
160 template <typename... Args>
161 static std::string concatenate(const Args&... args) {
162 std::ostringstream ss;
163 concat(ss, args...);
164 return ss.str();
165 }
166
167 template <typename FirstArg, typename... Args>
168 static void concat(std::ostringstream& out, const FirstArg& arg, const Args&... args) {
169 print(out, arg) << ' ';
170 concat(out, args...);
171 }
172
173 template <typename FirstArg>
174 static void concat(std::ostringstream& out, const FirstArg& arg) {
175 print(out, arg);
176 }
177
178 template <typename T>
179 static std::ostringstream& print(std::ostringstream& out, const T& arg) {
180 out << arg;
181 return out;
182 }
183
184 static std::ostringstream& print(std::ostringstream& out, const symbol& arg);
185
186 template <typename T, size_t N>
187 static std::ostringstream& print(std::ostringstream& out, const T (&str)[N]);
188
189 error_code _code;
190};
191
192/**
193 * Exception for errors encountered during IP address parsing.
194 *
195 * This exception is thrown when the library encounters an error while
196 * attempting to parse an IP address or network from a string. It is a
197 * specialized form of the `error` class that provides context specific
198 * to parsing operations.
199 *
200 * @sa error
201 */
203public:
204 /**
205 * Constructs a parsing error with a code and a concatenated message from multiple arguments.
206 *
207 * @tparam FirstArg The type of the first argument passed to the constructor.
208 * @tparam Args The types of the additional arguments passed to the constructor.
209 * @param[in] code The error code associated with the parsing exception.
210 * @param[in] arg The first argument describing the error.
211 * @param[in] args Additional arguments describing the error.
212 */
213 template <typename FirstArg, typename... Args>
214 explicit parse_error(error_code code, const FirstArg& arg, const Args&... args) : error(code, arg, args...) {
215 }
216
217 /**
218 * Constructs a parsing error with a code and a message string.
219 *
220 * @param[in] code The error code associated with the parsing exception.
221 * @param[in] message A detailed description of the parsing error.
222 */
223 explicit parse_error(error_code code, const std::string& message) : error(code, message) {
224 }
225
226 /**
227 * Constructs a parsing error with a code and a message C-string.
228 *
229 * @param[in] code The error code associated with the parsing exception.
230 * @param[in] message A detailed description of the parsing error.
231 */
232 explicit parse_error(error_code code, const char* message) : error(code, message) {
233 }
234};
235
236/**
237 * Exception for logical errors in IP address operations.
238 *
239 * This exception is thrown for logical errors that do not pertain directly
240 * to parsing, such as using an incorrect prefix length or other operations
241 * that violate the logic of IP address manipulation. It extends the `error`
242 * class to provide additional context for these types of logical issues.
243 *
244 * @sa error
245 */
247public:
248 /**
249 * Constructs a logic error with a code and a concatenated message from multiple arguments.
250 *
251 * @tparam FirstArg The type of the first argument passed to the constructor.
252 * @tparam Args The types of the additional arguments passed to the constructor.
253 * @param[in] code The error code associated with the logical exception.
254 * @param[in] arg The first argument describing the error.
255 * @param[in] args Additional arguments describing the error.
256 */
257 template <typename FirstArg, typename... Args>
258 explicit logic_error(error_code code, const FirstArg& arg, const Args&... args) : error(code, arg, args...) {
259 }
260
261 /**
262 * Constructs a logic error with a code and a message string.
263 *
264 * @param[in] code The error code associated with the logical exception.
265 * @param[in] message A detailed description of the logical error.
266 */
267 explicit logic_error(error_code code, const std::string& message) : error(code, message) {
268 }
269
270 /**
271 * Constructs a logic error with a code and a message C-string.
272 *
273 * @param[in] code The error code associated with the logical exception.
274 * @param[in] message A detailed description of the logical error.
275 */
276 explicit logic_error(error_code code, const char* message) : error(code, message) {
277 }
278};
279
280/**
281 * Raises an error with a specific error code and additional context.
282 *
283 * This function constructs an error message based on the provided error code,
284 * value, and address, then throws a parse_error or a logic_error exception with the constructed message.
285 *
286 * @tparam T The character type of the address string.
287 * @param[in] code The error code indicating the type of error encountered.
288 * @param[in] value The value at which the error occurred, if applicable.
289 * @param[in] address A pointer to the beginning of the address string.
290 * @param[in] length The length of the address string.
291 * @throw parse_error Thrown with a message corresponding to the error code.
292 * @throw logic_error Thrown with a message corresponding to the error code.
293 * @note This function is marked [[noreturn]] as it always throws an exception.
294 */
295IPADDRESS_EXPORT template <typename T>
296#ifndef IPADDRESS_NO_EXCEPTIONS
297[[noreturn]]
298#endif
299IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE void raise_error(error_code code, uint32_t value, const T* address, size_t length) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
300#ifndef IPADDRESS_NO_EXCEPTIONS
301 T str[104] = {};
302 size_t max_len = length;
303 if (length > 100) {
304 max_len = 100;
305 }
306 for (size_t i = 0; i < max_len; ++i) {
307 str[i] = address[i];
308 }
309 if (length > 100) {
310 str[100] = '.';
311 str[101] = '.';
312 str[102] = '.';
313 }
314 switch (code) {
316 throw parse_error(code, "address cannot be empty");
318 throw parse_error(code, "empty mask in address", str);
320 throw parse_error(code, "is not a valid netmask in address", str);
322 throw parse_error(code, "netmask pattern mixes zeroes & ones in address", str);
324 throw parse_error(code, "has host bits set in address", str);
326 throw parse_error(code, "only one '/' permitted in address", str);
328 throw parse_error(code, "input string is too long", str);
330 throw parse_error(code, "unexpected next unicode symbol", error::symbol { value }, "in string", str);
332 throw parse_error(code, "incorrect sequence of bytes in unicode encoding for string", str);
334 throw parse_error(code, "empty octet", value, "in address", str);
336 throw parse_error(code, "expected 4 octets in", str);
338 throw parse_error(code, "leading zeros are not permitted in octet", value, "of address", str);
340 throw parse_error(code, "in octet", value, "of address", str, "more 3 characters");
342 throw parse_error(code, "in octet", value, "of address", str, "has invalid symbol");
344 throw parse_error(code, "octet", value, "of address", str, "exceeded 255");
346 throw parse_error(code, "least 3 parts in address", str);
348 throw parse_error(code, "most 8 colons permitted in address", str);
350 throw parse_error(code, "in part", value, "of address", str, "more 4 characters");
352 throw parse_error(code, "in part", value, "of address", str, "has invalid symbols");
354 throw parse_error(code, "at most one '::' permitted in address", str);
356 throw parse_error(code, "at leading ':' only permitted as part of '::' in address", str);
358 throw parse_error(code, "at trailing ':' only permitted as part of '::' in address", str);
360 throw parse_error(code, "expected at most 7 other parts with '::' in address", str);
362 throw parse_error(code, "exactly 8 parts expected without '::' in address", str);
364 throw parse_error(code, "scope id is too long in address", str);
366 throw parse_error(code, "invalid scope id in address", str);
368 throw logic_error(code, "versions don't match");
370 throw logic_error(code, "invalid prefixlen_diff");
372 throw logic_error(code, "new prefix must be shorter");
374 throw logic_error(code, "new prefix must be longer");
376 throw logic_error(code, "cannot set prefixlen_diff and new_prefix");
378 throw logic_error(code, "network is not a subnet of other");
380 throw logic_error(code, "last address must be greater than first");
381 default:
382 throw error(code, "unknown error");
383 }
384#else
385 if (IPADDRESS_IS_CONST_EVALUATED(length)) {
386 const auto _err = int(code) / (int(code) - int(code)); // invalid input string
387 }
388#endif
389}
390
391} // namespace IPADDRESS_NAMESPACE
392
393#endif // IPADDRESS_ERRORS_HPP
The primary exception class used by the IP address library.
Definition errors.hpp:113
error_code code() const noexcept
Returns the error code associated with this error.
Definition errors.hpp:151
error(error_code code, const char *message)
Constructs an error with a code and a message C-string.
Definition errors.hpp:143
error(error_code code, const std::string &message)
Constructs an error with a code and a message string.
Definition errors.hpp:134
error(error_code code, const FirstArg &arg, const Args &... args)
Constructs an error with a code and a concatenated message from multiple arguments.
Definition errors.hpp:125
Exception for logical errors in IP address operations.
Definition errors.hpp:246
logic_error(error_code code, const std::string &message)
Constructs a logic error with a code and a message string.
Definition errors.hpp:267
logic_error(error_code code, const char *message)
Constructs a logic error with a code and a message C-string.
Definition errors.hpp:276
logic_error(error_code code, const FirstArg &arg, const Args &... args)
Constructs a logic error with a code and a concatenated message from multiple arguments.
Definition errors.hpp:258
Exception for errors encountered during IP address parsing.
Definition errors.hpp:202
parse_error(error_code code, const FirstArg &arg, const Args &... args)
Constructs a parsing error with a code and a concatenated message from multiple arguments.
Definition errors.hpp:214
parse_error(error_code code, const std::string &message)
Constructs a parsing error with a code and a message string.
Definition errors.hpp:223
parse_error(error_code code, const char *message)
Constructs a parsing error with a code and a message C-string.
Definition errors.hpp:232
#define IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS
Definition config.hpp:96
#define IPADDRESS_EXPORT
Definition config.hpp:45
#define IPADDRESS_NODISCARD
Definition config.hpp:101
#define IPADDRESS_FORCE_INLINE
Definition config.hpp:115
#define IPADDRESS_NAMESPACE
Definition config.hpp:41
#define IPADDRESS_NOEXCEPT
Definition config.hpp:92
constexpr inline void raise_error(error_code code, uint32_t value, const T *address, size_t length)
Raises an error with a specific error code and additional context.
Definition errors.hpp:299
error_code
Enumeration of error codes for IP address parsing and validation.
Definition errors.hpp:52
@ cannot_set_prefixlen_diff_and_new_prefix
Both prefix length difference and new prefix cannot be set simultaneously.
@ trailing_colon_only_permitted_as_part_of_double_colon
A trailing colon is only permitted as part of a double colon.
@ octet_has_invalid_symbol
An octet contains characters other than digits, which are invalid.
@ last_address_must_be_greater_than_first
The last IP address in the range must be greater than the first IP address.
@ invalid_version
The IP address version does not match the expected version.
@ unexpected_symbol
The input string contains an unexpected character.
@ empty_address
The IP address string is empty when it should contain a valid address.
@ exactly_8_parts_expected_without_double_colon
Without a double colon, exactly eight parts are expected.
@ leading_colon_only_permitted_as_part_of_double_colon
A leading colon is only permitted as part of a double colon.
@ octet_exceeded_255
An octet's value exceeds the maximum allowed value of 255.
@ invalid_scope_id
The scope ID in the IPv6 address is invalid.
@ string_is_too_long
Input string is too long.
@ not_contained_network
The network is not a subnet of the other network as expected.
@ most_one_double_colon_permitted
More than one double colon is present in the IPv6 address.
@ wrong_encoding_sequence
Incorrect byte sequence in Unicode encoding.
@ part_has_invalid_symbol
A part of the IPv6 address contains invalid characters.
@ leading_0_are_not_permitted
Leading zeroes are not permitted in any octet of the IPv4 address.
@ empty_octet
An octet in the IPv4 address is empty when it should contain a numeric value.
@ new_prefix_must_be_shorter
The new prefix length must be shorter for the operation being performed.
@ no_error
Indicates the absence of any errors.
@ scope_id_is_too_long
The scope ID in the IPv6 address exceeds the maximum length.
@ empty_netmask
The netmask portion of the address is empty when it should specify a valid netmask.
@ invalid_prefixlen_diff
The difference in prefix length is invalid for the operation being performed.
@ new_prefix_must_be_longer
The new prefix length must be longer for the operation being performed.
@ part_is_more_4_chars
A part of the IPv6 address contains more than four characters.
@ has_host_bits_set
The address has host bits set when they are expected to be clear.
@ only_one_slash_permitted
Only one slash character is permitted, used to separate the address from the netmask.
@ octet_more_3_characters
An octet contains more than three characters, exceeding the maximum allowed.
@ most_8_colons_permitted
The IPv6 address contains more than the maximum allowed number of colons.
@ least_3_parts
The IPv6 address contains fewer than the minimum required parts.
@ expected_4_octets
The IPv4 address does not contain the expected four octets.
@ expected_at_most_7_other_parts_with_double_colon
With a double colon present, at most seven other parts are expected.
@ netmask_pattern_mixes_zeroes_and_ones
The netmask contains an invalid pattern of zeroes and ones.
@ invalid_netmask
The provided netmask is not valid according to standard netmask formatting rules.