openssl编程-基础知识-OpenSSL堆栈

堆栈介绍

  • 堆栈是一种先进后出的数据结构
  • openssl 大量采用堆栈来存放数据。它实现了一 个通用的堆栈,可以方便的存储任意数据
  • 它实现了许多基本的堆栈操作,主要有:堆栈拷贝(sk_dup)、构建新堆栈(sk_new_null,sk_new)、插入数据(sk_insert)、删除数据(sk_delete)、查找数据(sk_find,sk_find_ex)、入栈(sk_push)、出栈(sk_pop)、获取堆栈元素个数(sk_num)、获取堆栈值(sk_value)、设置堆栈值(sk_set)和堆栈排序(sk_sort)

数据结构

  • openssl 堆栈数据结构在 stack.h 中
  • stack.h 位于 include/openssl文件夹下
  • 定义位于crypto/stack文件夹下的stack.c文件内,具体内容如下:

stack.h

/** Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.** Licensed under the OpenSSL license (the "License").  You may not use* this file except in compliance with the License.  You can obtain a copy* in the file LICENSE in the source distribution or at* https://www.openssl.org/source/license.html*/#ifndef HEADER_STACK_H
# define HEADER_STACK_H#ifdef  __cplusplus
extern "C" {
#endiftypedef struct stack_st OPENSSL_STACK; /* Use STACK_OF(...) instead */typedef int (*OPENSSL_sk_compfunc)(const void *, const void *);
typedef void (*OPENSSL_sk_freefunc)(void *);
typedef void *(*OPENSSL_sk_copyfunc)(const void *);int OPENSSL_sk_num(const OPENSSL_STACK *);
void *OPENSSL_sk_value(const OPENSSL_STACK *, int);void *OPENSSL_sk_set(OPENSSL_STACK *st, int i, const void *data);OPENSSL_STACK *OPENSSL_sk_new(OPENSSL_sk_compfunc cmp);
OPENSSL_STACK *OPENSSL_sk_new_null(void);
void OPENSSL_sk_free(OPENSSL_STACK *);
void OPENSSL_sk_pop_free(OPENSSL_STACK *st, void (*func) (void *));
OPENSSL_STACK *OPENSSL_sk_deep_copy(const OPENSSL_STACK *, OPENSSL_sk_copyfunc c, OPENSSL_sk_freefunc f);
int OPENSSL_sk_insert(OPENSSL_STACK *sk, const void *data, int where);
void *OPENSSL_sk_delete(OPENSSL_STACK *st, int loc);
void *OPENSSL_sk_delete_ptr(OPENSSL_STACK *st, const void *p);
int OPENSSL_sk_find(OPENSSL_STACK *st, const void *data);
int OPENSSL_sk_find_ex(OPENSSL_STACK *st, const void *data);
int OPENSSL_sk_push(OPENSSL_STACK *st, const void *data);
int OPENSSL_sk_unshift(OPENSSL_STACK *st, const void *data);
void *OPENSSL_sk_shift(OPENSSL_STACK *st);
void *OPENSSL_sk_pop(OPENSSL_STACK *st);
void OPENSSL_sk_zero(OPENSSL_STACK *st);
OPENSSL_sk_compfunc OPENSSL_sk_set_cmp_func(OPENSSL_STACK *sk, OPENSSL_sk_compfunc cmp);
OPENSSL_STACK *OPENSSL_sk_dup(const OPENSSL_STACK *st);
void OPENSSL_sk_sort(OPENSSL_STACK *st);
int OPENSSL_sk_is_sorted(const OPENSSL_STACK *st);# if OPENSSL_API_COMPAT < 0x10100000L
#  define _STACK OPENSSL_STACK
#  define sk_num OPENSSL_sk_num
#  define sk_value OPENSSL_sk_value
#  define sk_set OPENSSL_sk_set
#  define sk_new OPENSSL_sk_new
#  define sk_new_null OPENSSL_sk_new_null
#  define sk_free OPENSSL_sk_free
#  define sk_pop_free OPENSSL_sk_pop_free
#  define sk_deep_copy OPENSSL_sk_deep_copy
#  define sk_insert OPENSSL_sk_insert
#  define sk_delete OPENSSL_sk_delete
#  define sk_delete_ptr OPENSSL_sk_delete_ptr
#  define sk_find OPENSSL_sk_find
#  define sk_find_ex OPENSSL_sk_find_ex
#  define sk_push OPENSSL_sk_push
#  define sk_unshift OPENSSL_sk_unshift
#  define sk_shift OPENSSL_sk_shift
#  define sk_pop OPENSSL_sk_pop
#  define sk_zero OPENSSL_sk_zero
#  define sk_set_cmp_func OPENSSL_sk_set_cmp_func
#  define sk_dup OPENSSL_sk_dup
#  define sk_sort OPENSSL_sk_sort
#  define sk_is_sorted OPENSSL_sk_is_sorted
# endif#ifdef  __cplusplus
}
#endif#endif

stack.cpp

/** Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.** Licensed under the OpenSSL license (the "License").  You may not use* this file except in compliance with the License.  You can obtain a copy* in the file LICENSE in the source distribution or at* https://www.openssl.org/source/license.html*/#include <stdio.h>
#include "internal/cryptlib.h"
#include "internal/numbers.h"
#include <openssl/stack.h>
#include <openssl/objects.h>struct stack_st {int num;const char **data;int sorted;size_t num_alloc;OPENSSL_sk_compfunc comp;
};#undef MIN_NODES
#define MIN_NODES       4#include <errno.h>OPENSSL_sk_compfunc OPENSSL_sk_set_cmp_func(OPENSSL_STACK *sk, OPENSSL_sk_compfunc c)
{OPENSSL_sk_compfunc old = sk->comp;if (sk->comp != c)sk->sorted = 0;sk->comp = c;return old;
}OPENSSL_STACK *OPENSSL_sk_dup(const OPENSSL_STACK *sk)
{OPENSSL_STACK *ret;if (sk->num < 0)return NULL;if ((ret = OPENSSL_malloc(sizeof(*ret))) == NULL)return NULL;/* direct structure assignment */*ret = *sk;if ((ret->data = OPENSSL_malloc(sizeof(*ret->data) * sk->num_alloc)) == NULL)goto err;memcpy(ret->data, sk->data, sizeof(char *) * sk->num);return ret;err:OPENSSL_sk_free(ret);return NULL;
}OPENSSL_STACK *OPENSSL_sk_deep_copy(const OPENSSL_STACK *sk,OPENSSL_sk_copyfunc copy_func,OPENSSL_sk_freefunc free_func)
{OPENSSL_STACK *ret;int i;if (sk->num < 0)return NULL;if ((ret = OPENSSL_malloc(sizeof(*ret))) == NULL)return NULL;/* direct structure assignment */*ret = *sk;ret->num_alloc = sk->num > MIN_NODES ? (size_t)sk->num : MIN_NODES;ret->data = OPENSSL_zalloc(sizeof(*ret->data) * ret->num_alloc);if (ret->data == NULL) {OPENSSL_free(ret);return NULL;}for (i = 0; i < ret->num; ++i) {if (sk->data[i] == NULL)continue;if ((ret->data[i] = copy_func(sk->data[i])) == NULL) {while (--i >= 0)if (ret->data[i] != NULL)free_func((void *)ret->data[i]);OPENSSL_sk_free(ret);return NULL;}}return ret;
}OPENSSL_STACK *OPENSSL_sk_new_null(void)
{return OPENSSL_sk_new((OPENSSL_sk_compfunc)NULL);
}OPENSSL_STACK *OPENSSL_sk_new(OPENSSL_sk_compfunc c)
{OPENSSL_STACK *ret;if ((ret = OPENSSL_zalloc(sizeof(*ret))) == NULL)goto err;if ((ret->data = OPENSSL_zalloc(sizeof(*ret->data) * MIN_NODES)) == NULL)goto err;ret->comp = c;ret->num_alloc = MIN_NODES;return (ret);err:OPENSSL_free(ret);return (NULL);
}int OPENSSL_sk_insert(OPENSSL_STACK *st, const void *data, int loc)
{if (st == NULL || st->num < 0 || st->num == INT_MAX) {return 0;}if (st->num_alloc <= (size_t)(st->num + 1)) {size_t doub_num_alloc = st->num_alloc * 2;const char **tmpdata;/* Overflow checks */if (doub_num_alloc < st->num_alloc)return 0;/* Avoid overflow due to multiplication by sizeof(char *) */if (doub_num_alloc > SIZE_MAX / sizeof(char *))return 0;tmpdata = OPENSSL_realloc((char *)st->data,sizeof(char *) * doub_num_alloc);if (tmpdata == NULL)return 0;st->data = tmpdata;st->num_alloc = doub_num_alloc;}if ((loc >= st->num) || (loc < 0)) {st->data[st->num] = data;} else {memmove(&st->data[loc + 1], &st->data[loc],sizeof(st->data[0]) * (st->num - loc));st->data[loc] = data;}st->num++;st->sorted = 0;return st->num;
}void *OPENSSL_sk_delete_ptr(OPENSSL_STACK *st, const void *p)
{int i;for (i = 0; i < st->num; i++)if (st->data[i] == p)return OPENSSL_sk_delete(st, i);return NULL;
}void *OPENSSL_sk_delete(OPENSSL_STACK *st, int loc)
{const char *ret;if (st == NULL || loc < 0 || loc >= st->num)return NULL;ret = st->data[loc];if (loc != st->num - 1)memmove(&st->data[loc], &st->data[loc + 1],sizeof(st->data[0]) * (st->num - loc - 1));st->num--;return (void *)ret;
}static int internal_find(OPENSSL_STACK *st, const void *data,int ret_val_options)
{const void *r;int i;if (st == NULL)return -1;if (st->comp == NULL) {for (i = 0; i < st->num; i++)if (st->data[i] == data)return (i);return (-1);}OPENSSL_sk_sort(st);if (data == NULL)return (-1);r = OBJ_bsearch_ex_(&data, st->data, st->num, sizeof(void *), st->comp,ret_val_options);if (r == NULL)return (-1);return (int)((const char **)r - st->data);
}int OPENSSL_sk_find(OPENSSL_STACK *st, const void *data)
{return internal_find(st, data, OBJ_BSEARCH_FIRST_VALUE_ON_MATCH);
}int OPENSSL_sk_find_ex(OPENSSL_STACK *st, const void *data)
{return internal_find(st, data, OBJ_BSEARCH_VALUE_ON_NOMATCH);
}int OPENSSL_sk_push(OPENSSL_STACK *st, const void *data)
{return (OPENSSL_sk_insert(st, data, st->num));
}int OPENSSL_sk_unshift(OPENSSL_STACK *st, const void *data)
{return (OPENSSL_sk_insert(st, data, 0));
}void *OPENSSL_sk_shift(OPENSSL_STACK *st)
{if (st == NULL)return (NULL);if (st->num <= 0)return (NULL);return (OPENSSL_sk_delete(st, 0));
}void *OPENSSL_sk_pop(OPENSSL_STACK *st)
{if (st == NULL)return (NULL);if (st->num <= 0)return (NULL);return (OPENSSL_sk_delete(st, st->num - 1));
}void OPENSSL_sk_zero(OPENSSL_STACK *st)
{if (st == NULL)return;if (st->num <= 0)return;memset(st->data, 0, sizeof(*st->data) * st->num);st->num = 0;
}void OPENSSL_sk_pop_free(OPENSSL_STACK *st, OPENSSL_sk_freefunc func)
{int i;if (st == NULL)return;for (i = 0; i < st->num; i++)if (st->data[i] != NULL)func((char *)st->data[i]);OPENSSL_sk_free(st);
}void OPENSSL_sk_free(OPENSSL_STACK *st)
{if (st == NULL)return;OPENSSL_free(st->data);OPENSSL_free(st);
}int OPENSSL_sk_num(const OPENSSL_STACK *st)
{if (st == NULL)return -1;return st->num;
}void *OPENSSL_sk_value(const OPENSSL_STACK *st, int i)
{if (st == NULL || i < 0 || i >= st->num)return NULL;return (void *)st->data[i];
}void *OPENSSL_sk_set(OPENSSL_STACK *st, int i, const void *data)
{if (st == NULL || i < 0 || i >= st->num)return NULL;st->data[i] = data;return (void *)st->data[i];
}void OPENSSL_sk_sort(OPENSSL_STACK *st)
{if (st && !st->sorted && st->comp != NULL) {qsort(st->data, st->num, sizeof(char *), st->comp);st->sorted = 1;}
}int OPENSSL_sk_is_sorted(const OPENSSL_STACK *st)
{if (st == NULL)return 1;return st->sorted;
}

数据结构

struct stack_st {int num;const char **data;int sorted;size_t num_alloc;OPENSSL_sk_compfunc comp;
};
  • 各项意义如下:
    • num: 堆栈中存放数据的个数。
    • data:  用于存放数据地址,每个数据地址存放在 data[0]到 data[num-1]中。
    • sorted: 堆栈是否已排序,如果排序则值为 1,否则为 0,堆栈数据一般是无序的,只有当用户调用了 sk_sort 操作,其值才为 1。
    • comp: 堆栈内存放数据的比较函数地址,此函数用于排序和查找操作;当用户生成一 个新堆栈时,可以指定comp为用户实现的一个比较函数;或当堆栈已经存在 时通过调用 sk_set_cmp_func 函数来重新指定比较函数。
  • 注意,用户不需要调用底层的堆栈函数(sk_sort、sk_set_cmp_func 等),而是调用他通过 宏实现的各个函数。

函数介绍

  • openssl 堆栈实现源码位于 crypto/stack 目录下。下面分析了部分函数。
  •  sk_set_cmp_func
  • 此函数用于设置堆栈存放数据的比较函数。由于堆栈不知道用户存放的是什么数据,所以,比较函数必须由用户自己实现。
OPENSSL_sk_compfunc OPENSSL_sk_set_cmp_func(OPENSSL_STACK *sk, OPENSSL_sk_compfunc c)
{OPENSSL_sk_compfunc old = sk->comp;if (sk->comp != c)sk->sorted = 0;sk->comp = c;return old;
}
  • OPENSSL_sk_dup 堆栈拷贝
  • 使用OPSNSSL_malloc进行内存的分配,其实质是调用CRYPTO_malloc进行内存的分配
OPENSSL_STACK *OPENSSL_sk_dup(const OPENSSL_STACK *sk)
{OPENSSL_STACK *ret;if ((ret = OPENSSL_malloc(sizeof(*ret))) == NULL)goto err;if (sk == NULL) {ret->num = 0;ret->sorted = 0;ret->comp = NULL;} else {/* direct structure assignment */*ret = *sk;}if (sk == NULL || sk->num == 0) {/* postpone |ret->data| allocation */ret->data = NULL;ret->num_alloc = 0;return ret;}/* duplicate |sk->data| content */if ((ret->data = OPENSSL_malloc(sizeof(*ret->data) * sk->num_alloc)) == NULL)goto err;memcpy(ret->data, sk->data, sizeof(void *) * sk->num);return ret;err:ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);OPENSSL_sk_free(ret);return NULL;
}
  • C++版本 
OPENSSL_STACK *OPENSSL_sk_dup(const OPENSSL_STACK *sk){OPENSSL_STACK *ret;if((ret = reinterpret_cast<OPENSSL_STACK *>(OPENSSL_malloc(sizeof (*ret)))) == nullptr){goto err;}if (sk == nullptr){ret->num = 0;ret->sorted = 0;ret->comp = nullptr;} else{//直接结构赋值*ret = *sk;}if (sk == nullptr || sk->num == 0){//推迟|ret->data|分配ret->data = nullptr;ret->num_alloc = 0;return ret;}// 重复|sk->data|内容if ((ret->data = static_cast<const void **>(OPENSSL_malloc(sizeof((*ret).data) * sk->num_alloc))) == nullptr)goto err;memcpy(ret->data,sk->data,sizeof (void*)*sk->num);return ret;err:ERR_raise(ERR_LIB_CRYPTO,ERR_R_MALLOC_FAILURE);OPENSSL_sk_free(ret);return nullptr;
}
# define OPENSSL_malloc(num) \CRYPTO_malloc(num, OPENSSL_FILE, OPENSSL_LINE)
  • *根据配置制作我们自己的__FILE__和__LINE__变体
/** Make our own variants of __FILE__ and __LINE__, depending on configuration*/# ifndef OPENSSL_FILE
#  ifdef OPENSSL_NO_FILENAMES
#   define OPENSSL_FILE ""
#   define OPENSSL_LINE 0
#  else
#   define OPENSSL_FILE __FILE__
#   define OPENSSL_LINE __LINE__
#  endif
# endif
  •  CRYPTO_malloc
  • # define INCREMENT(x) /* empty */
void *CRYPTO_malloc(size_t num, const char *file, int line)
{INCREMENT(malloc_count);if (malloc_impl != CRYPTO_malloc)return malloc_impl(num, file, line);if (num == 0)return NULL;FAILTEST();if (allow_customize) {/** Disallow customization after the first allocation. We only set this* if necessary to avoid a store to the same cache line on every* allocation.*/allow_customize = 0;}return malloc(num);
}
  • malloc_count 全局静态变量,在openssl里面出现了三次
  • 定义位于 mem.c 文件中 

  •  只要设置了“allow_customize”,就可以更改以下指针
/** the following pointers may be changed as long as 'allow_customize' is set*/static CRYPTO_malloc_fn malloc_impl = CRYPTO_malloc;
  •  INCREMENT  和  FAILTEST
# define FAILTEST() if (shouldfail()) return NULL#else# define INCREMENT(x) /* empty */
# define FAILTEST() /* empty */
#endif
  • *allow_customize  禁止在第一次分配后进行自定义。我们仅在必要时设置此值,以避免在每次分配时将存储存储到相同的缓存行。 

 

OPENSSL_sk_deep_copy  深拷贝

OPENSSL_STACK *OPENSSL_sk_deep_copy(const OPENSSL_STACK *sk,OPENSSL_sk_copyfunc copy_func,OPENSSL_sk_freefunc free_func)
{OPENSSL_STACK *ret;int i;if ((ret = OPENSSL_malloc(sizeof(*ret))) == NULL)goto err;if (sk == NULL) {ret->num = 0;ret->sorted = 0;ret->comp = NULL;} else {/* direct structure assignment */*ret = *sk;}if (sk == NULL || sk->num == 0) {/* postpone |ret| data allocation */ret->data = NULL;ret->num_alloc = 0;return ret;}ret->num_alloc = sk->num > min_nodes ? sk->num : min_nodes;ret->data = OPENSSL_zalloc(sizeof(*ret->data) * ret->num_alloc);if (ret->data == NULL)goto err;for (i = 0; i < ret->num; ++i) {if (sk->data[i] == NULL)continue;if ((ret->data[i] = copy_func(sk->data[i])) == NULL) {while (--i >= 0)if (ret->data[i] != NULL)free_func((void *)ret->data[i]);goto err;}}return ret;err:ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);OPENSSL_sk_free(ret);return NULL;
}
OPENSSL_STACK *OPENSSL_sk_deep_copy(const OPENSSL_STACK *sk,OPENSSL_sk_copyfunc copy_func,OPENSSL_sk_freefunc free_func)
{OPENSSL_STACK *ret;int j;if ((ret = reinterpret_cast<OPENSSL_STACK *>(OPENSSL_malloc(sizeof (*ret))))== nullptr)goto err;if (sk == nullptr){ret->num = 0;ret->sorted = 0;ret->comp = nullptr;} else{//直接结构赋值*ret = *sk;}if (sk == nullptr || sk->num == 0){//推迟|ret->data|分配ret->data = nullptr;ret->num_alloc = 0;return ret;}ret->num_alloc = sk->num > min_nodes ? sk->num : min_nodes;ret->data = static_cast<const void **>(OPENSSL_zalloc(sizeof(*ret->data) * ret->num_alloc));if (ret->data == nullptr)goto err;for (j = 0; j < ret->num; ++j) {if (sk->data[j] == nullptr)continue;if ((ret->data[j] = copy_func(sk->data[j]))== nullptr){while (--j >= 0)if (ret->data[j]!= nullptr)free_func((void *)ret->data[j]);goto err;}}return ret;err:ERR_raise(ERR_LIB_CRYPTO,ERR_R_MALLOC_FAILURE);OPENSSL_sk_free(ret);return nullptr;
}
# define OPENSSL_zalloc(num) \CRYPTO_zalloc(num, OPENSSL_FILE, OPENSSL_LINE)
  •  CRYPTO_zalloc 内存分配,内部调用 CRYPTO_malloc
void *CRYPTO_zalloc(size_t num, const char *file, int line)
{void *ret;ret = CRYPTO_malloc(num, file, line);FAILTEST();if (ret != NULL)memset(ret, 0, num);return ret;
}
typedef void *(*OPENSSL_sk_copyfunc)(const void *);
typedef void (*OPENSSL_sk_freefunc)(void *);
/* Main error raising functions */
# define ERR_raise(lib, reason) ERR_raise_data((lib),(reason),NULL)
# define ERR_raise_data                                         \(ERR_new(),                                                 \ERR_set_debug(OPENSSL_FILE,OPENSSL_LINE,OPENSSL_FUNC),     \ERR_set_error)
void ERR_new(void)
{c_new_error(NULL);
}void ERR_set_debug(const char *file, int line, const char *func)
{c_set_error_debug(NULL, file, line, func);
}void ERR_set_error(int lib, int reason, const char *fmt, ...)
{va_list args;va_start(args, fmt);c_vset_error(NULL, ERR_PACK(lib, 0, reason), fmt, args);va_end(args);
}
void OPENSSL_sk_free(OPENSSL_STACK *st)
{if (st == NULL)return;OPENSSL_free(st->data);OPENSSL_free(st);
}

 OPENSSL_sk_new_reserve

OPENSSL_STACK *OPENSSL_sk_new_null(void)
{return OPENSSL_sk_new_reserve(NULL, 0);
}

  OPENSSL_sk_new

OPENSSL_STACK *OPENSSL_sk_new(OPENSSL_sk_compfunc c)
{return OPENSSL_sk_new_reserve(c, 0);
}

 OPENSSL_sk_new_reserve

OPENSSL_STACK *OPENSSL_sk_new_reserve(OPENSSL_sk_compfunc c, int n)
{OPENSSL_STACK *st = reinterpret_cast<OPENSSL_STACK *>(OPENSSL_zalloc(sizeof(OPENSSL_STACK)));if (st == NULL)return NULL;st->comp = c;if (n <= 0)return st;if (!sk_reserve(st, n, 1)) {OPENSSL_sk_free(st);return NULL;}return st;
}

 sk_reserve

/* internal STACK storage allocation */
static int sk_reserve(OPENSSL_STACK *st, int n, int exact)
{const void **tmpdata;int num_alloc;//检查预订是否超过硬限制if (n > max_nodes - st->num){return 0;}//指出新的大小num_alloc = st->num + n;if (num_alloc < min_nodes){num_alloc = min_nodes;}//如果 |st->data| 分配被推迟if (st->data == nullptr){//此时,|st->num_alloc| 和 |st->num| 是 0//所以 |num_alloc| 值为 |n| 或 |min_nodes| 如果大于 |n|if((st->data = static_cast<const void **>(OPENSSL_zalloc(sizeof (void *)*num_alloc)))== nullptr){ERR_raise(ERR_LIB_CRYPTO,ERR_R_MALLOC_FAILURE);return 0;}st->num_alloc = num_alloc;return 1;}if (!exact){if (num_alloc <= st->num_alloc)return 1;num_alloc = compute_growth(num_alloc,st->num_alloc);if (num_alloc == 0)return 0;} else if (num_alloc == st->num_alloc){return 1;}tmpdata = static_cast<const void **>(OPENSSL_realloc((void *)st->data, sizeof(void *) * num_alloc));if (tmpdata == NULL)return 0;st->data = tmpdata;st->num_alloc = num_alloc;return 1;
}

compute_growth 

/** 根据目标大小计算数组增长。** 增长分数是有理数,由分子和分母定义。 根据 Andrew Koenig 在他的论文“为什么向量是有效的?”中的说法。 从 JOOP 11(5) 1998 开始,这个因子应该小于黄金比例 (1.618...)。** 我们使用 3/2 = 1.5 来简化计算和溢出检查。另一个选项 8/5 = 1.6 允许稍微更快的增长,尽管安全计算更加困难。** 避免溢出的限制是正确的。 模三校正项确保限制是在不超过硬限制的情况下可以通过增长因子扩展的最大数。** 不要用 |current| 调用它 小于2,否则会无限循环。*/
static ossl_inline int compute_growth(int target,int current){const int limit = (max_nodes / 3)*2 + (max_nodes % 3 ? 1: 0);while(current < target){//检查我们是否处于硬限制if (current >= max_nodes)return 0;//如果在范围内,则将大小扩大 3/2 倍current = current < limit ? current + current / 2 : max_nodes;}return current;
}

OPENSSL_sk_reserve

int OPENSSL_sk_reserve(OPENSSL_STACK *st, int n)
{if (st == NULL)return 0;if (n < 0)return 1;return sk_reserve(st, n, 1);
}

OPENSSL_sk_insert 

  • C 库函数 – memmove() | 菜鸟教程
int OPENSSL_sk_insert(OPENSSL_STACK *st,const void *data,int loc)
{if (st == nullptr || st->num == max_nodes){return 0;}if (!sk_reserve(st,1,0))return 0;if ((loc >= st->num) || (loc < 0)){st->data[st->num] = data;} else{memmove(&st->data[loc+1],&st->data[loc],sizeof(st->data[0]) * (st->num - loc));st->data[loc] = data;}st->num++;st->sorted = 0;return st->num;
}

internal_delete 

static ossl_inline void * internal_delete(OPENSSL_STACK *st,int loc){const void *ret = st->data[loc];if (loc != st->num-1){memmove(&st->data[loc],&st->data[loc+1],sizeof (st->data[0]) * (st->num - loc -1));}st->num--;return (void*)ret;
}

 OPENSSL_sk_delete_ptr

void* OPENSSL_sk_delete_ptr(OPENSSL_STACK *st,const void *p){for (int j = 0; j < st->num; ++j) {if (st->data[j]==p)return internal_delete(st,j);}return nullptr;
}

OPENSSL_sk_delete 

void *OPENSSL_sk_delete(OPENSSL_STACK *st,int loc)
{if (st == nullptr || loc < 0 || loc >= st->num){return nullptr;}return internal_delete(st,loc);
}

 internal_find

  • 根据数据地址来查找它在堆栈中的位置。当堆栈设置了比较函数时,它首先对堆栈进行排序,然后通过二分法进行查找。
  • 如果堆栈没有设置比较函数,它只是简单的比较数据地址来查找
static int internal_find(OPENSSL_STACK *st,const void *data,int ret_val_options,int *pnum)
{const void *r = nullptr;if (st == nullptr || st->num == 0){return -1;}//未排序 采用循环遍历的方式进行查找if (st->comp == nullptr){for (int i = 0; i < st->num; ++i) {if (st->data[i] == data){if (pnum != nullptr)*pnum = 1;return i;}if (pnum != nullptr){*pnum = 0;}return -1;}}//根据comp比较函数进行快速排序if (!st->sorted){if (st->num > 1)qsort(st->data,st->num,sizeof (void*),st->comp);st->sorted = 1; //空或单元素堆栈被视为已排序}if (data == nullptr)return -1;if (pnum != nullptr)ret_val_options |= OSSL_BSEARCH_FIRST_VALUE_ON_MATCH;r = ossl_bsearch(&data,st->data,st->num,sizeof(void*),st->comp,ret_val_options);if (pnum != nullptr){*pnum = 0;if (r != nullptr){const void **p = (const void **)r;while (p < st->data + st->num){if (st->comp(&data,p) != 0)break;++*pnum;++p;}}}return r == nullptr ? -1 : (int)((const void **)r - st->data);
}

 ossl_bsearch

  • C 库函数 – bsearch() | 菜鸟教程
#include <stddef.h>
#include "internal/cryptlib.h"const void *ossl_bsearch(const void *key, const void *base, int num,int size, int (*cmp) (const void *, const void *),int flags)
{const char *base_ = base;int l, h, i = 0, c = 0;const char *p = NULL;if (num == 0)return NULL;l = 0;h = num;while (l < h) {i = (l + h) / 2;p = &(base_[i * size]);c = (*cmp) (key, p);if (c < 0)h = i;else if (c > 0)l = i + 1;elsebreak;}if (c != 0 && !(flags & OSSL_BSEARCH_VALUE_ON_NOMATCH))p = NULL;else if (c == 0 && (flags & OSSL_BSEARCH_FIRST_VALUE_ON_MATCH)) {while (i > 0 && (*cmp) (key, &(base_[(i - 1) * size])) == 0)i--;p = &(base_[i * size]);}return p;
}
/* Function for simple binary search *//* Flags */
# define OSSL_BSEARCH_VALUE_ON_NOMATCH            0x01
# define OSSL_BSEARCH_FIRST_VALUE_ON_MATCH        0x02

 OPENSSL_sk_find

int OPENSSL_sk_find(OPENSSL_STACK *st, const void *data)
{return internal_find(st, data, OSSL_BSEARCH_FIRST_VALUE_ON_MATCH, NULL);
}

OPENSSL_sk_find_ex

int OPENSSL_sk_find_ex(OPENSSL_STACK *st, const void *data)
{return internal_find(st, data, OSSL_BSEARCH_VALUE_ON_NOMATCH, NULL);
}

OPENSSL_sk_find_all 

int OPENSSL_sk_find_all(OPENSSL_STACK *st, const void *data, int *pnum)
{return internal_find(st, data, OSSL_BSEARCH_FIRST_VALUE_ON_MATCH, pnum);
}

OPENSSL_sk_push 

int OPENSSL_sk_push(OPENSSL_STACK *st, const void *data)
{if (st == NULL)return -1;return OPENSSL_sk_insert(st, data, st->num);
}

OPENSSL_sk_unshift 

int OPENSSL_sk_unshift(OPENSSL_STACK *st, const void *data)
{return OPENSSL_sk_insert(st, data, 0);
}

OPENSSL_sk_shift 

void *OPENSSL_sk_shift(OPENSSL_STACK *st)
{if (st == NULL || st->num == 0)return NULL;return internal_delete(st, 0);
}

OPENSSL_sk_pop 

void *OPENSSL_sk_pop(OPENSSL_STACK *st)
{if (st == NULL || st->num == 0)return NULL;return internal_delete(st, st->num - 1);
}

OPENSSL_sk_zero 

void OPENSSL_sk_zero(OPENSSL_STACK *st)
{if (st == NULL || st->num == 0)return;memset(st->data, 0, sizeof(*st->data) * st->num);st->num = 0;
}

 OPENSSL_sk_pop_free

  • 释放data和结构体 
void OPENSSL_sk_pop_free(OPENSSL_STACK *st, OPENSSL_sk_freefunc func)
{int i;if (st == NULL)return;for (i = 0; i < st->num; i++)if (st->data[i] != NULL)func((char *)st->data[i]);OPENSSL_sk_free(st);
}

OPENSSL_sk_free 

void OPENSSL_sk_free(OPENSSL_STACK *st)
{if (st == NULL)return;OPENSSL_free(st->data);OPENSSL_free(st);
}

OPENSSL_sk_num 

int OPENSSL_sk_num(const OPENSSL_STACK *st)
{return st == NULL ? -1 : st->num;
}

OPENSSL_sk_value 

void *OPENSSL_sk_value(const OPENSSL_STACK *st, int i)
{if (st == NULL || i < 0 || i >= st->num)return NULL;return (void *)st->data[i];
}

OPENSSL_sk_set 

void *OPENSSL_sk_set(OPENSSL_STACK *st, int i, const void *data)
{if (st == NULL || i < 0 || i >= st->num)return NULL;st->data[i] = data;st->sorted = 0;return (void *)st->data[i];
}

OPENSSL_sk_sort 

  • 本函数对堆栈数据排序。它首先根据sorted来判断是否已经排序,如果未排序 则调用了标准C 函数qsort 进行快速排序。
void OPENSSL_sk_sort(OPENSSL_STACK *st)
{if (st != NULL && !st->sorted && st->comp != NULL) {if (st->num > 1)qsort(st->data, st->num, sizeof(void *), st->comp);st->sorted = 1; /* empty or single-element stack is considered sorted */}
}

OPENSSL_sk_is_sorted 

int OPENSSL_sk_is_sorted(const OPENSSL_STACK *st)
{return st == NULL ? 1 : st->sorted;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/445879.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

小米用户画像_企鹅智库:高学历用苹果中老年用华为 男性用小米女性用OV

不同手机品牌都有着自己不同的定位人群&#xff0c;在国内市场目前几大非常有名的手机品牌分别被三星、苹果、华为、小米、OV占据&#xff0c;而这些手机品牌的主要购买人群到底是什么样的呢&#xff1f;企鹅智库近日发布了一份手机消费者的调研报告&#xff0c;并且根据消费者…

国密gmtls协议-双证书体系的服务端和客户端通信代码

内容介绍 国密的双证书体系&#xff0c;将证书按照使用目的的不同划分为加密证书和签名证书两种&#xff0c;也就是两对公私钥&#xff0c;二者本质一致&#xff0c;均为SM2密钥对&#xff0c;区别仅体现在用法国密CA体系中&#xff0c;加密密钥对由CA产生&#xff0c;签名密钥…

jwt 私钥_什么是 JSON Web Token(JWT)

有关本文档的快速链接&#xff0c;请参考页面提示。什么是 JSON Web Token(JWT)?JSON Web Token (JWT) 作为一个开放的标准 (RFC 7519) 定义了一种简洁自包含的方法用于通信双方之间以 JSON 对象的形式安全的传递信息。因为有数字签名&#xff0c;所以这些通信的信息能够被校验…

天线下倾角示意图_常用天线和无源器件技术参数汇总

原标题&#xff1a;常用天线和无源器件技术参数汇总一、天线原理天线的定义&#xff1a; 能够有效地向空间某特定方向辐射电磁波或能够有效的接收空间某特定方向来的电磁波的装置。天线的功能&#xff1a; 能量转换-导行波和自由空间波的转换; 定向辐射(接收)-具有一定的方向性…

制作作品图片_不懂人文后期制作流程?来,大师手把手教你

制作前1、处理一张照片思路决定步骤 想要了解学习的老师可以私聊小编fzhdyx222制作后2、2020年最新Camera Raw局部影调和色调的控制想要了解学习的老师可以私聊小编fzhdyx222制作前3、2020年最新Camera Raw基础工具细节性运用想要了解学习的老师可以私聊小编fzhdyx222制作后4、…

xlsx文件打开乱码_Excel 2016 双击无法打开xlsx文件怎么办?

最近我重装了系统(Win10Office2016)&#xff0c;然后发现了一个奇怪的bug&#xff1a;双击xlsx文件&#xff0c;只能打开Excel窗口&#xff0c;但是打不开这个文件&#xff0c;有时候再次双击就能打开了&#xff0c;但有时再次双击也不管用&#xff0c;需要在Excel的菜单中点“…

gmssl使用双证书双向认证的gmtl协议报错crypto/sm2/sm2_sign.c 510: sm2_do_verifySSL3 alert write:fatal:decrypt error

报错内容 crypto/sm2/sm2_sign.c 510: sm2_do_verify SSL3 alert write:fatal:decrypt error SSL_accept:error in error ERROR 140655864152064:error:1417B07B:SSL routines:tls_process_cert_verify:bad signature:ssl/statem/statem_srvr.c:2941: 相关内容 版本&#xf…

纠偏的意思_承压能力和纠偏能力,决定成长的高度

承压能力&#xff0c;包含抗压能力、抵御能力&#xff0c;担当能力&#xff0c;分解能力&#xff0c;消化能力&#xff0c;释放能力&#xff0c;等一系列的精神要素&#xff0c;是一个人生存生活工作中一项重要的素质。有的人&#xff0c;承压能力很强&#xff0c;无论经受什么…

函数指针作为形参进行调用

代码 两个代码均位于namespace作用域之内addOne将传递进来的形参进行加一&#xff0c;然后返回performance_test函数主要是想简化函数调用&#xff0c;两个形参&#xff0c;第一个表示循环的次数&#xff0c;第二个是带参数的函数指针&#xff0c;函数内部初始化start和end两个…

解决吉大正源(身份认证网关|USBKey)和gmssl(server|client)使用gmtl协议交叉互通报错tlsv1 alert decrypt error

报错内容 SSL_connect:error in SSLv3/TLS write finished140057291788288:error:1409441B:SSL routines:ssl3_read_bytes:tlsv1 alert decrypt error:ssl/record/rec_layer_s3.c:1385:SSL alert number 51 报错原因 gmssl库生成 certificate verify 消息时&#xff0c;对自客…

12无法使用otg_12个冷知识:或许只能看看而无法使用,但却真实存在着

12个或许只能看看而无法使用&#xff0c;但却真实存在着。脸红一所有已知动物中&#xff0c;唯一可以脸红的是人类。二有些地区将雨水归类为公共财物&#xff0c;作为公共财物是不允许收集的&#xff0c;违反者将面临处罚。三世界上汽车研发成本最高的一款车是福特蒙迪欧&#…

三目运算符_C语言知识点:运算符的优先级和结合性

运算符是一种告诉编译器执行特定的数学或逻辑操作的符号。C语言内置了丰富的运算符&#xff0c;大体可分为10类&#xff1a;算术运算符、关系运算符、逻辑运算符、位操作运算符、赋值运算符、条件运算符、逗号运算符、指针运算符、求字节数运算符和特殊运算符。根据运算符可操作…

可以直接进行运算么_WORD办公技巧:如何直接在WORD中进行加法、乘法运算?

排版目标下图文档中有一张2020年&#xff11;&#xff0d;&#xff13;月口罩购买情况统计表&#xff0c;数据量并不大&#xff0c;我们想不动用excel表格进行统计&#xff0c;直接利用WORD自带的函数公式计算出表格内空白单元格的数值。其中&#xff0c;金额&#xff1d;单价&…

《剑指Offer》36:二叉搜索树与双向链表

题目 输入一棵二叉搜索树&#xff0c;将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的节点&#xff0c;只能调整树中节点指针的指向。比如&#xff0c;输入下图中的二叉搜索树&#xff0c;输出转换之后的排序双向链表。 二叉树节点的定义如下&#xff1a; pub…

窗口位置按钮取消_VBA002:“宏”的保存位置有哪几种方式?

商务合作请加微信 | Allen_Lyq文章投稿 | jiangjunpeng1996126.com微信公众号 | Word和Excel达人先生头条号 | 跟小小筱学办公技能通过上一篇文章的学习&#xff0c;我们已经知道宏的基本用法&#xff0c;在录制宏的过程中&#xff0c;还有几个点需要我们注意下&#xff1a;宏命…

《剑指Offer》38:字符串的排列

题目 输入一个字符串&#xff0c;打印该字符中字符的所有排列。 例如&#xff0c;输入字符串abc&#xff0c;则打印出由字符a、b、c所能排列出来的所有字符串有abc、acb、bac、bca、cab、cba 分析 把一个字符串看成由两部分组成&#xff1a;第一部分是它的第一个字符&#…

《剑指Offer》23:链表中环的入口节点

题目 若一个链表中包含环&#xff0c;如何找出的入口结点&#xff1f;如下图链表中&#xff0c;环的入口节点的节点3。 分析 一快&#xff08;移两节点&#xff09;一慢&#xff08;移一节点&#xff09;两指针判断链表是否存在环。算出环有几个节点&#xff08;上一步的两指…

mysql win 64_win10下装mysql-5.7.18-winx64

步骤1官网下载地址&#xff1a;https://dev.mysql.com/downloads/mysql/选择手动安装版&#xff1a;解压到D盘mysql文件夹下&#xff1a;比以往的版本里缺少了两个.ini文件&#xff0c;直接copy过来&#xff0c;进行修改,my.ini&#xff1a;[client]port3306default-character-…

《剑指Offer》62:圆圈中最后剩下的数字(约瑟夫环)

题目 0,1,2…,n-1这n个数字排成一个圆圈&#xff0c;从数字0开始&#xff0c;每次从这圆圈你删除第m个数字。求出这个圆圈里剩下的最后一个数字。 例如&#xff0c;0、1、2、3、4这5个数字组成一个圆圈&#xff0c;从数字0开始每次删除第3个数字&#xff0c;则删除的前4个数字…

我们边吃曲奇边聊——Cookie与Session那些事

Cookie与Session分别是什么&#xff1f; HTTP Cookie&#xff08;也叫 Web Cookie 或浏览器 Cookie&#xff09;是服务器发送到用户浏览器并保存在本地的一小块数据&#xff0c;它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。 通常&#xff0c;它用于告知…