OpenSSL 和多线程

发布于 2024-09-13 18:59:01 字数 976 浏览 4 评论 0原文

我一直在阅读有关如果在多用途中使用 OpenSSL 的要求线程应用程序,您必须使用 OpenSSL 注册线程识别函数(以及互斥体创建函数)。

在 Linux 上,根据 OpenSSL 提供的示例,通常通过注册如下函数来标识线程:

static unsigned long id_function(void){
    return (unsigned long)pthread_self();
}

pthread_self() 返回 pthread_t,这在 Linux 上有效,因为 pthread_t 只是 unsigned long 的 typedef。

在 Windows pthreads、FreeBSD 和其他操作系统上,pthread_t 是一个结构体,具有以下结构:

struct {
    void * p;                   /* Pointer to actual object */
    unsigned int x;             /* Extra information - reuse count etc */ 
}

这不能简单地转换为 unsigned long,当我尝试这样做时,它会抛出编译错误。我尝试采用 void *p 并将其转换为无符号长整型,理论上内存指针应该在线程之间保持一致和唯一,但这只会导致我的程序崩溃很多。

当使用 Windows pthreads 或 FreeBSD 或任何其他类似操作系统时,我可以使用 OpenSSL 注册什么作为线程识别功能?

另外,作为一个附加问题:
有谁知道如果OpenSSL被编译到QT中并与QT一起使用是否也需要这样做,如果是的话如何使用OpenSSL注册QThreads?令人惊讶的是,我似乎无法在QT中找到答案文档。

I've been reading about the requirement that if OpenSSL is used in a multi-threaded application, you have to register a thread identification function (and also a mutex creation function) with OpenSSL.

On Linux, according to the example provided by OpenSSL, a thread is normally identified by registering a function like this:

static unsigned long id_function(void){
    return (unsigned long)pthread_self();
}

pthread_self() returns a pthread_t, and this works on Linux since pthread_t is just a typedef of unsigned long.

On Windows pthreads, FreeBSD, and other operating systems, pthread_t is a struct, with the following structure:

struct {
    void * p;                   /* Pointer to actual object */
    unsigned int x;             /* Extra information - reuse count etc */ 
}

This can't be simply cast to an unsigned long, and when I try to do so, it throws a compile error. I tried taking the void *p and casting that to an unsigned long, on the theory that the memory pointer should be consistent and unique across threads, but this just causes my program to crash a lot.

What can I register with OpenSSL as the thread identification function when using Windows pthreads or FreeBSD or any of the other operating systems like this?

Also, as an additional question:
Does anyone know if this also needs to be done if OpenSSL is compiled into and used with QT, and if so how to register QThreads with OpenSSL? Surprisingly, I can't seem to find the answer in QT's documentation.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

盗梦空间 2024-09-20 18:59:01

我将把这段代码放在这里。它不是万能药,因为它不处理 FreeBSD,但在大多数情况下,当您只需要支持 Windows 和 Debian 时,它会很有帮助。当然,干净的解决方案假设使用最近推出的 CRYPTO_THREADID_* 系列。 (举个例子,它有一个 CRYPTO_THREADID_cmp 回调,可以映射到 pthread_equal

#include <pthread.h>
#include <openssl/err.h>

#if defined(WIN32)
    #define MUTEX_TYPE            HANDLE
    #define MUTEX_SETUP(x)        (x) = CreateMutex(NULL, FALSE, NULL)
    #define MUTEX_CLEANUP(x)      CloseHandle(x)
    #define MUTEX_LOCK(x)         WaitForSingleObject((x), INFINITE)
    #define MUTEX_UNLOCK(x)       ReleaseMutex(x)
    #define THREAD_ID             GetCurrentThreadId()
#else
    #define MUTEX_TYPE            pthread_mutex_t
    #define MUTEX_SETUP(x)        pthread_mutex_init(&(x), NULL)
    #define MUTEX_CLEANUP(x)      pthread_mutex_destroy(&(x))
    #define MUTEX_LOCK(x)         pthread_mutex_lock(&(x))
    #define MUTEX_UNLOCK(x)       pthread_mutex_unlock(&(x))
    #define THREAD_ID             pthread_self()
#endif

/* This array will store all of the mutexes available to OpenSSL. */ 
static MUTEX_TYPE *mutex_buf=NULL;

static void locking_function(int mode, int n, const char * file, int line)
{
    if (mode & CRYPTO_LOCK)
        MUTEX_LOCK(mutex_buf[n]);
    else
        MUTEX_UNLOCK(mutex_buf[n]);
}

static unsigned long id_function(void)
{
    return ((unsigned long)THREAD_ID);
}

int thread_setup(void)
{
    int i;

    mutex_buf = malloc(CRYPTO_num_locks() * sizeof(MUTEX_TYPE));
    if (!mutex_buf)
        return 0;
    for (i = 0;  i < CRYPTO_num_locks(  );  i++)
        MUTEX_SETUP(mutex_buf[i]);
    CRYPTO_set_id_callback(id_function);
    CRYPTO_set_locking_callback(locking_function);
    return 1;
}

int thread_cleanup(void)
{
    int i;
    if (!mutex_buf)
        return 0;
    CRYPTO_set_id_callback(NULL);
    CRYPTO_set_locking_callback(NULL);
    for (i = 0;  i < CRYPTO_num_locks(  );  i++)
        MUTEX_CLEANUP(mutex_buf[i]);
    free(mutex_buf);
    mutex_buf = NULL;
    return 1;
}

I will just put this code here. It is not panacea, as it doesn't deal with FreeBSD, but it is helpful in most cases when all you need is to support Windows and and say Debian. Of course, the clean solution assumes usage of CRYPTO_THREADID_* family introduced recently. (to give an idea, it has a CRYPTO_THREADID_cmp callback, which can be mapped to pthread_equal)

#include <pthread.h>
#include <openssl/err.h>

#if defined(WIN32)
    #define MUTEX_TYPE            HANDLE
    #define MUTEX_SETUP(x)        (x) = CreateMutex(NULL, FALSE, NULL)
    #define MUTEX_CLEANUP(x)      CloseHandle(x)
    #define MUTEX_LOCK(x)         WaitForSingleObject((x), INFINITE)
    #define MUTEX_UNLOCK(x)       ReleaseMutex(x)
    #define THREAD_ID             GetCurrentThreadId()
#else
    #define MUTEX_TYPE            pthread_mutex_t
    #define MUTEX_SETUP(x)        pthread_mutex_init(&(x), NULL)
    #define MUTEX_CLEANUP(x)      pthread_mutex_destroy(&(x))
    #define MUTEX_LOCK(x)         pthread_mutex_lock(&(x))
    #define MUTEX_UNLOCK(x)       pthread_mutex_unlock(&(x))
    #define THREAD_ID             pthread_self()
#endif

/* This array will store all of the mutexes available to OpenSSL. */ 
static MUTEX_TYPE *mutex_buf=NULL;

static void locking_function(int mode, int n, const char * file, int line)
{
    if (mode & CRYPTO_LOCK)
        MUTEX_LOCK(mutex_buf[n]);
    else
        MUTEX_UNLOCK(mutex_buf[n]);
}

static unsigned long id_function(void)
{
    return ((unsigned long)THREAD_ID);
}

int thread_setup(void)
{
    int i;

    mutex_buf = malloc(CRYPTO_num_locks() * sizeof(MUTEX_TYPE));
    if (!mutex_buf)
        return 0;
    for (i = 0;  i < CRYPTO_num_locks(  );  i++)
        MUTEX_SETUP(mutex_buf[i]);
    CRYPTO_set_id_callback(id_function);
    CRYPTO_set_locking_callback(locking_function);
    return 1;
}

int thread_cleanup(void)
{
    int i;
    if (!mutex_buf)
        return 0;
    CRYPTO_set_id_callback(NULL);
    CRYPTO_set_locking_callback(NULL);
    for (i = 0;  i < CRYPTO_num_locks(  );  i++)
        MUTEX_CLEANUP(mutex_buf[i]);
    free(mutex_buf);
    mutex_buf = NULL;
    return 1;
}
゛清羽墨安 2024-09-20 18:59:01

我只能回答Qt部分。使用 QThread::currentThreadId(),甚至 QThread::currentThread() 因为指针值应该是唯一的。

I only can answer the Qt part. Use QThread::currentThreadId(), or even QThread::currentThread() as the pointer value should be unique.

双手揣兜 2024-09-20 18:59:01

从您链接的 OpenSSL 文档中:

需要

threadid_func(CRYPTO_THREADID *id)来将当前正在执行的线程的标识符记录到id中。此回调的实现不应直接填写 id,但如果线程 ID 是数字,则应使用 CRYPTO_THREADID_set_numeric() ;如果线程 ID 是基于指针的,则应使用 CRYPTO_THREADID_set_pointer() 。如果应用程序未使用 CRYPTO_THREADID_set_callback() 注册此类回调,则使用默认实现 - 在 Windows 和 BeOS 上,它使用系统的默认线程识别 API,在所有其他平台上,它使用地址的错误号。当且仅当平台具有线程本地错误号功能时,后者对于线程安全性是令人满意的。

如图所示,只有当您可以提供比 OpenSSL 默认实现更好的 ID 时,提供您自己的 ID 才真正有用。

当您不知道 pthread_t 是指针还是整数时,提供 ID 的唯一安全方法是维护自己存储为线程本地值的每线程 ID。

From the OpenSSL doc you linked:

threadid_func(CRYPTO_THREADID *id) is needed to record the currently-executing thread's identifier into id. The implementation of this callback should not fill in id directly, but should use CRYPTO_THREADID_set_numeric() if thread IDs are numeric, or CRYPTO_THREADID_set_pointer() if they are pointer-based. If the application does not register such a callback using CRYPTO_THREADID_set_callback(), then a default implementation is used - on Windows and BeOS this uses the system's default thread identifying APIs, and on all other platforms it uses the address of errno. The latter is satisfactory for thread-safety if and only if the platform has a thread-local error number facility.

As shown providing your own ID is really only useful if you can provide a better ID than OpenSSL's default implementation.

The only fail-safe way to provide IDs, when you don't know whether pthread_t is a pointer or an integer, is to maintain your own per-thread IDs stored as a thread-local value.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文