2015-04-19 1 views
1
#pragma once 

    #ifndef __CURL_CURL_H 
    #include "curl.h" 
    #endif 

    #ifndef __CURL_EASY_H 
    #include "easy.h" 
    #endif 

    #include <stdint.h> 
    #include <memory> 
    #include <string> 

    namespace CommUnit 
    { 
     enum ERR_PROXY 
     { 
      ERR_CURL_INIT_FAILED = 0xA0, 
      ERR_SET_PROXY_FAILED = 0xA1, 
     }; 


     class MyProxy 
     { 
     public: 
      static MyProxy & GetInstance() //Meyers' Singlton 
      { 
       static MyProxy ProxySigleton; 
       return ProxySigleton; 
      } 
     public: 
      /* 
      * @bref:Get request 
      * @param[in] sUrl:Access URL 
      * @param[in] sProxyIp:Proxy IP 
      * @param[in] uProxyPort:Proxy Port 
      * @param[in] uTimeOut:Time out 
      * @param[in] isSSL:HTTPS true,else false 
      * @param[out] sRetContent:Return the URL content 
      */ 
      uint32_t Get(const std::string &sUrl, 
       const std::string& sProxyIp, 
       uint32_t uProxyPort, 
       uint32_t uTimeOut, 
       bool isSSL, 
       std::string &sRetContent); 

     private: 
      MyProxy();        //Constructor hidden 
      MyProxy(MyProxy const &);    //Copy-Constructor hidden 
      MyProxy & operator= (MyProxy const &); //Assign operator hidden 
      ~MyProxy();        //Destructor hidden 

      inline void _setCurlopt(CURL *pCurl, 
       const std::string &sUrl, 
       std::string &sWriterData, 
       const uint32_t uTimeOut, 
       bool isSSL); 

      //Callback function, write data to writerData 
      static int Writer(char *data, 
       uint32_t size, 
       uint32_t nmemb, 
       std::string *writerData); 


     private: 
      std::string m_sErrMsg; 
      static char s_ErrBuffer[CURL_ERROR_SIZE]; 
      static const uint32_t m_MAXBUF = 2 * 1024 * 1024 - 128; 
     }; 
    } 


////////////////////////////////////////////////////////////////////////// 
#include <iostream> 
#include <string> 
#include "MyProxy.h" 
#include "Log.h" 
#include <curl.h> 

using namespace CommUnit; 

char MyProxy::s_ErrBuffer[CURL_ERROR_SIZE] = { 0 }; 


MyProxy::MyProxy(void) 
{ 
    CURLcode oCURLcode = curl_global_init(CURL_GLOBAL_ALL); 
    if (oCURLcode != CURLE_OK) 
    { 
     Log("ERR: %s curl_init failed!", __func__); 
    } 
} 

MyProxy::~MyProxy(void) 
{ 
    curl_global_cleanup(); 
} 


uint32_t MyProxy::Get(const std::string &sUrl, 
    const std::string& sProxyIp, 
    uint32_t uProxyPort, 
    uint32_t uTimeOut, 
    bool isSSL, 
    std::string &sRetContent) 
{ 
    sRetContent.clear(); 
    CURL *pCurl = curl_easy_init(); 
    CURLcode oCURLcode; 
    if (nullptr == pCurl) 
    { 
     Log("ERR: %s curl_easy_init failed!", __func__); 
     return ERR_CURL_INIT_FAILED; 
    } 
    _setCurlopt(pCurl, sUrl, sRetContent, uTimeOut, isSSL); 
    if (0 == sProxyIp.length()|| 0 == uProxyPort) 
    { 
     Log("ERR: %s SetProxy: ProxyIp [%s], ProxyPort[%u] failed",__func__, sProxyIp.c_str(), uProxyPort); 
     return ERR_SET_PROXY_FAILED; 
    } 
    Log("INFO: %s SetProxy: ProxyIp [%s], ProxyPort[%u] failed", __func__, sProxyIp.c_str(), uProxyPort); 
    curl_easy_setopt(pCurl, CURLOPT_PROXY, sProxyIp.c_str()); 
    curl_easy_setopt(pCurl, CURLOPT_PROXYPORT, uProxyPort); 
    int iTimes = 0; 
    while (true) 
    { 
     oCURLcode = curl_easy_perform(pCurl); 
     if (oCURLcode != CURLE_OK && ++iTimes < 3) 
      usleep(5); 
     else 
      break; 
    } 
    if (oCURLcode != CURLE_OK) 
    { 
     Log("ERR: %s curl_easy_perform failed!", __func__); 
    } 
    curl_easy_cleanup(pCurl); 
    return oCURLcode; 
} 

void MyProxy::_setCurlopt(CURL *pCurl, 
    const std::string &sUrl, 
    std::string &sWriterData, 
    const uint32_t uTimeOut, 
    bool isSSL) 
{ 
    curl_easy_setopt(pCurl, CURLOPT_ERRORBUFFER, s_ErrBuffer); 
    curl_easy_setopt(pCurl, CURLOPT_FOLLOWLOCATION, 1); 
    curl_easy_setopt(pCurl, CURLOPT_URL, sUrl.c_str()); 
    curl_easy_setopt(pCurl, CURLOPT_TIMEOUT, uTimeOut); 
    Log("INFO: %s Set Url:[%s],TimeOut:[%d]", __func__, sUrl.c_str(), uTimeOut); 
    curl_easy_setopt(pCurl, CURLOPT_WRITEFUNCTION, MyProxy::Writer); 
    curl_easy_setopt(pCurl, CURLOPT_WRITEDATA, &sWriterData); 

    //Skip peer and hostname verification 
    if (isSSL) 
    { 
     curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 0L); 
     curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYHOST, 0L); 
    } 
} 


int MyProxy::Writer(char *data, 
    uint32_t size, 
    uint32_t nmemb, 
    std::string *writerData) 
{ 
    if (writerData == nullptr) 
    { 
     Log("ERR: %s writerData is null!", __func__); 
     return 0; 
    } 
    int len = size * nmemb; 
    if ((writerData->size() + len) > m_MAXBUF) 
    { 
     Log("ERR: %s writerData size over MAXBUF!", __func__); 
     return 0; 
    } 
    writerData->append(data, len); 
    return len; 
} 

Я хочу реализовать прокси-сервер с libcurl, который может получить содержимое данного URL-адреса (https). Более того, он должен быть безопасным для потоков. Но когда я создал 200 потоков с pthreads для проверки моего кода, иногда возникала ошибка сегмента. Как я могу решить эту проблему? Есть ли связь с sRetContent (std :: string)? Спасибо!thread-safety proxy с libcurl

ERRMSG: двойной бесплатно или повреждение (пред!): 0x0ac72840 *** вина Сегментация

+0

Начните с изучения использования отладчика. – deviantfan

ответ

0

Libcurl потокобезопасно до тех пор, как вы играете the rules

0

Я понимаю, что Libcurl не потокобезопасным, если вы используете https (и это похоже на вас) из-за того, что он использует базовые библиотеки ssl. See libcurl documentation и OpenSSL documentation для получения дополнительной информации.

Если ваш libcurl был скомпилирован с помощью OpenSSL, то вы должны инициализировать несколько функций обратного вызова или можете столкнуться с проблемами. Это та вещь, что вам нужно сделать (компилирует на Windows):

#include <curl/curl.h> 
#include <openssl/crypto.h> 

void win32_locking_callback(int mode, int type, const char *file, int line) 
{ 
    if (mode & CRYPTO_LOCK) 
    { 
     WaitForSingleObject(lock_cs[type],INFINITE); 
    } 
    else 
    { 
     ReleaseMutex(lock_cs[type]); 
    } 
} 

void thread_setup(void) 
{ 
    int i; 

    lock_cs=(HANDLE*)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(HANDLE)); 
    for (i=0; i<CRYPTO_num_locks(); i++) 
    { 
     lock_cs[i]=CreateMutex(NULL,FALSE,NULL); 
    } 

    CRYPTO_set_locking_callback((void (*)(int,int,const char *,int))win32_locking_callback); 
} 

void thread_cleanup(void) 
{ 
    int i; 

    CRYPTO_set_locking_callback(NULL); 
    for (i=0; i<CRYPTO_num_locks(); i++) 
     CloseHandle(lock_cs[i]); 
    OPENSSL_free(lock_cs); 
} 

Я всегда называю thread_setup() после моего звонка в curl_global_init (CURL_GLOBAL_ALL) , а затем thread_cleanup() прямо перед моим призывом к curl_global_cleanup ().

Я использую этот тип кода с libcurl часто в сценариях тестирования нагрузки и никогда не сталкивался с какими-либо проблемами. Если вы продолжаете сталкиваться с проблемами, это не libcurl, но что-то не выполняется должным образом в вашем коде.