OpenSSL и многопоточность - PullRequest
       4

OpenSSL и многопоточность

5 голосов
/ 05 августа 2010

Я читал о требовании, что если OpenSSL используется в многопоточном приложении, вы должны зарегистрировать функцию идентификации потока (а также функцию создания мьютекса) в OpenSSL.

В Linux, согласно примеру, предоставленному OpenSSL, поток обычно идентифицируется путем регистрации функции, подобной этой:

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

pthread_self () возвращает pthread_t, и это работает в Linux, так как pthread_t - это просто определение типа unsigned long.

В Windows pthreads, FreeBSD и других операционных системах pthread_t является структурой со следующей структурой:

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

Это не может быть просто приведено к unsigned long, и когда я пытаюсь это сделать, выдается ошибка компиляции. Я пытался взять void * p и привести его к unsigned long, полагая, что указатель памяти должен быть непротиворечивым и уникальным в разных потоках, но это просто приводит к серьезному аварийному завершению моей программы.

Что я могу зарегистрировать в OpenSSL в качестве функции идентификации потока при использовании Windows pthreads или FreeBSD или любой другой операционной системы, подобной этой?

Также в качестве дополнительного вопроса:
Кто-нибудь знает, нужно ли это делать, если OpenSSL скомпилирован и используется с QT, и если да, как зарегистрировать QThreads с OpenSSL? Удивительно, но я не могу найти ответ в документации QT .

Ответы [ 3 ]

5 голосов
/ 10 октября 2012

Я просто положу этот код здесь.Это не панацея, так как она не имеет отношения к 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;
}
1 голос
/ 20 января 2012

Из документа OpenSSL вы связались:

threadid_func(CRYPTO_THREADID *id) необходим для записи идентификатора текущего выполняющегося потока в id. Реализация этого обратного вызова не должна заполнять идентификатор напрямую, но должна использовать CRYPTO_THREADID_set_numeric(), если идентификаторы потоков являются числовыми, или CRYPTO_THREADID_set_pointer(), если они основаны на указателе. Если приложение не регистрирует такой обратный вызов, используя CRYPTO_THREADID_set_callback(), то используется реализация по умолчанию - в Windows и BeOS это использует системный поток по умолчанию, идентифицирующий API, а на всех других платформах - адрес errno. Последнее является удовлетворительным для обеспечения безопасности потока, если и только если платформа имеет локальное средство определения номера ошибки потока.

Как показано, предоставление собственного идентификатора действительно полезно, только если вы можете предоставить лучший идентификатор, чем реализация по умолчанию OpenSSL.

Единственный отказоустойчивый способ предоставления идентификаторов, когда вы не знаете, является ли pthread_t указателем или целым числом, состоит в том, чтобы поддерживать ваши собственные идентификаторы для каждого потока, сохраненные как локальное значение потока.

1 голос
/ 05 августа 2010

Я могу ответить только на часть Qt. Используйте QThread :: currentThreadId () или даже QThread :: currentThread () , поскольку значение указателя должно быть уникальным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...