具有直接呼叫和间接呼叫的Openssl线程安全回调函数注册

我正在Linux中编写一个C库(比方说,libA),它利用Openssl来执行base64编解码器,哈希等。其他一些项目(例如projB)利用libA来做某事,而这些项目本身也调用了Openssl API。 因此,projB以两种方式调用Openssl API:

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

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

  • void ssl_locking_function(int mode,int n,const char * file,int line)
  • unsigned long ssl_threadid_function()

libA向projB公开以下API:

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

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

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

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

假设libA注册以下回调函数

  • 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 mode,int n,const char * file,int line)
  • unsigned long ssl_threadid_function_B()

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

  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 uninitialization

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

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

叉安全和信号安全性更差。 参见,例如, Random Fork Safety和Libcrypto Fork Safety 。


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

我相信还有第三个…. OpenSSL提供了一个名为OPENSSL_THREADS的定义。 如果定义了OPENSSL_THREADS ,则使用线程支持构建OpenSSL。 请务必包含以获得准确的结果。

LibALibB初始化期间,如果需要,任一库都应安装锁。 我相信你可以检查CRYPTO_THREADID_get_callback ,如果它是null,那么你应该初始化锁。 您还应该包含一个状态变量,以便在关闭时清理资源。

实际上,您真的想知道/crypto/th-lock.c 。 这就是锁定arrays的位置。 但它的静电让你无法接受它。


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

在实践中,您可能会发现这些库没有做任何事情,并且使用库将它留给开发人员(尽管有可能的比赛)。 RTFM是最好的。

最安全的解决方案可能是:(1)如果OpenSSL支持线程,(2)你的库需要线程,(3)没有安装线程锁,那么在初始化期间安装锁。