dodo  0.0.1
A C++ library to create containerized Linux services
systemerror.hpp
Go to the documentation of this file.
1 /*
2  * This file is part of the dodo library (https://github.com/jmspit/dodo).
3  * Copyright (c) 2019 Jan-Marten Spit.
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, version 3.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 /**
19  * @file systemerror.hpp
20  * Defines the dodo::common::SystemError class.
21  */
22 
23 #ifndef common_systemerror_hpp
24 #define common_systemerror_hpp
25 
26 
27 #include <cstring>
28 #include <netdb.h>
29 #include <sstream>
30 #include <string>
31 
32 #include <common/puts.hpp>
33 
34 namespace dodo::common {
35 
36  /**
37  * Linux system error primitive to provide a consistent interface to
38  * Linux error codes. The [[nodiscard]] attribute causes the compiler to issue a warning in case
39  * a SystemError is produced as r-value but not assigned to an l-value - encouraging more robust
40  * code by pinpointing omitted error checking.
41  * @code
42  * SystemError error1; // set to ecOK
43  * SystemError error2( SystemError::ecECONNREFUSED ); // set to ECONNREFUSED
44  * error1 == error2; // false
45  * error1 != error2; // true
46  * error1 == SystemError::ecECONNREFUSED; // false
47  * error2 == SystemError::ecECONNREFUSED; // true
48  * error2 == SystemError( SystemError::ecECONNREFUSED ); //true
49  * int i = error1; // error1 cast to int=ecOK
50  * error1 = SystemError::ecEBADF // error1 set to SystemError::ecEBADF
51  * @endcode
52  */
53  class [[nodiscard]] SystemError {
54  public:
55 
56  /**
57  * Enumerate mimicking Linux error codes, integrates the EAI (addrinfo) ranges of errors.
58  */
59  enum ErrorCode {
60  ecOK = 0, /**< 0 Not an error, success */
61  ecEPERM = EPERM, /**< 1 Operation not permitted */
62  ecENOENT = ENOENT, /**< 2 No such file or directory */
63  ecESRCH = ESRCH, /**< 3 No such process */
64  ecEINTR = EINTR, /**< 4 Interrupted system call */
65  ecEIO = EIO, /**< 5 I/O error */
66  ecENXIO = ENXIO, /**< 6 No such device or address */
67  ecE2BIG = E2BIG, /**< 7 Argument list too long */
68  ecENOEXEC = ENOEXEC, /**< 8 Exec format error */
69  ecEBADF = EBADF, /**< 9 Bad file number */
70  ecECHILD = ECHILD, /**< 10 No child processes */
71  ecEAGAIN = EAGAIN, /**< 11 Try again */
72  ecENOMEM = ENOMEM, /**< 12 Out of memory */
73  ecEACCES = EACCES, /**< 13 Permission denied */
74  ecEFAULT = EFAULT, /**< 14 Bad address */
75  ecENOTBLK = ENOTBLK, /**< 15 Block device required */
76  ecEBUSY = EBUSY, /**< 16 Device or resource busy */
77  ecEEXIST = EEXIST, /**< 17 File exists */
78  ecEXDEV = EXDEV, /**< 18 Cross-device link */
79  ecENODEV = ENODEV, /**< 19 No such device */
80  ecENOTDIR = ENOTDIR, /**< 20 Not a directory */
81  ecEISDIR = EISDIR, /**< 21 Is a directory */
82  ecEINVAL = EINVAL, /**< 22 Invalid argument */
83  ecENFILE = ENFILE, /**< 23 File table overflow */
84  ecEMFILE = EMFILE, /**< 24 Too many open files */
85  ecENOTTY = ENOTTY, /**< 25 Not a typewriter */
86  ecETXTBSY = ETXTBSY, /**< 26 Text file busy */
87  ecEFBIG = EFBIG, /**< 27 File too large */
88  ecENOSPC = ENOSPC, /**< 28 No space left on device */
89  ecESPIPE = ESPIPE, /**< 29 Illegal seek */
90  ecEROFS = EROFS, /**< 30 Read-only file system */
91  ecEMLINK = EMLINK, /**< 31 Too many links */
92  ecEPIPE = EPIPE, /**< 32 Broken pipe */
93  ecEDOM = EDOM, /**< 33 Math argument out of domain of function */
94  ecERANGE = ERANGE, /**< 34 Math result not representable */
95  ecEDEADLK = EDEADLK, /**< 35 Resource deadlock would occur */
96  ecENAMETOOLONG = ENAMETOOLONG, /**< 36 File name too long */
97  ecENOLCK = ENOLCK, /**< 37 No record locks available */
98  ecENOSYS = ENOSYS, /**< 38 Invalid system call number */
99  ecENOTEMPTY = ENOTEMPTY, /**< 39 Directory not empty */
100  ecELOOP = ELOOP, /**< 40 Too many symbolic links encountered */
101  ecEWOULDBLOCK = EWOULDBLOCK, /**< 41 Operation would block */
102  ecENOMSG = ENOMSG, /**< 42 No message of desired type */
103  ecEIDRM = EIDRM, /**< 43 Identifier removed */
104  ecECHRNG = ECHRNG, /**< 44 Channel number out of range */
105  ecEL2NSYNC = EL2NSYNC, /**< 45 Level 2 not synchronized */
106  ecEL3HLT = EL3HLT, /**< 46 Level 3 halted */
107  ecEL3RST = EL3RST, /**< 47 Level 3 reset */
108  ecELNRNG = ELNRNG, /**< 48 Link number out of range */
109  ecEUNATCH = EUNATCH, /**< 49 Protocol driver not attached */
110  ecENOCSI = ENOCSI, /**< 50 No CSI structure available */
111  ecEL2HLT = EL2HLT, /**< 51 Level 2 halted */
112  ecEBADE = EBADE, /**< 52 Invalid exchange */
113  ecEBADR = EBADR, /**< 53 Invalid request descriptor */
114  ecEXFULL = EXFULL, /**< 54 Exchange full */
115  ecENOANO = ENOANO, /**< 55 No anode */
116  ecEBADRQC = EBADRQC, /**< 56 Invalid request code */
117  ecEBADSLT = EBADSLT, /**< 57 Invalid slot */
118  ecEDEADLOCK = EDEADLOCK, /**< 58 EDEADLK */
119  ecEBFONT = EBFONT, /**< 59 Bad font file format */
120  ecENOSTR = ENOSTR, /**< 60 Device not a stream */
121  ecENODATA = ENODATA, /**< 61 No data available */
122  ecETIME = ETIME, /**< 62 Timer expired */
123  ecENOSR = ENOSR, /**< 63 Out of streams resources */
124  ecENONET = ENONET, /**< 64 Machine is not on the network */
125  ecENOPKG = ENOPKG, /**< 65 Package not installed */
126  ecEREMOTE = EREMOTE, /**< 66 Object is remote */
127  ecENOLINK = ENOLINK, /**< 67 Link has been severed */
128  ecEADV = EADV, /**< 68 Advertise error */
129  ecESRMNT = ESRMNT, /**< 69 Srmount error */
130  ecECOMM = ECOMM, /**< 70 Communication error on send */
131  ecEPROTO = EPROTO, /**< 71 Protocol error */
132  ecEMULTIHOP = EMULTIHOP, /**< 72 Multihop attempted */
133  ecEDOTDOT = EDOTDOT, /**< 73 RFS specific error */
134  ecEBADMSG = EBADMSG, /**< 74 Not a data message */
135  ecEOVERFLOW = EOVERFLOW, /**< 75 Value too large for defined data type */
136  ecENOTUNIQ = ENOTUNIQ, /**< 76 Name not unique on network */
137  ecEBADFD = EBADFD, /**< 77 File descriptor in bad state */
138  ecEREMCHG = EREMCHG, /**< 78 Remote address changed */
139  ecELIBACC = ELIBACC, /**< 79 Can not access a needed shared library */
140  ecELIBBAD = ELIBBAD, /**< 80 Accessing a corrupted shared library */
141  ecELIBSCN = ELIBSCN, /**< 81 .lib section in a.out corrupted */
142  ecELIBMAX = ELIBMAX, /**< 82 Attempting to link in too many shared libraries */
143  ecELIBEXEC = ELIBEXEC, /**< 83 Cannot exec a shared library directly */
144  ecEILSEQ = EILSEQ, /**< 84 Illegal byte sequence */
145  ecERESTART = ERESTART, /**< 85 Interrupted system call should be restarted */
146  ecESTRPIPE = ESTRPIPE, /**< 86 Streams pipe error */
147  ecEUSERS = EUSERS, /**< 87 Too many users */
148  ecENOTSOCK = ENOTSOCK, /**< 88 Socket operation on non-socket */
149  ecEDESTADDRREQ = EDESTADDRREQ, /**< 89 Destination address required */
150  ecEMSGSIZE = EMSGSIZE, /**< 90 Message too long */
151  ecEPROTOTYPE = EPROTOTYPE, /**< 91 Protocol wrong type for socket */
152  ecENOPROTOOPT = ENOPROTOOPT, /**< 92 Protocol not available */
153  ecEPROTONOSUPPORT = EPROTONOSUPPORT, /**< 93 Protocol not supported */
154  ecESOCKTNOSUPPORT = ESOCKTNOSUPPORT, /**< 94 Socket type not supported */
155  ecEOPNOTSUPP = EOPNOTSUPP, /**< 95 Operation not supported on transport endpoint */
156  ecEPFNOSUPPORT = EPFNOSUPPORT, /**< 96 Protocol family not supported */
157  ecEAFNOSUPPORT = EAFNOSUPPORT, /**< 97 Address family not supported by protocol */
158  ecEADDRINUSE = EADDRINUSE, /**< 98 Address already in use */
159  ecEADDRNOTAVAIL = EADDRNOTAVAIL, /**< 99 Cannot assign requested address */
160  ecENETDOWN = ENETDOWN, /**< 100 Network is down */
161  ecENETUNREACH = ENETUNREACH, /**< 101 Network is unreachable */
162  ecENETRESET = ENETRESET, /**< 102 Network dropped connection because of reset */
163  ecECONNABORTED = ECONNABORTED, /**< 103 Software caused connection abort */
164  ecECONNRESET = ECONNRESET, /**< 104 Connection reset by peer */
165  ecENOBUFS = ENOBUFS, /**< 105 No buffer space available */
166  ecEISCONN = EISCONN, /**< 106 Transport endpoint is already connected */
167  ecENOTCONN = ENOTCONN, /**< 107 Transport endpoint is not connected */
168  ecESHUTDOWN = ESHUTDOWN, /**< 108 Cannot send after transport endpoint shutdown */
169  ecETOOMANYREFS = ETOOMANYREFS, /**< 109 Too many references: cannot splice */
170  ecETIMEDOUT = ETIMEDOUT, /**< 110 Connection timed out */
171  ecECONNREFUSED = ECONNREFUSED, /**< 111 Connection refused */
172  ecEHOSTDOWN = EHOSTDOWN, /**< 112 Host is down */
173  ecEHOSTUNREACH = EHOSTUNREACH, /**< 113 No route to host */
174  ecEALREADY = EALREADY, /**< 114 Operation already in progress */
175  ecEINPROGRESS = EINPROGRESS, /**< 115 Operation now in progress */
176  ecESTALE = ESTALE, /**< 116 Stale file handle */
177  ecEUCLEAN = EUCLEAN, /**< 117 Structure needs cleaning */
178  ecENOTNAM = ENOTNAM, /**< 118 Not a XENIX named type file */
179  ecENAVAIL = ENAVAIL, /**< 119 No XENIX semaphores available */
180  ecEISNAM = EISNAM, /**< 120 Is a named type file */
181  ecEREMOTEIO = EREMOTEIO, /**< 121 Remote I/O error */
182  ecEDQUOT = EDQUOT, /**< 122 Quota exceeded */
183  ecENOMEDIUM = ENOMEDIUM, /**< 123 No medium found */
184  ecEMEDIUMTYPE = EMEDIUMTYPE, /**< 124 Wrong medium type */
185  ecECANCELED = ECANCELED, /**< 125 Operation Canceled */
186  ecENOKEY = ENOKEY, /**< 126 Required key not available */
187  ecEKEYEXPIRED = EKEYEXPIRED, /**< 127 Key has expired */
188  ecEKEYREVOKED = EKEYREVOKED, /**< 128 Key has been revoked */
189  ecEKEYREJECTED = EKEYREJECTED, /**< 129 Key was rejected by service */
190  ecEOWNERDEAD = EOWNERDEAD, /**< 130 Owner died */
191  ecENOTRECOVERABLE = ENOTRECOVERABLE, /**< 131 State not recoverable */
192  ecERFKILL = ERFKILL, /**< 132 Operation not possible due to RF-kill */
193  ecEHWPOISON = EHWPOISON, /**< 133 Memory page has hardware error */
194 
195 
196  ecEAI_BADFLAGS = EAI_BADFLAGS, /**< -1 Invalid value for `ai_flags' field. */
197  ecEAI_NONAME = EAI_NONAME, /**< -2 NAME or SERVICE is unknown. */
198  ecEAI_AGAIN = EAI_AGAIN, /**< -3 Temporary failure in name resolution. */
199  ecEAI_FAIL = EAI_FAIL, /**< -4 Non-recoverable failure in name res. */
200  ecEAI_NODATA = EAI_NODATA, /**< -5 No address associated with NAME. */
201  ecEAI_FAMILY = EAI_FAMILY, /**< -6 ai_family not supported. */
202  ecEAI_SOCKTYPE = EAI_SOCKTYPE, /**< -7 ai_socktype not supported. */
203  ecEAI_SERVICE = EAI_SERVICE, /**< -8 SERVICE not supported for `ai_socktype'. */
204  ecEAI_ADDRFAMILY = EAI_ADDRFAMILY, /**< -9 Address family for NAME not supported. */
205  ecEAI_MEMORY = EAI_MEMORY, /**< -10 Memory allocation failure. */
206  ecEAI_SYSTEM = EAI_SYSTEM, /**< -11 System error returned in `errno'. */
207  ecEAI_OVERFLOW = EAI_OVERFLOW, /**< -12 Argument buffer overflow. */
208  ecEAI_INPROGRESS = EAI_INPROGRESS, /**< -100 Processing request in progress. */
209  ecEAI_CANCELED = EAI_CANCELED, /**< -101 Request canceled. */
210  ecEAI_NOTCANCELED = EAI_NOTCANCELED, /**< -102 Request not canceled. */
211  ecEAI_ALLDONE = EAI_ALLDONE, /**< -103 All requests done. */
212  ecEAI_INTR = EAI_INTR, /**< -104 Interrupted by a signal. */
213  ecEAI_IDN_ENCODE = EAI_IDN_ENCODE, /**< -105 IDN encoding failed. */
214 
215  ecLIBRARY_FIRST = 10000, /**< 10000 Marker, library error codes from here. */
216 
217  ecSSL = 10002, /**< 10002 SSL exception */
218  ecSSL_ERROR_NONE = 10003, /**< 10003 SSL_ERROR_NONE */
219  ecSSL_ERROR_ZERO_RETURN = 10003, /**< 10003 SSL_ERROR_ZERO_RETURN */
220  ecSSL_ERROR_WANT_READ = 10004, /**< 10004 SSL_ERROR_WANT_READ */
221  ecSSL_ERROR_WANT_WRITE = 10005, /**< 10005 SSL_ERROR_WANT_WRITE */
222  ecSSL_ERROR_WANT_CONNECT = 10006, /**< 10006 SSL_ERROR_WANT_CONNECT */
223  ecSSL_ERROR_WANT_ACCEPT = 10007, /**< 10007 SSL_ERROR_WANT_ACCEPT */
224  ecSSL_ERROR_WANT_X509_LOOKUP = 10008, /**< 10008 SSL_ERROR_WANT_X509_LOOKUP */
225  ecSSL_ERROR_WANT_ASYNC = 10009, /**< 10009 SSL_ERROR_WANT_ASYNC */
226  ecSSL_ERROR_WANT_ASYNC_JOB = 10010, /**< 10010 SSL_ERROR_WANT_ASYNC_JOB */
227  ecSSL_ERROR_WANT_CLIENT_HELLO_CB = 10011, /**< 10011 SSL_ERROR_WANT_CLIENT_HELLO_CB */
228  ecSSL_ERROR_SYSCALL = 10012, /**< 10012 SSL_ERROR_SYSCALL */
229  ecSSL_ERROR_PEERVERIFICATION = 10013, /**< 10013 When peer verification failed */
230 
231  };
232 
233  /**
234  * Construct default with ecOK.
235  */
236  SystemError() : errorcode_(ecOK) {};
237 
238  /**
239  * Construct from ErrorCode enumerate.
240  * @param e The ErrorCode to assign.
241  */
242  SystemError( ErrorCode e ) : errorcode_(e) {};
243 
244  /**
245  * Construct from system error code.
246  * @param e The int error to assign.
247  */
248  SystemError( int e ) : errorcode_(ErrorCode(e)) {};
249 
250  /**
251  * Returns true when this->errorcode_ == ecOK
252  * @return True when this->errorcode_ == ecOK
253  */
254  bool ok() const { return this->errorcode_ == ecOK; }
255 
256  /**
257  * Compare this SystemError to the system error e.
258  * @param e The int to compare to.
259  * @return true when unequal.
260  */
261  bool operator!=( int e ) const { return this->errorcode_ != ErrorCode(e); };
262 
263  /**
264  * Compare this SystemError to the ErrorCode e.
265  * @param e The ErrorCode to compare to.
266  * @return true when unequal.
267  */
268  bool operator!=( ErrorCode e ) const { return this->errorcode_ != e; };
269 
270  /**
271  * Compare this SystemError to the SystemError e.
272  * @param e The SystemError to compare to.
273  * @return true when unequal.
274  */
275  bool operator!=( SystemError e ) const { return this->errorcode_ != e.errorcode_; };
276 
277  /**
278  * Compare this SystemError to the ErrorCode e.
279  * @param e The error to compare to.
280  * @return true when equal.
281  */
282  bool operator==( ErrorCode e ) const { return this->errorcode_ == e; };
283 
284  /**
285  * Compare this SystemError to the SystemError e.
286  * @param e The SystemError to compare to.
287  * @return true when equal.
288  */
289  bool operator==( const SystemError& e ) const { return this->errorcode_ == e.errorcode_; };
290 
291  /**
292  * Assign system error e.
293  * @param e The int error to assign
294  * @return This SystemError
295  */
296  SystemError& operator=( int e ) { this->errorcode_ = ErrorCode(e); return *this; };
297 
298  /**
299  * Assign ErrorCode e.
300  * @param e The ErrorCode to assign
301  * @return This SystemError
302  */
303  SystemError& operator=( ErrorCode e ) { this->errorcode_ = e; return *this; };
304 
305  /**
306  * Assign SystemError e.
307  * @param e The SystemError to assign
308  * @return This SystemError
309  */
310  SystemError& operator=( SystemError e ) { this->errorcode_ = e.errorcode_; return *this; };
311 
312  /**
313  * Cast this SystemError to an int by taking error code_.
314  * @return The int cast to.
315  */
316  operator int() const { return errorcode_; };
317 
318  /**
319  * Get the system error string.
320  * @return The system error string.
321  */
322  std::string asString() const {
323  std::stringstream ss;
324  if ( errorcode_ > 0 ) {
325  if ( errorcode_ >= ecLIBRARY_FIRST )
326  ss << libstrerror( errorcode_ );
327  else
328  ss << strerror(errorcode_);
329  } else if ( errorcode_ == 0 ) {
330  ss << "Succes";
331  } else {
332  ss << gai_strerror(errorcode_);
333  }
334  ss << " (" << errorcode_ << ")";
335  return ss.str();
336  };
337 
338  /**
339  * Translate SystemErrors in library range.
340  * @param error The SystemError to translate.
341  * @return The error string.
342  */
343  static std::string libstrerror( SystemError error ) {
344  switch ( error ) {
346  return "The peer certificate CN or SubjectAltNames do not match";
348  return "A SSL function encountered a failed syscall";
349  case SystemError::ecSSL:
350  return "SSL exception thrown";
351  default : return common::Puts() << "unknown error" << error;
352  }
353  }
354 
355  private:
356  /**
357  * Enumerate representation of the system error code.
358  */
360  };
361 
362 }
363 
364 
365 #endif
dodo::common::SystemError::libstrerror
static std::string libstrerror(SystemError error)
Translate SystemErrors in library range.
Definition: systemerror.hpp:343
dodo::common::SystemError::operator!=
bool operator!=(ErrorCode e) const
Compare this SystemError to the ErrorCode e.
Definition: systemerror.hpp:268
dodo::common::SystemError::operator!=
bool operator!=(int e) const
Compare this SystemError to the system error e.
Definition: systemerror.hpp:261
dodo::common::SystemError::ErrorCode
ErrorCode
Enumerate mimicking Linux error codes, integrates the EAI (addrinfo) ranges of errors.
Definition: systemerror.hpp:59
dodo::common::SystemError::operator==
bool operator==(const SystemError &e) const
Compare this SystemError to the SystemError e.
Definition: systemerror.hpp:289
dodo::common::SystemError::ecSSL_ERROR_PEERVERIFICATION
@ ecSSL_ERROR_PEERVERIFICATION
10013 When peer verification failed
Definition: systemerror.hpp:229
puts.hpp
dodo::common::SystemError::operator=
SystemError & operator=(ErrorCode e)
Assign ErrorCode e.
Definition: systemerror.hpp:303
dodo::common::SystemError::operator!=
bool operator!=(SystemError e) const
Compare this SystemError to the SystemError e.
Definition: systemerror.hpp:275
dodo::common::SystemError::ok
bool ok() const
Returns true when this->errorcode_ == ecOK.
Definition: systemerror.hpp:254
dodo::common::SystemError::asString
std::string asString() const
Get the system error string.
Definition: systemerror.hpp:322
dodo::common::SystemError::operator=
SystemError & operator=(SystemError e)
Assign SystemError e.
Definition: systemerror.hpp:310
dodo::common::SystemError::SystemError
SystemError()
Construct default with ecOK.
Definition: systemerror.hpp:236
dodo::common::SystemError::ecSSL_ERROR_SYSCALL
@ ecSSL_ERROR_SYSCALL
10012 SSL_ERROR_SYSCALL
Definition: systemerror.hpp:228
dodo::common::SystemError::SystemError
SystemError(int e)
Construct from system error code.
Definition: systemerror.hpp:248
dodo::common
Common and utility interfaces.
Definition: application.hpp:29
dodo::common::SystemError::operator==
bool operator==(ErrorCode e) const
Compare this SystemError to the ErrorCode e.
Definition: systemerror.hpp:282
dodo::common::Puts
Helper class to write strings in stream format, eg.
Definition: puts.hpp:46
dodo::common::SystemError
Linux system error primitive to provide a consistent interface to Linux error codes.
Definition: systemerror.hpp:53
dodo::common::SystemError::operator=
SystemError & operator=(int e)
Assign system error e.
Definition: systemerror.hpp:296
dodo::common::SystemError::errorcode_
ErrorCode errorcode_
Enumerate representation of the system error code.
Definition: systemerror.hpp:359
dodo::common::SystemError::SystemError
SystemError(ErrorCode e)
Construct from ErrorCode enumerate.
Definition: systemerror.hpp:242
dodo::common::SystemError::ecSSL
@ ecSSL
10002 SSL exception
Definition: systemerror.hpp:217