从stack容器结构看openssl中的一些设计

       首先希望看到这篇文章的你对openssl源码有一定的了解,因为本文是以栈这种openssl实现容器结构为例尝试把握openssl的设计。

       我在使用SI看openssl源码(1.1.0f)的时候,发现很多的函数定义找不到,而这些函数又不是库函数,也不是那种很直观的宏定义,一开始也挺郁闷,直到有一天,我明白了其中的道理,以sk_X509_new_null这个函数为例,该函数在源码中是找不到其定义的,分析如下:

       在openssl中,以sk开头的函数或者结构表示的是stack这种容器结构以及其相关的函数操作。在crypto/stack/stack.c中定义了栈的数据结构stack_st,当然栈作为一种容器,在其上的操作还包含对该容器的增删改查,排序等函数操作。当然具体的内容不做具体分析,可以直接查看该文件。

       可以看到stack_st这种结构作为openssl的一个基础容器,其设计的目的在于让这个容器去接纳不同的数据类型,方便数据的操作。当栈中存入的是int类型数据的时候,该栈就是一个int型栈;当存入的是一个string类型的话,该栈就是一个string类型栈;当存入的是一个x509类型的证书是,该栈就是一个证书栈。当然对于不同类型栈,对该类型栈的函数操作也会发生相应的变化,比如不同类型的比较函数就不相同。因此可以看到,stack_st的设计是一种较为通用的设计,如下:

struct stack_st {
    int num;
    const char **data;
    int sorted;
    size_t num_alloc;
    OPENSSL_sk_compfunc comp;
};

       其中存储数据的data字段被设计为一个二维指针,因为在C语言中,如果使用二维数组来理解的话,其中一维用来表示数据在栈中的位置,另一维用来指向具体的数据。

       再看include/openssl/stack.h中所有的函数声明中,入参都是函数指针以及const void *之类。

typedef int (*OPENSSL_sk_compfunc)(const void *, const void *);
typedef void (*OPENSSL_sk_freefunc)(void *);
typedef void *(*OPENSSL_sk_copyfunc)(const void *);

       由于函数指针可以指向不同类型的函数体,因此能够实现面向对象中的多态效果。当然C语言并不是面向对象语言,他是怎么样来实现这种思想呢?下面以X509为例着重介绍一下。

       在include/openssl/X509.h中是通过宏DEFINE_STACK_OF(X509)来定义X509栈的,而宏DEFINE_STACK_OF(t)的定义在 include/openssl/safestack.h中定义为# define DEFINE_STACK_OF(t) SKM_DEFINE_STACK_OF(t, t, t),当然看到最终的SKM_DEFINE_STACK_OF宏定义的时候,你会恍然大悟。原来C语言是通过宏替换来实现不同的派生类,以及函数的多态效果。而且只用DEFINE_STACK_OF(X509)这一条语句就将X509这个类型栈全部定义了。

       要说的是虽然C语言在设计上做到了面向对象的思想,但是带来的副作用却是代码的可读性降低,如果一开始不知道这种设计思想,看代码一定会看到崩溃。当然采用这种设计的还有就是include/openssl/lhash.h这个文件的内容实现的是哈希表这种容器。基本原理和stack是一致的。在看到lh开头的函数时候,应该就能知道其具体的定义了。

       当然关于openssl中面向对象的思想,后面在学习的过程中会继续分析。

       本文为CSDN村中少年原创文章,转载记得加上小尾巴偶,博主链接这里。

你可能感兴趣的:(OpenSSL,openssl,源码剖析)