使用直接调用和间接调用进行Openssl线程安全回调函数注册 [英] Openssl thread-safety-callback-function registration with both direct call and indirect call

查看:211
本文介绍了使用直接调用和间接调用进行Openssl线程安全回调函数注册的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在Linux中编写一个C库(例如libA),该库利用Openssl进行base64编解码器,哈希等.其他一些项目(例如projB)利用libA来完成某些工作,这些项​​目本身称为Openssl API也.因此,projB通过两种方式调用Openssl API:

I’m writing a C library (let’s say, libA) in Linux which leverages Openssl to do base64 codec, hash, etc. Some other projects (e.g. projB) leverage libA to do something, and these projects themselves call Openssl APIs too. So, projB calls Openssl APIs in two ways:

  1. 直接调用Openssl API:projB-> Openssl
  2. 间接调用Openssl API:projB-> libA-> Openssl

与此同时,正式宣布,除非Openssl并非线程安全的,否则至少两个回调函数已注册到Openssl中:

Meanwhile, it’s officially announced that Openssl isn’t thread-safe unless at least two callback functions are registered into Openssl:

  • void ssl_locking_function(int模式,int n,const char *文件,int行)
  • 无符号长ssl_threadid_function()
  • void ssl_locking_function(int mode, int n, const char * file, int line)
  • unsigned long ssl_threadid_function()

libA向projB公开了以下API:

libA exposes following APIs to projB:

  • int InitA(无效)
  • int ActionStuff()
  • void DestroyA()
  • int InitA(void)
  • int ActionStuff()
  • void DestroyA()

为了确保Openssl的线程安全,有两种解决方案:

In order to ensure thread-safety of Openssl, there’re two solutions:

#1. libA在InitA()中将回调函数注册到Openssl中
#2.在调用libA API之前,projB会在初始化时将回调函数注册到Openssl中,而libA不会进行回调注册

#1. libA registers callback functions into Openssl in InitA()
#2. projB registers callback functions into Openssl on initialization, before calling libA APIs, and libA doesn’t do the callback registration

在解决方案#1中,关于调用Openssl API,libA本身是线程安全的.但是,projB还必须确保其线程安全,并且将采取类似的操作将回调函数注册到Openssl中.

With solution #1, libA itself is thread-safe, regarding calling Openssl APIs. However, projB also has to ensure its thread-safety, and it’ll take a similar action of registering callback functions into Openssl.

假设libA注册了以下回调函数

Assume that libA registers the following callback functions

  • void ssl_locking_function_A(int模式,int n,const char *文件,int行)
  • 无符号长ssl_threadid_function_A()
  • void ssl_locking_function_A(int mode, int n, const char * file, int line)
  • unsigned long ssl_threadid_function_A()

和projB注册这些

  • void ssl_locking_function_B(int模式,int n,const char *文件,int行)
  • 无符号长ssl_threadid_function_B()
  • void ssl_locking_function_B(int mode, int n, const char * file, int line)
  • unsigned long ssl_threadid_function_B()

据我了解,libA的回调函数是在projB之后注册的,最终,projB的回调函数被libA的阴影所遮盖:

As I understand, libA’s callback functions are registered after projB’s, and eventually, projB’s callback functions are shaded by libA’s:

  1. projB初始化
  2. projB将ssl_locking_function_B()和ssl_threadid_function_B()注册到Openssl
  3. projB调用InitA()
  4. libA将ssl_locking_function_A()和ssl_threadid_function_A()注册到Openssl
  5. projB调用ActionStuff()
  6. projB调用DestroyA()
  7. projB未初始化
  1. projB initialization
  2. projB registers ssl_locking_function_B() and ssl_threadid_function_B() into Openssl
  3. projB calls InitA()
  4. libA registers ssl_locking_function_A() and ssl_threadid_function_A() into Openssl
  5. projB calls ActionStuff()
  6. projB calls DestroyA()
  7. projB uninitialization

我的问题是,#1或#2是哪种解决方案更好?有更好的解决方案吗?

My question is, which solution is better, #1 or #2? Is there any better solution?

推荐答案

正式宣布Openssl并非线程安全的,除非至少在Openssl中注册了两个回调函数:

it’s officially announced that Openssl isn’t thread-safe unless at least two callback functions are registered into Openssl:

前叉的安全性和信号安全性甚至更差.例如,参见随机叉安全

Fork safety and signal safety are even worse. See, for example, Random Fork Safety and Libcrypto Fork Safety.

为了确保Openssl的线程安全,有两种解决方案:

In order to ensure thread-safety of Openssl, there’re two solutions:

我相信还有第三种....OpenSSL提供了一个称为OPENSSL_THREADS的定义.如果定义了OPENSSL_THREADS,则说明OpenSSL是通过线程支持构建的.确保包含<openssl/opensslconf.h>以获得准确的结果.

I believe there is a third.... OpenSSL provides a define called OPENSSL_THREADS. If OPENSSL_THREADS is defined, then OpenSSL was built with threading support. Be sure to include <openssl/opensslconf.h> to get accurate results.

LibALibB的初始化期间,如果需要,两个库都应安装锁.我相信您可以检查CRYPTO_THREADID_get_callback,如果它为null,则应该初始化锁.您还应该包括一个状态变量,以便您知道在关机时清理资源.

During LibA or LibB's initialization, either library should install the locks if needed. I believe you can checkCRYPTO_THREADID_get_callback, and if its null, then you should initialize the locks. You should also include a state variable so you know to cleanup the resources on shutdown.

实际上,您确实想知道<openssl source>/crypto/th-lock.clock_cs的状态.那就是保存锁数组的地方.但是它是静态的,所以您无法使用它.

In reality, you really want to know the status of lock_cs in <openssl source>/crypto/th-lock.c. That's where the lock array is held. But its static so you can't get to it.

我的问题是,#1或#2是哪种解决方案更好?有更好的解决方案吗?

My question is, which solution is better, #1 or #2? Is there any better solution?

在实践中,您可能会发现库不执行任何操作,并且使用库将它们留给开发人员(尽管有可能发生竞争).最好的RTFM.

In practice, you'll probably find the libraries don't do anything, and they leave it to the developer using the library (despite the possible races). RTFM at its finest.

最安全的解决方案可能是:(1)如果OpenSSL支持线程,(2)您的库需要线程,并且(3)未安装线程锁,则在初始化期间安装锁.

The safest solution will probably be: (1) if OpenSSL supports threads, (2) your library needs threads and (3) thread locks are not installed, then install the locks during initialization.

这篇关于使用直接调用和间接调用进行Openssl线程安全回调函数注册的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆