openssl 多线程 线程安全 windows linux

公司某服务器的远古程序崩溃了, 分析crash dump发现是因为没解决openssl的线程安全问题,写个小demo记录一下解决方案。

openssl_multithreading_safe_windows_demo: Windows平台下演示如何解决openssl库多线程场景下线程安全问题的64位demo

openssl_lock.h

#ifndef __OPENSSL_LOCK_H__
#define __OPENSSL_LOCK_H__

//
// Windows平台下演示如何解决openssl库多线程场景下线程安全问题的64位demo
// 1.本项目为64位demo项目,32位同理
// 2.openssl存在版本差异,1_0_0前后的加解锁机制不同
// 3.需要根据系统平台差异定义OpensslProc_GetThreadId,如Windows平台下使用GetCurrentThreadId()
// 4.根据实际业务需求定义OpensslProc_LockingHandler,权衡安全性和性能
// 5.OpensslProc_InitLock、OpensslProc_CleanUpLock对应调用
//

#include <iostream>
#include <Windows.h>
//#include <pthread.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#pragma comment(lib, "libssl.lib")
#pragma comment(lib, "libcrypto.lib")

//在开始使用openssl库之前调用
void OpensslProc_InitLock(void);

//当不再使用openssl库以后调用
void OpensslProc_CleanUpLock(void);

//获取当前tid的线程回调
static unsigned long _stdcall OpensslProc_GetThreadId(void);

//给openssl内部线程资源加解锁的回调
static void _stdcall OpensslProc_LockingHandler(int mode, int type, const char* file, int line);

#endif // !__OPENSSL_LOCK_H__

openssl_lock.cpp

#include "openssl_lock.h"

using namespace std;

//Openssl全局加密锁的数量
UINT    g_uOpensslCrptLockCount = CRYPTO_num_locks();
//存储g_uOpensslCrptLockCount个互斥体句柄的数组
//每个互斥体与一个openssl内置内部资源(具体是什么资源还有待看源码研究)对应
PHANDLE g_hLock_csArray = NULL;

//获取当前tid的线程回调
static unsigned long _stdcall OpensslProc_GetThreadId(void){
    return (unsigned long)GetCurrentThreadId();
}

//给openssl内部线程资源加解锁的回调
static void _stdcall OpensslProc_LockingHandler(int mode, int type, const char* file, int line){

    if (type > g_uOpensslCrptLockCount || !g_hLock_csArray[type]){
        return;
    }

    if (mode & CRYPTO_LOCK){
        WaitForSingleObject(g_hLock_csArray[type], INFINITE);
    } else{
        ReleaseMutex(g_hLock_csArray[type]);
    }
}

//在开始使用openssl库之前调用
void OpensslProc_InitLock(void){

    //根据Openssl内部的crypto_lock的数量申请内存
    while (!g_hLock_csArray){
        g_hLock_csArray = (HANDLE*)OPENSSL_malloc(g_uOpensslCrptLockCount * sizeof(HANDLE));
    }

    for (int i = 0; i < CRYPTO_num_locks(); i++){
        while (!g_hLock_csArray[i]){
            g_hLock_csArray[i] = CreateMutex(NULL, FALSE, NULL);
        }
    }

    //register locking callback
    CRYPTO_set_locking_callback((void (*)(int, int, const char*, int))OpensslProc_LockingHandler);

    //regist tid callback
#if OPENSSL_VERSION_NUMBER >= 0x1000000f
    CRYPTO_THREADID_set_callback(OpensslProc_GetThreadId);
#else
    CRYPTO_set_id_callback(OpensslProc_GetThreadId);
#endif
}

//在openssl库使用结束后调用
void OpensslProc_CleanUpLock(void)
{
    //unregister tid callback
#if OPENSSL_VERSION_NUMBER >= 0x1000000f
    CRYPTO_THREADID_set_callback(NULL);
#else
    CRYPTO_set_id_callback(NULL);
#endif

    if (!g_hLock_csArray){
        return;
    }

    for (int i = 0; i < CRYPTO_num_locks(); i++){
        if (g_hLock_csArray[i]){
            CloseHandle(g_hLock_csArray[i]);
            g_hLock_csArray[i] = NULL;
        }
    }

    OPENSSL_free(g_hLock_csArray);
}

另外感谢这篇博客的详细讲解  多线程环境下使用openssl_yasi_xi的博客-优快云博客_openssl 多线程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值