如果使用curl访问https(注意不是http),则会牵涉到OpenSSL,就需要注意多线程安全问题。 一是OpenSSL需要编译成多线程安全版本,二是需要为OpenSSL注册两个回调函数。如果不这样多线程环境应用时,会遇到coredump问题。
ssl_manager.zip OpenSSL初始化和注册两个回调函数可参考如下代码:
CSSLmanager::CSSLmanager()
: m_ctx(NULL), m_lock_cs(NULL)
{
}
void CSSLmanager::SSLFini()
{
CRYPTO_set_locking_callback(NULL);
for (int i = 0; i < CRYPTO_num_locks(); i++)
{
pthread_mutex_destroy(&m_lock_cs[i]);
}
OPENSSL_free(m_lock_cs);
if (m_ctx != NULL)
{
SSL_CTX_free((SSL_CTX *)m_ctx);
m_ctx = NULL;
}
ERR_free_strings();
EVP_cleanup();
}
bool CSSLmanager::SSLInit(const TChar* cacert, const TChar * privkey)
{
SSL_library_init(); // SSL库初始化
OpenSSL_add_all_algorithms(); // 载入所有 SSL 算法
SSL_load_error_strings(); // 载入所有SSL错误消息
while (true)
{
// 以 SSL V2 和 V3 标准兼容方式产生一个 SSL_CTX ,即 SSL Content Text
SSL_CTX* ctx = SSL_CTX_new(SSLv23_server_method());
if (NULL == ctx)
break;
// 载入用户的数字证书, 此证书用来发送给客户端,证书里包含有公钥
if (SSL_CTX_use_certificate_file(ctx, cacert, SSL_FILETYPE_PEM) != 1)
break;
// 载入用户私钥
if (SSL_CTX_use_PrivateKey_file(ctx, privkey, SSL_FILETYPE_PEM) != 1)
break;
// 检查用户私钥是否正确
if (SSL_CTX_check_private_key(ctx) != 1)
break;
m_ctx = (void *)ctx;
m_lock_cs = (pthread_mutex_t *)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t));
for (int i = 0; i < CRYPTO_num_locks(); ++i)
{
pthread_mutex_init(&(m_lock_cs[i]),NULL);
}
CRYPTO_set_id_callback(IDFunction); // 注册回调
CRYPTO_set_locking_callback(LockingFunction); // 注册回调
return true;
}
SSLFini();
return false;
}
unsigned long CSSLmanager::IDFunction( void )
{
return ((unsigned long)pthread_self());
}
void CSSLmanager::LockingFunction(int mode, int type, const char *file, int line)
{
pthread_mutex_t* lock = CSSLmanager::singleton()->GetLock();
if (mode & CRYPTO_LOCK) {
pthread_mutex_lock(&lock[type]);
} else {
pthread_mutex_unlock(&lock[type]);
}
}