openssl和多线程

这星期在程序里的多线程使用openssl来进行ssl通信,看了一些openssl的文档,前两天领导提醒我注意使用锁,今晚发现openssl提供了非常简单的加锁方式:用户无需显式地进行加锁、解锁,只需提供2个回调函数:

1) void locking_function(int mode, int n, const char *file, int line); 

2) unsigned long id_function(void);

对openssl设置这2个回调函数,在需要加锁、解锁时,openssl自动调用这2个函数。于是,过程大概如下:

  1. 自己实现回调函数1: locking_function
  2. 自己实现回调函数2: id_function
  3. 设置回调函数



上面的3个子过程大概又分别如下:

  1. 实现回调函数1: locking_function

     // 这个数组需要自己申请空间,后续给到openssl使用
     static pthread_mutex_t *ssl_lock = NULL;
    
     void locking_function(int mode, int type, char *file, int line)
     {
         // 根据第1个参数mode来判断是加锁还是解锁
         // 第2个参数是数组下标
         if (mode & CRYPTO_LOCK){
             pthread_mutex_lock(&(ssl_lock[type]));
         }else{
             pthread_mutex_unlock(&(ssl_lock[type]));
         }
     }
    
  2. 实现回调函数2: id_function

     // 返回当前线程id
     unsigned long id_function(void)
     {
         unsigned long ret;
    
         ret=(unsigned long)pthread_self();
         return(ret);
     }
    
  3. 设置回调函数

     int create_ssl_lock(void)
     {
         int i;
    
         // 申请空间,锁的个数是:CRYPTO_num_locks(),
         ssl_lock = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t));
         if (!ssl_lock)
             return -1;
    
         for (i =0 ; i < CRYPTO_num_locks(); i++){
             pthread_mutex_init(&(ssl_lock[i]), NULL);
         }
    
         // 设置回调函数,获取当前线程id
         CRYPTO_set_id_callback((unsigned long (*)())id_function);
    
         // 设置回调函数,加锁和解锁
         CRYPTO_set_locking_callback((void (*)())locking_function);
         return 0;
     }
    
  4. 释放资源

     void ssl_lock_cleanup(void)
     {
         int i;
    
         if (!ssl_lock){
             return;
         }
    
         CRYPTO_set_locking_callback(NULL);
         for (i = 0; i < CRYPTO_num_locks(); i++){
             pthread_mutex_destroy(&(ssl_lock[i]));
         }
         OPENSSL_free(ssl_lock);
         ssl_lock = NULL;
     }
    



另外,在启动其他线程、初始化ssl之前调用create_ssl_lock(),在程序最后清理资源时调用ssl_lock_cleanup()
最后总的流程大概为:

main start:

void init_ssl_env()
{
    SSL_load_error_strings();
    SSL_library_init();
    OpenSSL_add_all_algorithms();


    if (create_ssl_lock()){
        printf("create ssl lock buffer err:%m\n");
    }
}

// 启动其他工作线程
// 线程里初始化ssl、使用ssl(不需显式地进行加锁、解锁)

void clean_ssl_env()
{
    ssl_lock_cleanup();

    ERR_free_strings();
}

main end

这里使用的是openssl的静态锁,固定申请CRYPTO_num_locks()这么多个锁。 当然也可以使用动态锁,对性能还有提高。
但是,openssl的man页面上说,openssl内部当前不使用动态锁,未来也许会使用:

Also, dynamic locks are currently not used internally by OpenSSL, but may do so in the future.

参考自: Multithread Support
ps,推荐上面这本书《Cryptography for Secure Communications》,这里是pdf下载页面



– EOF –

Categories: in_lib
Tags: c,openssl