ipaddress 1.1.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
62 // ipv4 errors
63 empty_octet, /**< An octet in the IPv4 address is empty when it should contain a numeric value. */
64 expected_4_octets, /**< The IPv4 address does not contain the expected four octets. */
65 leading_0_are_not_permitted, /**< Leading zeroes are not permitted in any octet of the IPv4 address. */
66 octet_more_3_characters, /**< An octet contains more than three characters, exceeding the maximum allowed. */
67 octet_has_invalid_symbol, /**< An octet contains characters other than digits, which are invalid. */
68 octet_exceeded_255, /**< An octet's value exceeds the maximum allowed value of 255. */
69
70 // ipv6 errors
71 least_3_parts, /**< The IPv6 address contains fewer than the minimum required parts. */
72 most_8_colons_permitted, /**< The IPv6 address contains more than the maximum allowed number of colons. */
73 part_is_more_4_chars, /**< A part of the IPv6 address contains more than four characters. */
74 part_has_invalid_symbol, /**< A part of the IPv6 address contains invalid characters. */
75 most_one_double_colon_permitted, /**< More than one double colon is present in the IPv6 address. */
76 leading_colon_only_permitted_as_part_of_double_colon, /**< A leading colon is only permitted as part of a double colon. */
77 trailing_colon_only_permitted_as_part_of_double_colon, /**< A trailing colon is only permitted as part of a double colon. */
78 expected_at_most_7_other_parts_with_double_colon, /**< With a double colon present, at most seven other parts are expected. */
79 exactly_8_parts_expected_without_double_colon, /**< Without a double colon, exactly eight parts are expected. */
80 scope_id_is_too_long, /**< The scope ID in the IPv6 address exceeds the maximum length. */
81 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 */
82
83 // logic errors
84 invalid_version, /**< The IP address version does not match the expected version. */
85 invalid_prefixlen_diff, /**< The difference in prefix length is invalid for the operation being performed. */
86 new_prefix_must_be_shorter, /**< The new prefix length must be shorter for the operation being performed. */
87 new_prefix_must_be_longer, /**< The new prefix length must be longer for the operation being performed. */
88 cannot_set_prefixlen_diff_and_new_prefix, /**< Both prefix length difference and new prefix cannot be set simultaneously. */
89 not_contained_network, /**< The network is not a subnet of the other network as expected. */
90
91 // input string errors
92 unexpected_symbol, /**< The input string contains an unexpected character. */
93 wrong_encoding_sequence /**< Incorrect byte sequence in Unicode encoding. */
94};
95
96/**
97 * The primary exception class used by the IP address library.
98 *
99 * This class extends the standard `std::runtime_error` and serves as the base exception
100 * type for the library. It is designed to be thrown when an error condition is encountered
101 * during the processing of IP addresses, such as parsing errors or logical inconsistencies.
102 *
103 * The `error` class encapsulates an `error_code` value representing the specific error
104 * that occurred, along with a descriptive message that provides context about the error.
105 * This design allows for precise and informative error reporting, aiding in debugging
106 * and error handling.
107 *
108 * Overall, the `error` class is a critical component of the library's error management
109 * system, providing a standardized way to handle exceptions throughout the library.
110 *
111 * @sa parse_error
112 * @sa logic_error
113 */
114IPADDRESS_EXPORT class error : public std::runtime_error {
115public:
116 /**
117 * Constructs an error with a code and a concatenated message from multiple arguments.
118 *
119 * @tparam FirstArg The type of the first argument passed to the constructor.
120 * @tparam Args The types of the additional arguments passed to the constructor.
121 * @param[in] code The error code associated with the exception.
122 * @param[in] arg The first argument describing the error.
123 * @param[in] args Additional arguments describing the error.
124 */
125 template <typename FirstArg, typename... Args>
126 explicit error(error_code code, const FirstArg& arg, const Args&... args) : std::runtime_error(concatenate(arg, args...)), _code(code) {
127 }
128
129 /**
130 * Constructs an error with a code and a message string.
131 *
132 * @param[in] code The error code associated with the exception.
133 * @param[in] message A detailed description of the error.
134 */
135 explicit error(error_code code, const std::string& message) : std::runtime_error(message), _code(code) {
136 }
137
138 /**
139 * Constructs an error with a code and a message C-string.
140 *
141 * @param[in] code The error code associated with the exception.
142 * @param[in] message A detailed description of the error.
143 */
144 explicit error(error_code code, const char* message) : std::runtime_error(message), _code(code) {
145 }
146
147 /**
148 * Returns the error code associated with this error.
149 *
150 * @return The error code that represents the specific error condition.
151 */
153 return _code;
154 }
155
156 struct symbol {
157 uint32_t value;
158 };
159
160private:
161 template <typename... Args>
162 static std::string concatenate(const Args&... args) {
163 std::ostringstream ss;
164 concat(ss, args...);
165 return ss.str();
166 }
167
168 template <typename FirstArg, typename... Args>
169 static void concat(std::ostringstream& out, const FirstArg& arg, const Args&... args) {
170 print(out, arg) << ' ';
171 concat(out, args...);
172 }
173
174 template <typename FirstArg>
175 static void concat(std::ostringstream& out, const FirstArg& arg) {
176 print(out, arg);
177 }
178
179 template <typename T>
180 static std::ostringstream& print(std::ostringstream& out, const T& arg) {
181 out << arg;
182 return out;
183 }
184
185 static std::ostringstream& print(std::ostringstream& out, const symbol& arg);
186
187 template <typename T, size_t N>
188 static std::ostringstream& print(std::ostringstream& out, const T (&str)[N]);
189
190 error_code _code;
191};
192
193/**
194 * Exception for errors encountered during IP address parsing.
195 *
196 * This exception is thrown when the library encounters an error while
197 * attempting to parse an IP address or network from a string. It is a
198 * specialized form of the `error` class that provides context specific
199 * to parsing operations.
200 *
201 * @sa error
202 */
204public:
205 /**
206 * Constructs a parsing error with a code and a concatenated message from multiple arguments.
207 *
208 * @tparam FirstArg The type of the first argument passed to the constructor.
209 * @tparam Args The types of the additional arguments passed to the constructor.
210 * @param[in] code The error code associated with the parsing exception.
211 * @param[in] arg The first argument describing the error.
212 * @param[in] args Additional arguments describing the error.
213 */
214 template <typename FirstArg, typename... Args>
215 explicit parse_error(error_code code, const FirstArg& arg, const Args&... args) : error(code, arg, args...) {
216 }
217
218 /**
219 * Constructs a parsing error with a code and a message string.
220 *
221 * @param[in] code The error code associated with the parsing exception.
222 * @param[in] message A detailed description of the parsing error.
223 */
224 explicit parse_error(error_code code, const std::string& message) : error(code, message) {
225 }
226
227 /**
228 * Constructs a parsing error with a code and a message C-string.
229 *
230 * @param[in] code The error code associated with the parsing exception.
231 * @param[in] message A detailed description of the parsing error.
232 */
233 explicit parse_error(error_code code, const char* message) : error(code, message) {
234 }
235};
236
237/**
238 * Exception for logical errors in IP address operations.
239 *
240 * This exception is thrown for logical errors that do not pertain directly
241 * to parsing, such as using an incorrect prefix length or other operations
242 * that violate the logic of IP address manipulation. It extends the `error`
243 * class to provide additional context for these types of logical issues.
244 *
245 * @sa error
246 */
248public:
249 /**
250 * Constructs a logic error with a code and a concatenated message from multiple arguments.
251 *
252 * @tparam FirstArg The type of the first argument passed to the constructor.
253 * @tparam Args The types of the additional arguments passed to the constructor.
254 * @param[in] code The error code associated with the logical exception.
255 * @param[in] arg The first argument describing the error.
256 * @param[in] args Additional arguments describing the error.
257 */
258 template <typename FirstArg, typename... Args>
259 explicit logic_error(error_code code, const FirstArg& arg, const Args&... args) : error(code, arg, args...) {
260 }
261
262 /**
263 * Constructs a logic error with a code and a message string.
264 *
265 * @param[in] code The error code associated with the logical exception.
266 * @param[in] message A detailed description of the logical error.
267 */
268 explicit logic_error(error_code code, const std::string& message) : error(code, message) {
269 }
270
271 /**
272 * Constructs a logic error with a code and a message C-string.
273 *
274 * @param[in] code The error code associated with the logical exception.
275 * @param[in] message A detailed description of the logical error.
276 */
277 explicit logic_error(error_code code, const char* message) : error(code, message) {
278 }
279};
280
281/**
282 * Raises an error with a specific error code and additional context.
283 *
284 * This function constructs an error message based on the provided error code,
285 * value, and address, then throws a parse_error or a logic_error exception with the constructed message.
286 *
287 * @tparam T The character type of the address string.
288 * @param[in] code The error code indicating the type of error encountered.
289 * @param[in] value The value at which the error occurred, if applicable.
290 * @param[in] address A pointer to the beginning of the address string.
291 * @param[in] length The length of the address string.
292 * @throw parse_error Thrown with a message corresponding to the error code.
293 * @throw logic_error Thrown with a message corresponding to the error code.
294 * @note This function is marked [[noreturn]] as it always throws an exception.
295 */
296IPADDRESS_EXPORT template <typename T>
297#ifndef IPADDRESS_NO_EXCEPTIONS
298[[noreturn]]
299#endif
300IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE void raise_error(error_code code, uint32_t value, const T* address, size_t length) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
301#ifndef IPADDRESS_NO_EXCEPTIONS
302 T str[104] = {};
303 size_t max_len = length;
304 if (length > 100) {
305 max_len = 100;
306 }
307 for (size_t i = 0; i < max_len; ++i) {
308 str[i] = address[i];
309 }
310 if (length > 100) {
311 str[100] = '.';
312 str[101] = '.';
313 str[102] = '.';
314 }
315 switch (code) {
317 throw parse_error(code, "address cannot be empty");
319 throw parse_error(code, "empty mask in address", str);
321 throw parse_error(code, "is not a valid netmask in address", str);
323 throw parse_error(code, "netmask pattern mixes zeroes & ones in address", str);
325 throw parse_error(code, "has host bits set in address", str);
327 throw parse_error(code, "only one '/' permitted in address", str);
329 throw parse_error(code, "input string is too long", str);
331 throw parse_error(code, "empty octet", value, "in address", str);
333 throw parse_error(code, "expected 4 octets in", str);
335 throw parse_error(code, "leading zeros are not permitted in octet", value, "of address", str);
337 throw parse_error(code, "in octet", value, "of address", str, "more 3 characters");
339 throw parse_error(code, "in octet", value, "of address", str, "has invalid symbol");
341 throw parse_error(code, "octet", value, "of address", str, "exceeded 255");
343 throw parse_error(code, "least 3 parts in address", str);
345 throw parse_error(code, "most 8 colons permitted in address", str);
347 throw parse_error(code, "in part", value, "of address", str, "more 4 characters");
349 throw parse_error(code, "in part", value, "of address", str, "has invalid symbols");
351 throw parse_error(code, "at most one '::' permitted in address", str);
353 throw parse_error(code, "at leading ':' only permitted as part of '::' in address", str);
355 throw parse_error(code, "at trailing ':' only permitted as part of '::' in address", str);
357 throw parse_error(code, "expected at most 7 other parts with '::' in address", str);
359 throw parse_error(code, "exactly 8 parts expected without '::' in address", str);
361 throw parse_error(code, "scope id is too long in address", str);
363 throw parse_error(code, "invalid scope id in address", str);
365 throw logic_error(code, "versions don't match");
367 throw logic_error(code, "invalid prefixlen_diff");
369 throw logic_error(code, "new prefix must be shorter");
371 throw logic_error(code, "new prefix must be longer");
373 throw logic_error(code, "cannot set prefixlen_diff and new_prefix");
375 throw logic_error(code, "network is not a subnet of other");
377 throw parse_error(code, "unexpected next unicode symbol", error::symbol { value }, "in string", str);
379 throw parse_error(code, "incorrect sequence of bytes in unicode encoding for string", str);
380 default:
381 throw error(code, "unknown error");
382 }
383#else
384 if (IPADDRESS_IS_CONST_EVALUATED(length)) {
385 const auto _err = int(code) / (int(code) - int(code)); // invalid input string
386 }
387#endif
388}
389
390} // namespace IPADDRESS_NAMESPACE
391
392#endif // IPADDRESS_ERRORS_HPP
The primary exception class used by the IP address library.
Definition errors.hpp:114
error_code code() const noexcept
Returns the error code associated with this error.
Definition errors.hpp:152
error(error_code code, const char *message)
Constructs an error with a code and a message C-string.
Definition errors.hpp:144
error(error_code code, const std::string &message)
Constructs an error with a code and a message string.
Definition errors.hpp:135
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:126
Exception for logical errors in IP address operations.
Definition errors.hpp:247
logic_error(error_code code, const std::string &message)
Constructs a logic error with a code and a message string.
Definition errors.hpp:268
logic_error(error_code code, const char *message)
Constructs a logic error with a code and a message C-string.
Definition errors.hpp:277
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:259
Exception for errors encountered during IP address parsing.
Definition errors.hpp:203
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:215
parse_error(error_code code, const std::string &message)
Constructs a parsing error with a code and a message string.
Definition errors.hpp:224
parse_error(error_code code, const char *message)
Constructs a parsing error with a code and a message C-string.
Definition errors.hpp:233
#define IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS
Definition config.hpp:93
#define IPADDRESS_EXPORT
Definition config.hpp:42
#define IPADDRESS_NODISCARD
Definition config.hpp:98
#define IPADDRESS_FORCE_INLINE
Definition config.hpp:112
#define IPADDRESS_NAMESPACE
Definition config.hpp:38
#define IPADDRESS_NOEXCEPT
Definition config.hpp:89
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:300
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.
@ 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.