OpenVPN 3 Core Library
Loading...
Searching...
No Matches
exception.hpp
Go to the documentation of this file.
1// OpenVPN -- An application to securely tunnel IP networks
2// over a single port, with support for SSL/TLS-based
3// session authentication and key exchange,
4// packet encryption, packet authentication, and
5// packet compression.
6//
7// Copyright (C) 2012- OpenVPN Inc.
8//
9// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
10//
11
12// Basic exception handling. Allow exception classes for specific errors
13// to be easily defined, and allow exceptions to be thrown with a consise
14// syntax that allows stringstream concatenation using <<
15
16#ifndef OPENVPN_COMMON_EXCEPTION_H
17#define OPENVPN_COMMON_EXCEPTION_H
18
19#include <string>
20#include <sstream>
21#include <exception>
22#include <utility>
23
24#include <openvpn/common/stringize.hpp> // for OPENVPN_STRINGIZE
25
26#ifdef OPENVPN_DEBUG_EXCEPTION
27// well-known preprocessor hack to get __FILE__:__LINE__ rendered as a string
28#define OPENVPN_FILE_LINE "/" __FILE__ ":" OPENVPN_STRINGIZE(__LINE__)
29#else
30#define OPENVPN_FILE_LINE
31#endif
32
33namespace openvpn {
34
35// string exception class, where the exception is described by a std::string
36class Exception : public std::exception
37{
38 public:
39 explicit Exception(const std::string &err) noexcept
40 : err_(err)
41 {
42 }
43 explicit Exception(std::string &&err) noexcept
44 : err_(std::move(err))
45 {
46 }
47 const char *what() const noexcept override
48 {
49 return err_.c_str();
50 }
51 const std::string &err() const noexcept
52 {
53 return err_;
54 }
55 virtual ~Exception() noexcept = default;
56
57 void add_label(const std::string &label)
58 {
59 err_ = label + ": " + err_;
60 }
61
62 void remove_label(const std::string &label)
63 {
64 const std::string head = label + ": ";
65 if (err_.starts_with(head))
66 err_ = err_.substr(head.length());
67 }
68
69 private:
70 std::string err_;
71};
72
73// define a simple custom exception class with no extra info
74#define OPENVPN_SIMPLE_EXCEPTION(C) \
75 class C : public std::exception \
76 { \
77 public: \
78 const char *what() const noexcept override \
79 { \
80 return #C OPENVPN_FILE_LINE; \
81 } \
82 }
83
84// define a simple custom exception class with no extra info that inherits from a custom base
85#define OPENVPN_SIMPLE_EXCEPTION_INHERIT(B, C) \
86 class C : public B \
87 { \
88 public: \
89 C() : B(#C OPENVPN_FILE_LINE) \
90 { \
91 } \
92 const char *what() const noexcept override \
93 { \
94 return #C OPENVPN_FILE_LINE; \
95 } \
96 }
97
98// define a custom exception class that allows extra info
99#define OPENVPN_EXCEPTION(C) \
100 class C : public openvpn::Exception \
101 { \
102 public: \
103 C() : openvpn::Exception(#C OPENVPN_FILE_LINE) \
104 { \
105 } \
106 C(const std::string &err) : openvpn::Exception(#C OPENVPN_FILE_LINE ": " + err) \
107 { \
108 } \
109 }
110
111// define a custom exception class that allows extra info with error code
112#define OPENVPN_EXCEPTION_WITH_CODE(C, DEFAULT_CODE, ...) \
113 enum C##_##code : unsigned int{__VA_ARGS__}; \
114 class C : public openvpn::Exception \
115 { \
116 public: \
117 C() : openvpn::Exception(#C OPENVPN_FILE_LINE) \
118 { \
119 add_label(#DEFAULT_CODE); \
120 } \
121 C(const std::string &err) : openvpn::Exception(#C OPENVPN_FILE_LINE ": " + err) \
122 { \
123 add_label(#DEFAULT_CODE); \
124 } \
125 option_error(C##_##code code, const std::string &err) \
126 : openvpn::Exception(#C OPENVPN_FILE_LINE ": " + err) \
127 { \
128 add_label(code2string(code)); \
129 } \
130 static std::string code2string(C##_##code code); \
131 }
132// define a custom exception class that allows extra info, but does not emit a tag
133#define OPENVPN_UNTAGGED_EXCEPTION(C) \
134 class C : public openvpn::Exception \
135 { \
136 public: \
137 C(const std::string &err) : openvpn::Exception(err) \
138 { \
139 } \
140 }
141
142// define a custom exception class that allows extra info, and inherits from a custom base
143#define OPENVPN_EXCEPTION_INHERIT(B, C) \
144 class C : public B \
145 { \
146 public: \
147 C() : B(#C OPENVPN_FILE_LINE) \
148 { \
149 } \
150 C(const std::string &err) : B(#C OPENVPN_FILE_LINE ": " + err) \
151 { \
152 } \
153 }
154
155// define a custom exception class that allows extra info, and inherits from a custom base,
156// but does not emit a tag
157#define OPENVPN_UNTAGGED_EXCEPTION_INHERIT(B, C) \
158 class C : public B \
159 { \
160 public: \
161 using B::B; \
162 }
163
164// throw an Exception with stringstream concatenation allowed
165#define OPENVPN_THROW_EXCEPTION(stuff) \
166 do \
167 { \
168 std::ostringstream _ovpn_exc; \
169 _ovpn_exc << stuff; \
170 throw openvpn::Exception(_ovpn_exc.str()); \
171 } while (0)
172
173// throw an OPENVPN_EXCEPTION class with stringstream concatenation allowed
174#define OPENVPN_THROW(exc, stuff) \
175 do \
176 { \
177 std::ostringstream _ovpn_exc; \
178 _ovpn_exc << stuff; \
179 throw exc(_ovpn_exc.str()); \
180 } while (0)
181
182#define OPENVPN_THROW_ARG1(exc, arg, stuff) \
183 do \
184 { \
185 std::ostringstream _ovpn_exc; \
186 _ovpn_exc << stuff; \
187 throw exc(arg, _ovpn_exc.str()); \
188 } while (0)
189
190// properly rethrow an exception that might be derived from Exception
191inline void throw_ref(const std::exception &e)
192{
193 const Exception *ex = dynamic_cast<const Exception *>(&e);
194 if (ex)
195 throw *ex;
196 throw e;
197}
198
199} // namespace openvpn
200
201#endif // OPENVPN_COMMON_EXCEPTION_H
Exception(const std::string &err) noexcept
Definition exception.hpp:39
const std::string & err() const noexcept
Definition exception.hpp:51
const char * what() const noexcept override
Definition exception.hpp:47
std::string err_
Definition exception.hpp:70
virtual ~Exception() noexcept=default
Exception(std::string &&err) noexcept
Definition exception.hpp:43
void remove_label(const std::string &label)
Definition exception.hpp:62
void add_label(const std::string &label)
Definition exception.hpp:57
void throw_ref(const std::exception &e)