sk_new() -- SSLeay 0.9.0b -- January 1999

NAME

ERR_PUT_error, ERR_PACK, ERR_GET_LIB, ERR_GET_FUNC, ERR_GET_REASON, ERR_FATAL_ERROR,
ERR_put_error, ERR_set_error_data, ERR_get_error, ERR_get_error_line,
ERR_get_error_line_data, ERR_peek_error, ERR_peek_error_line,
ERR_peek_error_line_data, ERR_clear_error, ERR_error_string,
ERR_lib_error_string, ERR_func_error_string, ERR_reason_error_string,
ERR_print_errors_fp, ERR_print_errors, ERR_add_error_data, ERR_load_strings,
ERR_load_ERR_strings, ERR_load_crypto_strings, ERR_free_strings,
ERR_remove_state, ERR_get_state, ERR_get_string_table,
ERR_get_err_state_table, ERR_get_next_error_library -- error handling

SYNOPSIS

#include "err.h"

void ERR_put_error(lib, func, reason, file, line)
int lib, func, reason, line;
char *file;

void ERR_set_error_data(data, flags)
char *data;
int flags;

unsigned long ERR_get_error();

unsigned long ERR_get_error_line(file, line)
char **file;
int *line;

unsigned long ERR_get_error_line_data(file, line, data, flags)
char **file, **data;
int *linem *flags;

unsigned long ERR_peek_error();

unsigned long ERR_peek_error_line(file, line)
char **file;
int *line;

unsigned long ERR_peek_error_line_data(file, line, data, flags)
char **file, **data;
int *line, *flags;

void ERR_clear_error();

char *ERR_error_string(e, buf)
unsigned long e;
char *buf;

char *ERR_lib_error_string(e)
unsigned long e;

char *ERR_func_error_string(e)
unsigned long e;

char *ERR_reason_error_string(e)
unsigned long e;

void ERR_print_errors_fp(fp)
FILE *fp;

void ERR_print_errors(bp)
BIO *bp;

void ERR_add_error_data( VAR_PLIST( int, num ) );

void ERR_load_strings(lib, str)
int lib; ERR_STRING_DATA str[];

void ERR_load_ERR_strings();

void ERR_load_crypto_strings();

void ERR_free_strings();

void ERR_remove_state(pid)
unsigned long pid;

ERR_STATE *ERR_get_state();

LHASH *ERR_get_string_table();

LHASH *ERR_get_err_state_table();

int ERR_get_next_error_library();

DESCRIPTION

The error system implemented in this library is intended to serve two purposes: to record the reason why a command failed and to record where in the libraries the failure occurred. It is more or less set up to record a sort of trace of which library components were being traversed when the error occurred.

When an error is recorded, it is done so a as single unsigned long which is composed of three parts. The top byte is the number corresponding to the library (RSA, X509, STACK, and so on), the middle 12 bits is the function code, and the bottom 12 bits is the reason code.

Each library of SSLeay has a different unique library error number. Each function in the library has a number that is unique for that library. Each library also has a number for each error reason that is only unique for that library.

Due to the way these error routines record a trace of which routines were executed on route to the error, there is one array per thread that is used to store the error codes. The various functions in this library are used to access and manipulate this array.

In order to translate these error codes into human-readable strings, we have a static table which maps library/function/reason codes to text strings.

This table actually consists of three static arrays of ERR_STRING_DATA: ERR_str_libraries, ERR_str_functs, and ERR_str_reasons. ERR_STRING_DATA is defined as follows:

typedef struct ERR_string_data_st
        {
        unsigned long error;
        char *string;
        } ERR_STRING_DATA;

The 'ERR_STRING_DATA' contains an error code and the corresponding text string. To add new function error strings for a library, the ERR_STRING_DATA needs to be 'registered' with the library.

Errors are recorded in a static hash table error_hash of ERR_STATE, defined as follows:

typedef struct err_state_st
        {
        unsigned long pid;
        unsigned long err_buffer[ERR_NUM_ERRORS];
        char *err_data[ERR_NUM_ERRORS];
        int err_data_flags[ERR_NUM_ERRORS];
        char *err_file[ERR_NUM_ERRORS];
        int err_line[ERR_NUM_ERRORS];
        int top,bottom;
        } ERR_STATE;

Each thread has its own copy of this table.

Checking errors from the library

ERR_get_error returns as an unsigned long the last error in the static error list and removes the entry from the list. If no errors are available 0 is returned.

ERR_get_error_line does the same as ERR_get_error but in addition retrieves the name of the file and the line number in which the error occured, returning these values in *file and *line respectively.

ERR_get_error_line_data does the same as ERR_get_error_line but in addition retrieves the text error message and any flags set, returning these values in *data and *flags respectively.

ERR_error_string returns the error string corresponding to the numeric error code e in buf if buf is not NULL, and returns a pointer to the message in either case. If you haven't loaded up all of the error strings in advance, the unpacked form of the error code will be returned in human-readable text, which is better than nothing. buf should be at least 120 bytes long; the function uses sprintf and does not check for buffer overruns.

ERR_peek_error returns as an unsigned long the last error in the static error list, as in ERR_get_error, but leaves the error in the list for future retrieval. If no errors are available 0 is returned.

ERR_peek_error_line does the same as ERR_peek_error but in addition retrieves the name of the file and the line number in which the error occured, returning these values in *file and *line respectively.

ERR_peek_error_line_data does the same as ERR_peek_error_line but in addition retrieves the text error message and any flags set, returning these values in *data and *flags respectively.

Translating error codes

ERR_lib_error_string returns a pointer to the name of the library corresponding to the numeric error code e, or NULL if it can't find a match. Don't free this pointer! It points into a static list.

ERR_func_error_string returns a pointer to the name of the function corresponding to the numeric error code e, or NULL if it can't find a match. Don't free this pointer! It points into a static list.

ERR_reason_error_string returns a pointer to the text error message corresponding to the numeric error code e, or NULL if it can't find a match. Don't free this pointer! It points into a static list.

Printing errors

ERR_print_errors_fp prints out all errors to the file fp in the static error list in human-readable form. The errors are removed from the static buffer as they are printed.

ERR_print_errors does what ERR_print_errors_fp does except that it uses a BIO instead of a file pointer. In fact, ERR_print_errors_fp calls this function.

Registering error strings for later use by a library

ERR_load_crypto_strings should be called only once; it loads the error strings for all parts of the crypto library. If you do call it more than once, it checks a static variable and returns right away, lucky you!

ERR_load_strings loads up for lib the array of ERR_STRING_DATA pointed to by err. It also does ERR_load_ERR_strings as a special bonus :)

ERR_load_ERR_strings initializes arrays for the error-handling library with messages specific to the ERR library. Call this before using any ERR routines in your code.

ERR_free_strings frees all error strings loaded into the static error table that maps library/function/reason codes to text strings.

ERR_get_string_table returns a pointer to the static error table that maps library/function/reason codes to text strings.

Flagging an error from your code

ERR_put_error adds the error contained in line, numeric error code reason, from the function func and the library lib, to a static list of errors. This static list can only contain 16 errors, so if you add one more then the oldest error gets overwritten.

ERR_clear_error empties the static list of error messages.

void ERR_add_error_data( VAR_PLIST( int, num ) );

void ERR_set_error_data(char *data,int flags); sets the data and flags subfields of the top entry in the static list of errors; these don't get set with ERR_put_error, which sets all the *other* subfields.

An example of the call, used in conf/conf.c, is:

ERR_set_error_data(BUF_strdup(file), ERR_TXT_MALLOCED|ERR_TXT_STRING);
CONFerr(CONF_F_CONF_LOAD,ERR_R_SYS_LIB);

where CONFerr is a macro which calls ERR_put_error with appropriate values for the CONF library and the particular function that called it. First the application sets data to be printed out along with the standard error message (in this case, the name of a file), and sets flags indicating that the text data was malloced and is a character string, so that the library knows how to free it later. Then the application sets the rest of the error fields with ERR_LIB_CONF, CONF_F_CONF_LOAD, ERR_R_SYS_LIB, ERR_file_name, and the line number (__LINE__).

Here's the full set of macros for the libraries, all defined in err.h:

#define SYSerr(f,r)  ERR_PUT_error(ERR_LIB_SYS,(f),(r),ERR_file_name,__LINE__)
#define BNerr(f,r)   ERR_PUT_error(ERR_LIB_BN,(f),(r),ERR_file_name,__LINE__)
#define RSAerr(f,r)  ERR_PUT_error(ERR_LIB_RSA,(f),(r),ERR_file_name,__LINE__)
#define DHerr(f,r)   ERR_PUT_error(ERR_LIB_DH,(f),(r),ERR_file_name,__LINE__)
#define EVPerr(f,r)  ERR_PUT_error(ERR_LIB_EVP,(f),(r),ERR_file_name,__LINE__)
#define BUFerr(f,r)  ERR_PUT_error(ERR_LIB_BUF,(f),(r),ERR_file_name,__LINE__)
#define BIOerr(f,r)  ERR_PUT_error(ERR_LIB_BIO,(f),(r),ERR_file_name,__LINE__)
#define OBJerr(f,r)  ERR_PUT_error(ERR_LIB_OBJ,(f),(r),ERR_file_name,__LINE__)
#define PEMerr(f,r)  ERR_PUT_error(ERR_LIB_PEM,(f),(r),ERR_file_name,__LINE__)
#define DSAerr(f,r)  ERR_PUT_error(ERR_LIB_DSA,(f),(r),ERR_file_name,__LINE__)
#define X509err(f,r) ERR_PUT_error(ERR_LIB_X509,(f),(r),ERR_file_name,__LINE__)
#define METHerr(f,r) ERR_PUT_error(ERR_LIB_METH,(f),(r),ERR_file_name,__LINE__)
#define ASN1err(f,r) ERR_PUT_error(ERR_LIB_ASN1,(f),(r),ERR_file_name,__LINE__)
#define CONFerr(f,r) ERR_PUT_error(ERR_LIB_CONF,(f),(r),ERR_file_name,__LINE__)
#define CRYPTOerr(f,r) ERR_PUT_error(ERR_LIB_CRYPTO,(f),(r),ERR_file_name,__LINE__)
#define SSLerr(f,r)  ERR_PUT_error(ERR_LIB_SSL,(f),(r),ERR_file_name,__LINE__)
#define SSL23err(f,r) ERR_PUT_error(ERR_LIB_SSL23,(f),(r),ERR_file_name,__LINE__)
#define SSL2err(f,r) ERR_PUT_error(ERR_LIB_SSL2,(f),(r),ERR_file_name,__LINE__)
#define SSL3err(f,r) ERR_PUT_error(ERR_LIB_SSL3,(f),(r),ERR_file_name,__LINE__)
#define RSAREFerr(f,r) ERR_PUT_error(ERR_LIB_RSAREF,(f),(r),ERR_file_name,__LINE__)
#define PROXYerr(f,r) ERR_PUT_error(ERR_LIB_PROXY,(f),(r),ERR_file_name,__LINE__)
#define PKCS7err(f,r) ERR_PUT_error(ERR_LIB_PKCS7,(f),(r),ERR_file_name,__LINE__)

Miscellaneous

ERR_get_next_error_library returns the next unused number that can be used to register library error codes. It uses a static variable to keep track. This function is not called by *anything* at present and is either left over from old code or part of something that hasn't been written yet. Someone can tell me which someday.

Thread-related routines

ERR_get_state returns a pointer to the static error state table for the calling thread but if there is no such table will allocate and initialize it first in a thread-safe way. Use this instead of ERR_get_err_state_table.

ERR_get_err_state_table returns a pointer to the static error state table for the calling thread.

ERR_remove_state frees the static error state table for the particular pid; if pid is 0, then this is done for the current process. If you do not remove the error state of a thread, this could be considered a form of memory leak, so just after reaping a thread that has died, call ERR_remove_state(pid).

The following macros are provided for the convenience of the user:

#define ERR_PUT_error(a,b,c,d,e)        ERR_put_error(a,b,c,d,e)
#define ERR_PACK(l,f,r)         (((((unsigned long)l)&0xffL)*0x1000000)| \
                                ((((unsigned long)f)&0xfffL)*0x1000)| \
                                ((((unsigned long)r)&0xfffL)))
#define ERR_GET_LIB(l)          (int)((((unsigned long)l)>>24L)&0xffL)
#define ERR_GET_FUNC(l)         (int)((((unsigned long)l)>>12L)&0xfffL)
#define ERR_GET_REASON(l)       (int)((l)&0xfffL)
#define ERR_FATAL_ERROR(l)      (int)((l)&ERR_R_FATAL)