读openssl的源码一直可以看到DEFINE_STACK_OF这个宏,它被定义在safestack.h这个头文件中。openssl的堆栈实现共涉及到三个文件,stack.h、stack.c 和safestack.h;其中stack.h、stack.c 实现了stack_st结构体,及对该结构体对象进行操作的一系列以OPENSSL_sk开头的函数,主要有:堆栈拷贝(OPENSSL_sk_dup)、构建新堆栈(OPENSSL_sk_new_null,OPENSSL_sk_new)、插入数据(OPENSSL_sk_insert)、删除数据(OPENSSL_sk_delete)、查找数据(OPENSSL_sk_find,OPENSSL_sk_find_ex)、入栈(OPENSSL_sk_push)、出栈(OPENSSL_sk_pop)、获取堆栈元素个数(OPENSSL_sk_num)、获取堆栈值(OPENSSL_sk_value)、设置堆栈值(OPENSSL_sk_set)和堆栈排序(OPENSSL_sk_sort)。
比对openssl0.9.6版本,stack_st,被定义成STACK,
typedef struct stack_st
{
int num;
char **data;
int sorted;
int num_alloc;
int (*comp)(const char * const *, const char * const *);
} STACK;
而openssl1.1.0版本,该结构体声明在了stack.c文件中,且在stack.h中,typedef struct stack_st OPENSSL_STACK; /* Use STACK_OF(...) instead */ 使得调用者对该结构体的具体成员不得操作,有点类的私有成员变量的意思在里边.
safestack.h封装的提升使得SKM_DEFINE_STACK_OF(t1, t2, t3),出现了多态的样式,只要给该宏传入类型即可用他生成一套对该数据类型操作的函数来,而其本质还是转换为对OPENSSL_STACK 类型的操作。
# define STACK_OF(type) struct stack_st_##type
# define SKM_DEFINE_STACK_OF(t1, t2, t3) \
STACK_OF(t1); \
typedef int (*sk_##t1##_compfunc)(const t3 * const *a, const t3 *const *b); \
typedef void (*sk_##t1##_freefunc)(t3 *a); \
typedef t3 * (*sk_##t1##_copyfunc)(const t3 *a); \
static ossl_inline int sk_##t1##_num(const STACK_OF(t1) *sk) \
{ \
return OPENSSL_sk_num((const OPENSSL_STACK *)sk); \
} \
static ossl_inline t2 *sk_##t1##_value(const STACK_OF(t1) *sk, int idx) \
{ \
return (t2 *)OPENSSL_sk_value((const OPENSSL_STACK *)sk, idx); \
} \
static ossl_inline STACK_OF(t1) *sk_##t1##_new(sk_##t1##_compfunc compare) \
{ \
return (STACK_OF(t1) *)OPENSSL_sk_new((OPENSSL_sk_compfunc)compare); \
} \
static ossl_inline STACK_OF(t1) *sk_##t1##_new_null(void) \
{ \
return (STACK_OF(t1) *)OPENSSL_sk_new_null(); \
} \
static ossl_inline STACK_OF(t1) *sk_##t1##_new_reserve(sk_##t1##_compfunc compare, int n) \
{ \
return (STACK_OF(t1) *)OPENSSL_sk_new_reserve((OPENSSL_sk_compfunc)compare, n); \
} \
static ossl_inline int sk_##t1##_reserve(STACK_OF(t1) *sk, int n) \
{ \
return OPENSSL_sk_reserve((OPENSSL_STACK *)sk, n); \
} \
static ossl_inline void sk_##t1##_free(STACK_OF(t1) *sk) \
{ \
OPENSSL_sk_free((OPENSSL_STACK *)sk); \
} \
static ossl_inline void sk_##t1##_zero(STACK_OF(t1) *sk) \
{ \
OPENSSL_sk_zero((OPENSSL_STACK *)sk); \
} \
static ossl_inline t2 *sk_##t1##_delete(STACK_OF(t1) *sk, int i) \
{ \
return (t2 *)OPENSSL_sk_delete((OPENSSL_STACK *)sk, i); \
} \
static ossl_inline t2 *sk_##t1##_delete_ptr(STACK_OF(t1) *sk, t2 *ptr) \
{ \
return (t2 *)OPENSSL_sk_delete_ptr((OPENSSL_STACK *)sk, \
(const void *)ptr); \
} \
static ossl_inline int sk_##t1##_push(STACK_OF(t1) *sk, t2 *ptr) \
{ \
return OPENSSL_sk_push((OPENSSL_STACK *)sk, (const void *)ptr); \
} \
static ossl_inline int sk_##t1##_unshift(STACK_OF(t1) *sk, t2 *ptr) \
{ \
return OPENSSL_sk_unshift((OPENSSL_STACK *)sk, (const void *)ptr); \
} \
static ossl_inline t2 *sk_##t1##_pop(STACK_OF(t1) *sk) \
{ \
return (t2 *)OPENSSL_sk_pop((OPENSSL_STACK *)sk); \
} \
static ossl_inline t2 *sk_##t1##_shift(STACK_OF(t1) *sk) \
{ \
return (t2 *)OPENSSL_sk_shift((OPENSSL_STACK *)sk); \
} \
static ossl_inline void sk_##t1##_pop_free(STACK_OF(t1) *sk, sk_##t1##_freefunc freefunc) \
{ \
OPENSSL_sk_pop_free((OPENSSL_STACK *)sk, (OPENSSL_sk_freefunc)freefunc); \
} \
static ossl_inline int sk_##t1##_insert(STACK_OF(t1) *sk, t2 *ptr, int idx) \
{ \
return OPENSSL_sk_insert((OPENSSL_STACK *)sk, (const void *)ptr, idx); \
} \
static ossl_inline t2 *sk_##t1##_set(STACK_OF(t1) *sk, int idx, t2 *ptr) \
{ \
return (t2 *)OPENSSL_sk_set((OPENSSL_STACK *)sk, idx, (const void *)ptr); \
} \
static ossl_inline int sk_##t1##_find(STACK_OF(t1) *sk, t2 *ptr) \
{ \
return OPENSSL_sk_find((OPENSSL_STACK *)sk, (const void *)ptr); \
} \
static ossl_inline int sk_##t1##_find_ex(STACK_OF(t1) *sk, t2 *ptr) \
{ \
return OPENSSL_sk_find_ex((OPENSSL_STACK *)sk, (const void *)ptr); \
} \
static ossl_inline void sk_##t1##_sort(STACK_OF(t1) *sk) \
{ \
OPENSSL_sk_sort((OPENSSL_STACK *)sk); \
} \
static ossl_inline int sk_##t1##_is_sorted(const STACK_OF(t1) *sk) \
{ \
return OPENSSL_sk_is_sorted((const OPENSSL_STACK *)sk); \
} \
static ossl_inline STACK_OF(t1) * sk_##t1##_dup(const STACK_OF(t1) *sk) \
{ \
return (STACK_OF(t1) *)OPENSSL_sk_dup((const OPENSSL_STACK *)sk); \
} \
static ossl_inline STACK_OF(t1) *sk_##t1##_deep_copy(const STACK_OF(t1) *sk, \
sk_##t1##_copyfunc copyfunc, \
sk_##t1##_freefunc freefunc) \
{ \
return (STACK_OF(t1) *)OPENSSL_sk_deep_copy((const OPENSSL_STACK *)sk, \
(OPENSSL_sk_copyfunc)copyfunc, \
(OPENSSL_sk_freefunc)freefunc); \
} \
static ossl_inline sk_##t1##_compfunc sk_##t1##_set_cmp_func(STACK_OF(t1) *sk, sk_##t1##_compfunc compare) \
{ \
return (sk_##t1##_compfunc)OPENSSL_sk_set_cmp_func((OPENSSL_STACK *)sk, (OPENSSL_sk_compfunc)compare); \
}
仔细阅读你会发现,STACK_OF(type) 只有对新类型结构体的声明而没有定义,与0.9.6版本的实现不同。如下
#define STACK_OF(type) struct stack_st_##type
#define PREDECLARE_STACK_OF(type) STACK_OF(type);
#define DECLARE_STACK_OF(type) \
STACK_OF(type) \
{ \
STACK stack; \
}; //0.9.6 STACK_OF(type) 结构的定义
我在这块陷入了困境,而后请教前辈才渐渐悟到其中道理,此处只声明了结构体,在使用的时候,也仅只是定义了一个结构体对象的指针,也即结构体的入口地址,结构体中存储的成员,他并不直接去访问。而是通过宏里边实现的操作函数,把STACK_OF(type)转为stack_st类型,调用OPENSSL_STACK(和stack_st是一个)结构的操作函数去处理成员。STACK_OF(type)虽然没有定义成员,但它的对象有存放地址,该地址处存放的数据的类型,和stack_st成员的类型一模一样,操作的时候,只要按照stack_st的内存结构去读去写即可。
至此其他人也可以利用宏define SKM_DEFINE_STACK_OF(t1, t2, t3)定义出对t1结构对象操作的一套API出来,我简单测试如下:
#include "openssl/stack.h"
#include "openssl/X509.h"
struct TASK
{
int ID;
std::string name;
std::string otherInfo;
};
DEFINE_STACK_OF(TASK)
int compareFun(const TASK * const *first, const TASK *const *second)
{
return (*first)->ID - (*second)->ID;
}
void freeTeskFun(TASK *task)
{
delete task;
}
void taskStackTest()
{
STACK_OF(TASK) *mytask = sk_TASK_new(compareFun);
TASK *t1=new TASK{1,std::string{"ssss"},std::string{"other1"}};
sk_TASK_push(mytask, t1);
TASK *t2 = new TASK{int(2),std::string{"two"},std::string{"twootherinfo"}};
sk_TASK_push(mytask, t2);
std::cout << sk_TASK_num(mytask) << std::endl;
TASK *popDT = static_cast<TASK *>(sk_TASK_pop(mytask));
std::cout << popDT->ID<<" "<< popDT->name << std::endl;
delete popDT;
//OPENSSL_STACK *ll = (OPENSSL_STACK *)mytask;
sk_TASK_pop_free(mytask,freeTeskFun);
}