src/error.h
author Tero Marttila <terom@fixme.fi>
Sun, 22 Feb 2009 10:16:28 +0200
changeset 10 9fe218576d13
parent 8 be88e543c8ff
child 11 14e79683c48c
permissions -rw-r--r--
fix sock_stream read/write return value, move line buffer inside of line_proto, add some initial code for event-based non-blocking operation
#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   ),
    _ERROR_CODE( ERR_FCNTL,                         0x000404,   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  ),
    _ERROR_CODE( ERR_GNUTLS_RECORD_SEND,            0x010107,   GNUTLS  ),
    _ERROR_CODE( ERR_GNUTLS_RECORD_RECV,            0x010108,   GNUTLS  ),

    /* Libevent errors */
    _ERROR_CODE( ERR_EVENT_NEW,                     0x010201,   NONE    ),
    
    // 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)

/* Compare the err_code/err_extra for an err_info */
#define MATCH_ERROR(err_info_ptr, err_code, err_extra) ((err_info_ptr)->code == (err_code) && (err_info_ptr)->extra == (err_extra))

/* 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