<commit_before>/**
 * @file posix/net.cpp
 * @brief POSIX network access layer (using cURL + c-ares)
 *
 * (c) 2013-2017 by Mega Limited, Auckland, New Zealand
 *
 * This file is part of the MEGA SDK - Client Access Engine.
 *
 * Applications using the MEGA API must present a valid application key
 * and comply with the the rules set forth in the Terms of Service.
 *
 * The MEGA SDK is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * @copyright Simplified (2-clause) BSD License.
 *
 * You should have received a copy of the license along with this
 * program.
 */

#include "mega.h"
#include "mega/posix/meganet.h"
#include "mega/logging.h"

#define IPV6_RETRY_INTERVAL_DS 72000
#define DNS_CACHE_TIMEOUT_DS 18000
#define MAX_SPEED_CONTROL_TIMEOUT_MS 500

namespace mega {

MUTEX_CLASS CurlHttpIO::curlMutex(false);

#if defined(USE_OPENSSL) && !defined(OPENSSL_IS_BORINGSSL)

MUTEX_CLASS **CurlHttpIO::sslMutexes = NULL;
void CurlHttpIO::locking_function(int mode, int lockNumber, const char *, int)
{
    MUTEX_CLASS *mutex = sslMutexes[lockNumber];
    if (mutex == NULL)
    {
        mutex = new MUTEX_CLASS(true);
        sslMutexes[lockNumber] = mutex;
    }

    if (mode & CRYPTO_LOCK)
    {
        mutex->lock();
    }
    else
    {
        mutex->unlock();
    }
}

#if OPENSSL_VERSION_NUMBER >= 0x10000000
void CurlHttpIO::id_function(CRYPTO_THREADID* id)
{
    CRYPTO_THREADID_set_pointer(id, (void *)THREAD_CLASS::currentThreadId());
}
#else
unsigned long CurlHttpIO::id_function()
{
    return THREAD_CLASS::currentThreadId();
}
#endif

#endif

CurlHttpIO::CurlHttpIO()
{
    curl_version_info_data* data = curl_version_info(CURLVERSION_NOW);
    if (data->version)
    {
        LOG_debug << "cURL version: " << data->version;
    }

    if (data->ssl_version)
    {
        LOG_debug << "SSL version: " << data->ssl_version;

        string curlssl = data->ssl_version;
        std::transform(curlssl.begin(), curlssl.end(), curlssl.begin(), ::tolower);
        if (strstr(curlssl.c_str(), "gskit"))
        {
            LOG_fatal << "Unsupported SSL backend (GSKit). Aborting.";
            exit(EXIT_FAILURE);
        }

        if (data->version_num < 0x072c00 // At least cURL 7.44.0
        #ifdef USE_OPENSSL
                && !(strstr(curlssl.c_str(), "openssl") && data->version_num > 0x070b00)
                // or cURL 7.11.0 with OpenSSL
        #endif
            )
        {
            LOG_fatal << "cURL built without public key pinning support. Aborting.";
            exit(EXIT_FAILURE);
        }
    }

    if (data->libz_version)
    {
        LOG_debug << "libz version: " << data->libz_version;
    }

    int i;
    for (i = 0; data->protocols[i]; i++)
    {
        if (strstr(data->protocols[i], "http"))
        {
            break;
        }
    }

    if (!data->protocols[i] || !(data->features & CURL_VERSION_SSL))
    {
        LOG_fatal << "cURL built without HTTP/HTTPS support. Aborting.";
        exit(EXIT_FAILURE);
    }

    curlipv6 = data->features & CURL_VERSION_IPV6;
    LOG_debug << "IPv6 enabled: " << curlipv6;

    dnsok = false;
    reset = false;
    statechange = false;
    maxspeed[GET] = 0;
    maxspeed[PUT] = 0;
    pkpErrors = 0;

    WAIT_CLASS::bumpds();
    lastdnspurge = Waiter::ds + DNS_CACHE_TIMEOUT_DS / 2;

    curlMutex.lock();

#if defined(USE_OPENSSL) && !defined(OPENSSL_IS_BORINGSSL)

    if (!CRYPTO_get_locking_callback()
#if OPENSSL_VERSION_NUMBER >= 0x10000000
        && !CRYPTO_THREADID_get_callback())
#else
        && !CRYPTO_get_id_callback())
#endif
    {
        LOG_debug << "Initializing OpenSSL locking callbacks";
        int numLocks = CRYPTO_num_locks();
        sslMutexes = new MUTEX_CLASS*[numLocks];
        memset(sslMutexes, 0, numLocks * sizeof(MUTEX_CLASS*));
#if OPENSSL_VERSION_NUMBER >= 0x10000000
        CRYPTO_THREADID_set_callback(CurlHttpIO::id_function);
#else
        CRYPTO_set_id_callback(CurlHttpIO::id_function);
#endif
        CRYPTO_set_locking_callback(CurlHttpIO::locking_function);
    }

#endif

    curl_global_init(CURL_GLOBAL_DEFAULT);
    ares_library_init(ARES_LIB_INIT_ALL);
    curlMutex.unlock();

    curlm[API] = curl_multi_init();
    curlm[GET] = curl_multi_init();
    curlm[PUT] = curl_multi_init();
    numconnections[API] = 0;
    numconnections[GET] = 0;
    numconnections[PUT] = 0;
    curlsocketsprocessed = true;
<commit_msg>fix libressl support<commit_after>/**
 * @file posix/net.cpp
 * @brief POSIX network access layer (using cURL + c-ares)
 *
 * (c) 2013-2017 by Mega Limited, Auckland, New Zealand
 *
 * This file is part of the MEGA SDK - Client Access Engine.
 *
 * Applications using the MEGA API must present a valid application key
 * and comply with the the rules set forth in the Terms of Service.
 *
 * The MEGA SDK is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * @copyright Simplified (2-clause) BSD License.
 *
 * You should have received a copy of the license along with this
 * program.
 */

#include "mega.h"
#include "mega/posix/meganet.h"
#include "mega/logging.h"

#define IPV6_RETRY_INTERVAL_DS 72000
#define DNS_CACHE_TIMEOUT_DS 18000
#define MAX_SPEED_CONTROL_TIMEOUT_MS 500

namespace mega {

MUTEX_CLASS CurlHttpIO::curlMutex(false);

#if defined(USE_OPENSSL) && !defined(OPENSSL_IS_BORINGSSL)

MUTEX_CLASS **CurlHttpIO::sslMutexes = NULL;
void CurlHttpIO::locking_function(int mode, int lockNumber, const char *, int)
{
    MUTEX_CLASS *mutex = sslMutexes[lockNumber];
    if (mutex == NULL)
    {
        mutex = new MUTEX_CLASS(true);
        sslMutexes[lockNumber] = mutex;
    }

    if (mode & CRYPTO_LOCK)
    {
        mutex->lock();
    }
    else
    {
        mutex->unlock();
    }
}

#if OPENSSL_VERSION_NUMBER >= 0x10000000 || defined (LIBRESSL_VERSION_NUMBER)
void CurlHttpIO::id_function(CRYPTO_THREADID* id)
{
    CRYPTO_THREADID_set_pointer(id, (void *)THREAD_CLASS::currentThreadId());
}
#else
unsigned long CurlHttpIO::id_function()
{
    return THREAD_CLASS::currentThreadId();
}
#endif

#endif

CurlHttpIO::CurlHttpIO()
{
    curl_version_info_data* data = curl_version_info(CURLVERSION_NOW);
    if (data->version)
    {
        LOG_debug << "cURL version: " << data->version;
    }

    if (data->ssl_version)
    {
        LOG_debug << "SSL version: " << data->ssl_version;

        string curlssl = data->ssl_version;
        std::transform(curlssl.begin(), curlssl.end(), curlssl.begin(), ::tolower);
        if (strstr(curlssl.c_str(), "gskit"))
        {
            LOG_fatal << "Unsupported SSL backend (GSKit). Aborting.";
            exit(EXIT_FAILURE);
        }

        if (data->version_num < 0x072c00 // At least cURL 7.44.0
        #ifdef USE_OPENSSL
                && !(strstr(curlssl.c_str(), "openssl") && data->version_num > 0x070b00)
                // or cURL 7.11.0 with OpenSSL
        #endif
            )
        {
            LOG_fatal << "cURL built without public key pinning support. Aborting.";
            exit(EXIT_FAILURE);
        }
    }

    if (data->libz_version)
    {
        LOG_debug << "libz version: " << data->libz_version;
    }

    int i;
    for (i = 0; data->protocols[i]; i++)
    {
        if (strstr(data->protocols[i], "http"))
        {
            break;
        }
    }

    if (!data->protocols[i] || !(data->features & CURL_VERSION_SSL))
    {
        LOG_fatal << "cURL built without HTTP/HTTPS support. Aborting.";
        exit(EXIT_FAILURE);
    }

    curlipv6 = data->features & CURL_VERSION_IPV6;
    LOG_debug << "IPv6 enabled: " << curlipv6;

    dnsok = false;
    reset = false;
    statechange = false;
    maxspeed[GET] = 0;
    maxspeed[PUT] = 0;
    pkpErrors = 0;

    WAIT_CLASS::bumpds();
    lastdnspurge = Waiter::ds + DNS_CACHE_TIMEOUT_DS / 2;

    curlMutex.lock();

#if defined(USE_OPENSSL) && !defined(OPENSSL_IS_BORINGSSL)

    if (!CRYPTO_get_locking_callback()
#if OPENSSL_VERSION_NUMBER >= 0x10000000  || defined (LIBRESSL_VERSION_NUMBER)
        && !CRYPTO_THREADID_get_callback())
#else
        && !CRYPTO_get_id_callback())
#endif
    {
        LOG_debug << "Initializing OpenSSL locking callbacks";
        int numLocks = CRYPTO_num_locks();
        sslMutexes = new MUTEX_CLASS*[numLocks];
        memset(sslMutexes, 0, numLocks * sizeof(MUTEX_CLASS*));
#if OPENSSL_VERSION_NUMBER >= 0x10000000  || defined (LIBRESSL_VERSION_NUMBER)
        CRYPTO_THREADID_set_callback(CurlHttpIO::id_function);
#else
        CRYPTO_set_id_callback(CurlHttpIO::id_function);
#endif
        CRYPTO_set_locking_callback(CurlHttpIO::locking_function);
    }

#endif

    curl_global_init(CURL_GLOBAL_DEFAULT);
    ares_library_init(ARES_LIB_INIT_ALL);
    curlMutex.unlock();

    curlm[API] = curl_multi_init();
    curlm[GET] = curl_multi_init();
    curlm[PUT] = curl_multi_init();
    numconnections[API] = 0;
    numconnections[GET] = 0;
    numconnections[PUT] = 0;
    curlsocketsprocessed = true;

{'fraction_non_alphanumeric': 0.11868852459016394, 'fraction_numerical': 0.01814207650273224, 'mean_word_length': 3.059893522626442, 'pattern_counts': {'":': 0, '<': 53, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 6, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6135629', 'n_tokens_mistral': 3322, 'n_tokens_neox': 3097, 'n_words': 684}