具有直接呼叫和间接呼叫的Openssl线程安全回调函数注册
我正在Linux中编写一个C库(比方说,libA),它利用Openssl来执行base64编解码器,哈希等。其他一些项目(例如projB)利用libA来做某事,而这些项目本身也调用了Openssl API。 因此,projB以两种方式调用Openssl API:
- 直接调用Openssl API:projB – > Openssl
- 间接调用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的阴影所掩盖:
- projB初始化
- projB将ssl_locking_function_B()和ssl_threadid_function_B()注册到Openssl中
- projB调用InitA()
- libA将ssl_locking_function_A()和ssl_threadid_function_A()注册到Openssl
- projB调用ActionStuff()
- …
- projB调用DestroyA()
- projB uninitialization
我的问题是,哪种解决方案更好,#1还是#2? 有没有更好的解决方案?
它正式宣布Openssl不是线程安全的,除非在Openssl中注册了至少两个回调函数:
叉安全和信号安全性更差。 参见,例如, Random Fork Safety和Libcrypto Fork Safety 。
为了确保Openssl的线程安全,有两个解决方案:
我相信还有第三个…. OpenSSL提供了一个名为OPENSSL_THREADS
的定义。 如果定义了OPENSSL_THREADS
,则使用线程支持构建OpenSSL。 请务必包含
以获得准确的结果。
在LibA
或LibB
初始化期间,如果需要,任一库都应安装锁。 我相信你可以检查CRYPTO_THREADID_get_callback
,如果它是null,那么你应该初始化锁。 您还应该包含一个状态变量,以便在关闭时清理资源。
实际上,您真的想知道
。 这就是锁定arrays的位置。 但它的静电让你无法接受它。
我的问题是,哪种解决方案更好,#1还是#2? 有没有更好的解决方案?
在实践中,您可能会发现这些库没有做任何事情,并且使用库将它留给开发人员(尽管有可能的比赛)。 RTFM是最好的。
最安全的解决方案可能是:(1)如果OpenSSL支持线程,(2)你的库需要线程,(3)没有安装线程锁,那么在初始化期间安装锁。