#ifndef ERROR_H
#define ERROR_H
/*
* Error-handling functions
*/
#include <errno.h>
/*
* Type used for error codes is an explicitly *unsigned* int, meaning that error codes themselves are positive.
* Negative error codes also exist in some places, and they are just a negative err_t.
*/
typedef unsigned int err_t;
/*
* Bitmask of error_info.extra meanings
*/
enum error_extra_types {
// bit offset of ERR_EXTRA_* mask in error_code
_ERR_EXTRA_OFFSET = 3 * 8,
// mask of bits used for the error_extra_types value
_ERR_EXTRA_MASK = 0xff << _ERR_EXTRA_OFFSET,
ERR_EXTRA_NONE = 0x00 << _ERR_EXTRA_OFFSET,
ERR_EXTRA_ERRNO = 0x01 << _ERR_EXTRA_OFFSET,
ERR_EXTRA_GAI = 0x02 << _ERR_EXTRA_OFFSET,
ERR_EXTRA_GNUTLS = 0x03 << _ERR_EXTRA_OFFSET,
};
#define _ERROR_CODE(name, code, extra) name = (code | ERR_EXTRA_ ## extra)
/*
* List of defined error codes, organized mostly by function name
*/
enum error_code {
/* Core functions */
_ERROR_CODE( ERR_CALLOC, 0x000100, NONE ),
/* Network resolver errors */
_ERROR_CODE( ERR_GETADDRINFO, 0x000200, GAI ),
_ERROR_CODE( ERR_GETADDRINFO_EMPTY, 0x000201, GAI ),
/* Low-level network errors */
_ERROR_CODE( ERR_SOCKET, 0x000301, ERRNO ),
_ERROR_CODE( ERR_CONNECT, 0x000302, ERRNO ),
/* Low-level IO errors */
_ERROR_CODE( ERR_READ, 0x000401, ERRNO ),
_ERROR_CODE( ERR_READ_EOF, 0x000402, NONE ),
_ERROR_CODE( ERR_WRITE, 0x000403, ERRNO ),
/* GnuTLS errors */
_ERROR_CODE( ERR_GNUTLS_CERT_ALLOC_CRED, 0x010101, GNUTLS ),
_ERROR_CODE( ERR_GNUTLS_GLOBAL_INIT, 0x010102, GNUTLS ),
_ERROR_CODE( ERR_GNUTLS_INIT, 0x010103, GNUTLS ),
_ERROR_CODE( ERR_GNUTLS_SET_DEFAULT_PRIORITY, 0x010104, GNUTLS ),
_ERROR_CODE( ERR_GNUTLS_CRED_SET, 0x010105, GNUTLS ),
_ERROR_CODE( ERR_GNUTLS_HANDSHAKE, 0x010106, GNUTLS ),
// mask of bits used for the error_code value
_ERROR_CODE_MASK = 0xffffff,
};
/*
* An error code and associated extra infos
*/
struct error_info {
/* The base error code */
err_t code;
/* Additional detail info, usually some third-part error code */
unsigned int extra;
};
/*
* Translate an err_t into a function name.
*/
const char *error_name (err_t code);
/*
* Maximum length of error messages returned by error_msg (including NUL byte)
*/
#define ERROR_MSG_MAXLEN 1024
/*
* Translate an error_info into a message.
*
* This is returned as a pointer into a statically allocated buffer. It is not re-entrant.
*/
const char *error_msg (const struct error_info *err);
/** No error, evaulates as logical false */
#define SUCCESS (0)
/* Evaulates to error_info.code as lvalue */
#define ERROR_CODE(err_info_ptr) ((err_info_ptr)->code)
/* Evaulates to error_info.extra as lvalue */
#define ERROR_EXTRA(err_info_ptr) ((err_info_ptr)->extra)
/* Set error_info.code to SUCCESS, evaulates as zero */
#define RESET_ERROR(err_info_ptr) ((err_info_ptr)->code = SUCCESS)
/* Compare error_info.code != 0 */
#define IS_ERROR(err_info_ptr) (!!(err_info_ptr)->code)
/* Set error_info.code, but leave err_extra as-is. Evaluates to err_code */
#define SET_ERROR(err_info_ptr, err_code) ((err_info_ptr)->code = (err_code))
/* Set error_info.code/extra. XXX: should evaluate to err_code */
#define _SET_ERROR_EXTRA(err_info_ptr, err_code, err_extra) (err_info_ptr)->code = (err_code); (err_info_ptr)->extra = (err_extra)
#define SET_ERROR_EXTRA(err_info_ptr, err_code, err_extra) do { _SET_ERROR_EXTRA(err_info_ptr, err_code, err_extra); } while (0)
/* Set error_info.code to err_code, and .extra to errno. XXX: should evaulate to err_code */
#define _SET_ERROR_ERRNO(err_info_ptr, err_code) _SET_ERROR_EXTRA(err_info_ptr, err_code, errno);
#define SET_ERROR_ERRNO(err_info_ptr, err_code) SET_ERROR_EXTRA(err_info_ptr, err_code, errno);
/* Set error_info from another error_info. Evaluates to the new error_info */
#define SET_ERROR_INFO(err_info_ptr, from_ptr) (*err_info_ptr = *from_ptr)
/* Same as above, but also return err_code from func. XXX: use 'return SET_ERROR...' instead */
#define RETURN_SET_ERROR(err_info_ptr, err_code) do { SET_ERROR(err_info_ptr, err_code); return (err_code); } while (0)
#define RETURN_SET_ERROR_EXTRA(err_info_ptr, err_code, err_extra) do { _SET_ERROR_EXTRA(err_info_ptr, err_code, err_extra); return (err_code); } while (0)
#define RETURN_SET_ERROR_ERRNO(err_info_ptr, err_code) do { _SET_ERROR_ERRNO(err_info_ptr, err_code); return (err_code); } while (0)
#define RETURN_SET_ERROR_INFO(err_info_ptr, from_ptr) do { SET_ERROR_INFO(err_info_ptr, from_ptr); return (from_ptr->code); } while (0)
/* Same as above, but also do a 'goto error' */
#define JUMP_SET_ERROR(err_info_ptr, err_code) do { SET_ERROR(err_info_ptr, err_code); goto error; } while (0)
#define JUMP_SET_ERROR_INFO(err_info_ptr, from_ptr) do { SET_ERROR_INFO(err_info_ptr, from_ptr); goto error; } while (0)
#endif