文档章节

libcurl 多线程使用注意事项(补充)——HTTPS,openssl多线程使用加锁

henry-zhang
 henry-zhang
发布于 2015/08/18 10:21
字数 924
阅读 1994
收藏 4

问题

多线程libcurl运行一段时间后出现崩掉,没有确定的点,没有确定的URL。一直查看源代码没有问题,最后通过debug跟踪发现是在访问SSL的时候出现的crash。

才想起来openssl是不支持多线程的,要自己做加锁处理。而且libcurl中并没有支持相关的加锁操作。


解决办法:

在初始化libcurl的时候为openssl创建一个互斥锁函数,一个回调函数传给openss

openssl锁l函数原形 :void (* func )(int ,int , const char * ,int)

设置方式:CRYPTO_set_locking_callback(void (* func )(int ,int , const char * ,int));

设置这样一个函数还不够,另外还要配置一个锁id回调函数,这个可以参考openssl多线程下的使用相关。

id函数原形:unsigned int (*func)(void)

设置方式:CRYPTO_set_id_callback(unsigned int (*func)(void));

通过这两个设置就可以解决HTTPS多线程请求出现crash的问题。


代码示例:

下面是引用了libcurl示例的一个代码

最关键就是,两个callback的实现,还有初始化锁(init_locks)和释放锁(kill_locks)的位置

#define USE_OPENSSL 
       
    #include <stdio.h> 
    #include <pthread.h> 
    #include <curl/curl.h> 
       
    #define NUMT 4 
       
    /* we have this global to let the callback get easy access to it */ 
    static pthread_mutex_t *lockarray; 
       
    #ifdef USE_OPENSSL 
    #include <openssl/crypto.h> 
    static void lock_callback(int mode, int type, char *file, int line) 
    { 
      (void)file; 
      (void)line; 
      if (mode & CRYPTO_LOCK) { 
        pthread_mutex_lock(&(lockarray[type])); 
      } 
      else { 
        pthread_mutex_unlock(&(lockarray[type])); 
      } 
    } 
       
    static unsigned long thread_id(void) 
    { 
      unsigned long ret; 
       
      ret=(unsigned long)pthread_self(); 
      return(ret); 
    } 
       
    static void init_locks(void) 
    { 
      int i; 
       
      lockarray=(pthread_mutex_t *)OPENSSL_malloc(CRYPTO_num_locks() * 
                                                sizeof(pthread_mutex_t)); 
      for (i=0; i<CRYPTO_num_locks(); i++) { 
        pthread_mutex_init(&(lockarray[i]),NULL); 
      } 
       
      CRYPTO_set_id_callback((unsigned long (*)())thread_id); 
      CRYPTO_set_locking_callback((void (*)())lock_callback); 
    } 
       
    static void kill_locks(void) 
    { 
      int i; 
       
      CRYPTO_set_locking_callback(NULL); 
      for (i=0; i<CRYPTO_num_locks(); i++) 
        pthread_mutex_destroy(&(lockarray[i])); 
       
      OPENSSL_free(lockarray); 
    } 
    #endif 
       
    #ifdef USE_GNUTLS 
    #include <gcrypt.h> 
    #include <errno.h> 
       
    GCRY_THREAD_OPTION_PTHREAD_IMPL; 
       
    void init_locks(void) 
    { 
      gcry_control(GCRYCTL_SET_THREAD_CBS); 
    } 
       
    #define kill_locks() 
    #endif 
       
    /* List of URLs to fetch.*/ 
    const char * const urls[]= { 
      "https://www.example.com/", 
      "https://www2.example.com/", 
      "https://www3.example.com/", 
      "https://www4.example.com/", 
    }; 
       
    static void *pull_one_url(void *url) 
    { 
      CURL *curl; 
       
      curl = curl_easy_init(); 
      curl_easy_setopt(curl, CURLOPT_URL, url); 
      /* this example doesn't verify the server's certificate, which means we 
         might be downloading stuff from an impostor */ 
      curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); 
      curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); 
      curl_easy_perform(curl); /* ignores error */ 
      curl_easy_cleanup(curl); 
       
      return NULL; 
    } 
       
    int main(int argc, char **argv) 
    { 
      pthread_t tid[NUMT]; 
      int i; 
      int error; 
      (void)argc; /* we don't use any arguments in this example */ 
      (void)argv; 
       
      /* Must initialize libcurl before any threads are started */ 
      curl_global_init(CURL_GLOBAL_ALL); 
       
      init_locks(); 
       
      for(i=0; i< NUMT; i++) { 
        error = pthread_create(&tid[i], 
                               NULL, /* default attributes please */ 
                               pull_one_url, 
                               (void *)urls[i]); 
        if(0 != error) 
          fprintf(stderr, "Couldn't run thread number %d, errno %d\n", i, error); 
        else 
          fprintf(stderr, "Thread %d, gets %s\n", i, urls[i]); 
      } 
       
      /* now wait for all threads to terminate */ 
      for(i=0; i< NUMT; i++) { 
        error = pthread_join(tid[i], NULL); 
        fprintf(stderr, "Thread %d terminated\n", i); 
      } 
       
      kill_locks(); 
       
      return 0; 
    }
#define USE_OPENSSL 
       
    #include <stdio.h> 
    #include <pthread.h> 
    #include <curl/curl.h> 
       
    #define NUMT 4 
       
    /* we have this global to let the callback get easy access to it */ 
    static pthread_mutex_t *lockarray; 
       
    #ifdef USE_OPENSSL 
    #include <openssl/crypto.h> 
    static void lock_callback(int mode, int type, char *file, int line) 
    { 
      (void)file; 
      (void)line; 
      if (mode & CRYPTO_LOCK) { 
        pthread_mutex_lock(&(lockarray[type])); 
      } 
      else { 
        pthread_mutex_unlock(&(lockarray[type])); 
      } 
    } 
       
    static unsigned long thread_id(void) 
    { 
      unsigned long ret; 
       
      ret=(unsigned long)pthread_self(); 
      return(ret); 
    } 
       
    static void init_locks(void) 
    { 
      int i; 
       
      lockarray=(pthread_mutex_t *)OPENSSL_malloc(CRYPTO_num_locks() * 
                                                sizeof(pthread_mutex_t)); 
      for (i=0; i<CRYPTO_num_locks(); i++) { 
        pthread_mutex_init(&(lockarray[i]),NULL); 
      } 
       
      CRYPTO_set_id_callback((unsigned long (*)())thread_id); 
      CRYPTO_set_locking_callback((void (*)())lock_callback); 
    } 
       
    static void kill_locks(void) 
    { 
      int i; 
       
      CRYPTO_set_locking_callback(NULL); 
      for (i=0; i<CRYPTO_num_locks(); i++) 
        pthread_mutex_destroy(&(lockarray[i])); 
       
      OPENSSL_free(lockarray); 
    } 
    #endif 
       
    #ifdef USE_GNUTLS 
    #include <gcrypt.h> 
    #include <errno.h> 
       
    GCRY_THREAD_OPTION_PTHREAD_IMPL; 
       
    void init_locks(void) 
    { 
      gcry_control(GCRYCTL_SET_THREAD_CBS); 
    } 
       
    #define kill_locks() 
    #endif 
       
    /* List of URLs to fetch.*/ 
    const char * const urls[]= { 
      "https://www.example.com/", 
      "https://www2.example.com/", 
      "https://www3.example.com/", 
      "https://www4.example.com/", 
    }; 
       
    static void *pull_one_url(void *url) 
    { 
      CURL *curl; 
       
      curl = curl_easy_init(); 
      curl_easy_setopt(curl, CURLOPT_URL, url); 
      /* this example doesn't verify the server's certificate, which means we 
         might be downloading stuff from an impostor */ 
      curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); 
      curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); 
      curl_easy_perform(curl); /* ignores error */ 
      curl_easy_cleanup(curl); 
       
      return NULL; 
    } 
       
    int main(int argc, char **argv) 
    { 
      pthread_t tid[NUMT]; 
      int i; 
      int error; 
      (void)argc; /* we don't use any arguments in this example */ 
      (void)argv; 
       
      /* Must initialize libcurl before any threads are started */ 
      curl_global_init(CURL_GLOBAL_ALL); 
       
      init_locks(); 
       
      for(i=0; i< NUMT; i++) { 
        error = pthread_create(&tid[i], 
                               NULL, /* default attributes please */ 
                               pull_one_url, 
                               (void *)urls[i]); 
        if(0 != error) 
          fprintf(stderr, "Couldn't run thread number %d, errno %d\n", i, error); 
        else 
          fprintf(stderr, "Thread %d, gets %s\n", i, urls[i]); 
      } 
       
      /* now wait for all threads to terminate */ 
      for(i=0; i< NUMT; i++) { 
        error = pthread_join(tid[i], NULL); 
        fprintf(stderr, "Thread %d terminated\n", i); 
      } 
       
      kill_locks(); 
       
      return 0; 
    }


本文转载自:

henry-zhang
粉丝 2
博文 62
码字总数 1431
作品 0
海淀
私信 提问
vs2013 配置支持https的libcurl

需求:在vs2013上配置支持https协议的libcurl。 环境:win7(64位),vs2013 一、安装openssl: 需要先安装nasm和ActivePerl。 nasm需要手动配置环境变量。ActivePerl下载下来一路next安装就好...

xcywt
2018/08/04
0
0
使用 PGP 保护代码完整性(三):生成 PGP 子密钥

在第三篇文章中,我们将解释如何生成用于日常工作的 PGP 子密钥。 在本系列教程中,我们提供了使用 PGP 的实用指南。在此之前,我们介绍了基本工具和概念,并介绍了如何生成并保护您的主 PG...

作者: Konstantin Ryabitsev
2018/05/04
0
0
图解 HTTP 笔记(七)——HTTPS

本章主要讲解 HTTPS 的基本原理,以及如何利用 HTTPS 防范 HTTP 通信过程中存在的伪装、窃听、篡改等问题 一、HTTP 的缺点 HTTP 在通信过程中会面临以下三种安全问题: 通信使用明文(不加密...

Russ_Zhong
07/18
0
0
OpenSSL 1.1 API 的迁移问题

很多人都知道,OpenSSL 1.1.0版本有意介绍了从以前的版本引入了重大的API更改,以前公开可见的大量数据结构已经变得不透明,添加了访问器函数以获取和设置这些现在不透明结构中的一些字段。值...

两味真火
2016/12/31
1K
2
大型网站的HTTPS实践(一)——HTTPS协议和原理

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/g2V13ah/article/details/83189718 前言 百度于2015年上线了全站HTTPS的安全搜索,默认会将HTTP请求跳转成HTT...

AIOps智能运维
2018/10/19
0
0

没有更多内容

加载失败,请刷新页面

加载更多

前端技术之:Prisma Demo服务部署过程记录

安装前提条件: 1、已经安装了docker运行环境 2、以下命令执行记录发生在MackBook环境 3、已经安装了PostgreSQL(我使用的是11版本) 4、Node开发运行环境可以正常工作 首先需要通过Node包管...

popgis
今天
5
0
数组和链表

数组 链表 技巧一:掌握链表,想轻松写出正确的链表代码,需要理解指针获引用的含义: 对指针的理解,记住下面的这句话就可以了: 将某个变量赋值给指针,实际上就是将这个变量的地址赋值给指...

code-ortaerc
今天
4
0
栈-链式(c/c++实现)

上次说“栈是在线性表演变而来的,线性表很自由,想往哪里插数据就往哪里插数据,想删哪数据就删哪数据...。但给线性表一些限制呢,就没那么自由了,把线性表的三边封起来就变成了栈,栈只能...

白客C
今天
43
0
Mybatis Plus service

/** * @author beth * @data 2019-10-20 23:34 */@RunWith(SpringRunner.class)@SpringBootTestpublic class ServiceTest { @Autowired private IUserInfoService iUserInfoS......

一个yuanbeth
今天
5
0
php7-internal 7 zval的操作

## 7.7 zval的操作 扩展中经常会用到各种类型的zval,PHP提供了很多宏用于不同类型zval的操作,尽管我们也可以自己操作zval,但这并不是一个好习惯,因为zval有很多其它用途的标识,如果自己...

冻结not
昨天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部