第十四章 错误处理 / 14.2 数据结构

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)>>24L)&0xffL)

#define ERR_GET_FUNC(l)         (int)((((unsigned long)l)>>12L)&0xfffL)

#define ERR_GET_REASON(l)    (int)((l)&0xfffL)

可以看出,库的个数不能大于2550xff),函数个数和错误原因不能大于40950xfff)。除非计算出来的值与已有的值没有冲突。

主要数据结构有两个,定义在crypto/err/err.h中,如下:

1ERR_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中实现。

       2ERR_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层错误的行号。

topbottom:用于指明ERR_STATE的使用状态。top对应与最后一个错误(错误堆栈的最上层),bottom对应第一个错误(错误堆栈的最底层)。

              当用户需要扩展openssl的模块时,可以仿照其他已有模块来实现自己的错误处理。