openssl中,通过unsigned long类型来存放错误信息。它包含三部分内容:库代码、函数代码以及错误原因代码。其中,库代码在crypto/err.h中定义,函数代码以及错误原因代码由各个功能模块定义(同类代码不能与其他的重复,也不能超过一定的大小)。比如err.h中为BIO定义如下库代码:
/* library */
#define ERR_LIB_BIO 32
而crypto/bio.h中定义了如下函数和错误原因代号:
/* Function codes. */
#define BIO_F_ACPT_STATE 100
/* Reason codes. */
#define BIO_R_ACCEPT_ERROR 100
错误信息通过上述三部分通过计算得到,并且根据此信息能提取各个代码。计算函数在err.h中定义如下:
#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)>>
#define
ERR_GET_FUNC(l) (int)((((unsigned
long)l)>>
#define ERR_GET_REASON(l) (int)((l)&0xfffL)
可以看出,库的个数不能大于255(0xff),函数个数和错误原因不能大于4095(0xfff)。除非计算出来的值与已有的值没有冲突。
主要数据结构有两个,定义在crypto/err/err.h中,如下:
1)ERR_STRING_DATA
typedef struct ERR_string_data_st
{
unsigned long error;
const char *string;
} ERR_STRING_DATA;
该数据结构的内容由各个功能模块来设置。其中,error用来存放错误信息(由库代码、函数代码以及错误原因代码计算得来),string用来存放文本信息,可以是函数名也可以是错误原因。以crypto/bio_err.c为例,它定义了两个全局表,分别用来存放函数信息和错误信息:
#define ERR_FUNC(func) ERR_PACK(ERR_LIB_BIO,func,0)
#define ERR_REASON(reason) ERR_PACK(ERR_LIB_BIO,0,reason)
static ERR_STRING_DATA BIO_str_functs[]=
{
{ERR_FUNC(BIO_F_ACPT_STATE), "ACPT_STATE"},
……
}
static ERR_STRING_DATA BIO_str_reasons[]=
{
{ERR_REASON(BIO_R_ACCEPT_ERROR) ,"accept error"},
{ERR_REASON(BIO_R_BAD_FOPEN_MODE) ,"bad fopen mode"},
……
}
这两个表通过ERR_load_BIO_strings函数来添加到错误信息哈希表中去。为了便于查找,所有模块的错误信息存放在一个全局哈希表中,在crypto/err.c中实现。
2)ERR_STATE
typedef struct err_state_st
{
unsigned long pid;
int err_flags[ERR_NUM_ERRORS];
unsigned long err_buffer[ERR_NUM_ERRORS];
char *err_data[ERR_NUM_ERRORS];
int err_data_flags[ERR_NUM_ERRORS];
const char *err_file[ERR_NUM_ERRORS];
int err_line[ERR_NUM_ERRORS];
int top,bottom;
} ERR_STATE;
该结构用于存放和获取错误信息。由于可能会有多层函数调用(错误堆栈),这些信息都是一个数组。每个数组代表了一层函数的错误信息。各项意义如下:
pid:当前线程id。
err_buffer[i]:第i层错误码,包含库、函数以及错误原因信息。
err_data[i]:存放第i层操作信息。
err_data_flags[i]:存放err_data[i]相关的标记;比如为ERR_TXT_MALLOCED时,表名err_data[i]中的数据是动态分配内存的,需要释放;为ERR_TXT_STRING表名err_data[i]中的数据是一个字符串,可以用来打印。
err_file[i]:第i层错误的文件名。
err_line[i]:第i层错误的行号。
top和bottom:用于指明ERR_STATE的使用状态。top对应与最后一个错误(错误堆栈的最上层),bottom对应第一个错误(错误堆栈的最底层)。
当用户需要扩展openssl的模块时,可以仿照其他已有模块来实现自己的错误处理。