X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fhttpfetch.cpp;h=6a9a5e235a7860b8fe0d20bd48431550d2889808;hb=5a6618cc57097e1e7205ad6b1d967a3ad79d016e;hp=c60e141fc087fbdcd40fc09d1ec2a437db1a88da;hpb=4ea5a96fffb1a0300f73e97d4c85bb5c32e3786d;p=minetest.git diff --git a/src/httpfetch.cpp b/src/httpfetch.cpp index c60e141fc..6a9a5e235 100644 --- a/src/httpfetch.cpp +++ b/src/httpfetch.cpp @@ -17,15 +17,16 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include "socket.h" // for select() -#include "porting.h" // for sleep_ms(), get_sysinfo() #include "httpfetch.h" +#include "porting.h" // for sleep_ms(), get_sysinfo(), secure_rand_fill_buf() #include #include #include #include -#include -#include "jthread/jevent.h" +#include +#include +#include "network/socket.h" // for select() +#include "threading/event.h" #include "config.h" #include "exceptions.h" #include "debug.h" @@ -34,20 +35,17 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "util/thread.h" #include "version.h" #include "settings.h" +#include "noise.h" -JMutex g_httpfetch_mutex; +std::mutex g_httpfetch_mutex; std::map > g_httpfetch_results; +PcgRandom g_callerid_randomness; -HTTPFetchRequest::HTTPFetchRequest() +HTTPFetchRequest::HTTPFetchRequest() : + timeout(g_settings->getS32("curl_timeout")), + connect_timeout(timeout), + useragent(std::string(PROJECT_NAME_C "/") + g_version_hash + " (" + porting::get_sysinfo() + ")") { - url = ""; - caller = HTTPFETCH_DISCARD; - request_id = 0; - timeout = g_settings->getS32("curl_timeout"); - connect_timeout = timeout; - multipart = false; - - useragent = std::string(PROJECT_NAME_C "/") + g_version_hash + " (" + porting::get_sysinfo() + ")"; } @@ -55,7 +53,7 @@ static void httpfetch_deliver_result(const HTTPFetchResult &fetch_result) { unsigned long caller = fetch_result.caller; if (caller != HTTPFETCH_DISCARD) { - JMutexAutoLock lock(g_httpfetch_mutex); + MutexAutoLock lock(g_httpfetch_mutex); g_httpfetch_results[caller].push(fetch_result); } } @@ -64,7 +62,7 @@ static void httpfetch_request_clear(unsigned long caller); unsigned long httpfetch_caller_alloc() { - JMutexAutoLock lock(g_httpfetch_mutex); + MutexAutoLock lock(g_httpfetch_mutex); // Check each caller ID except HTTPFETCH_DISCARD const unsigned long discard = HTTPFETCH_DISCARD; @@ -84,6 +82,34 @@ unsigned long httpfetch_caller_alloc() return discard; } +unsigned long httpfetch_caller_alloc_secure() +{ + MutexAutoLock lock(g_httpfetch_mutex); + + // Generate random caller IDs and make sure they're not + // already used or equal to HTTPFETCH_DISCARD + // Give up after 100 tries to prevent infinite loop + u8 tries = 100; + unsigned long caller; + + do { + caller = (((u64) g_callerid_randomness.next()) << 32) | + g_callerid_randomness.next(); + + if (--tries < 1) { + FATAL_ERROR("httpfetch_caller_alloc_secure: ran out of caller IDs"); + return HTTPFETCH_DISCARD; + } + } while (g_httpfetch_results.find(caller) != g_httpfetch_results.end()); + + verbosestream << "httpfetch_caller_alloc_secure: allocating " + << caller << std::endl; + + // Access element to create it + g_httpfetch_results[caller]; + return caller; +} + void httpfetch_caller_free(unsigned long caller) { verbosestream<<"httpfetch_caller_free: freeing " @@ -91,14 +117,14 @@ void httpfetch_caller_free(unsigned long caller) httpfetch_request_clear(caller); if (caller != HTTPFETCH_DISCARD) { - JMutexAutoLock lock(g_httpfetch_mutex); + MutexAutoLock lock(g_httpfetch_mutex); g_httpfetch_results.erase(caller); } } bool httpfetch_async_get(unsigned long caller, HTTPFetchResult &fetch_result) { - JMutexAutoLock lock(g_httpfetch_mutex); + MutexAutoLock lock(g_httpfetch_mutex); // Check that caller exists std::map >::iterator @@ -144,7 +170,8 @@ class CurlHandlePool std::list handles; public: - CurlHandlePool() {} + CurlHandlePool() = default; + ~CurlHandlePool() { for (std::list::iterator it = handles.begin(); @@ -177,7 +204,7 @@ class CurlHandlePool class HTTPFetchOngoing { public: - HTTPFetchOngoing(HTTPFetchRequest request, CurlHandlePool *pool); + HTTPFetchOngoing(const HTTPFetchRequest &request, CurlHandlePool *pool); ~HTTPFetchOngoing(); CURLcode start(CURLM *multi); @@ -198,7 +225,8 @@ class HTTPFetchOngoing }; -HTTPFetchOngoing::HTTPFetchOngoing(HTTPFetchRequest request_, CurlHandlePool *pool_): +HTTPFetchOngoing::HTTPFetchOngoing(const HTTPFetchRequest &request_, + CurlHandlePool *pool_): pool(pool_), curl(NULL), multi(NULL), @@ -245,7 +273,7 @@ HTTPFetchOngoing::HTTPFetchOngoing(HTTPFetchRequest request_, CurlHandlePool *po curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, request.connect_timeout); - if (request.useragent != "") + if (!request.useragent.empty()) curl_easy_setopt(curl, CURLOPT_USERAGENT, request.useragent.c_str()); // Set up a write callback that writes to the @@ -262,12 +290,11 @@ HTTPFetchOngoing::HTTPFetchOngoing(HTTPFetchRequest request_, CurlHandlePool *po } // Set POST (or GET) data - if (request.post_fields.empty()) { + if (request.post_fields.empty() && request.post_data.empty()) { curl_easy_setopt(curl, CURLOPT_HTTPGET, 1); } else if (request.multipart) { curl_httppost *last = NULL; - for (std::map::iterator it = - request.post_fields.begin(); + for (StringMap::iterator it = request.post_fields.begin(); it != request.post_fields.end(); ++it) { curl_formadd(&post, &last, CURLFORM_NAMELENGTH, it->first.size(), @@ -282,15 +309,12 @@ HTTPFetchOngoing::HTTPFetchOngoing(HTTPFetchRequest request_, CurlHandlePool *po } else if (request.post_data.empty()) { curl_easy_setopt(curl, CURLOPT_POST, 1); std::string str; - for (std::map::iterator it = - request.post_fields.begin(); - it != request.post_fields.end(); - ++it) { - if (str != "") + for (auto &post_field : request.post_fields) { + if (!str.empty()) str += "&"; - str += urlencode(it->first); + str += urlencode(post_field.first); str += "="; - str += urlencode(it->second); + str += urlencode(post_field.second); } curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, str.size()); @@ -306,9 +330,8 @@ HTTPFetchOngoing::HTTPFetchOngoing(HTTPFetchRequest request_, CurlHandlePool *po // modified until CURLOPT_POSTFIELDS is cleared } // Set additional HTTP headers - for (std::vector::iterator it = request.extra_headers.begin(); - it != request.extra_headers.end(); ++it) { - http_header = curl_slist_append(http_header, it->c_str()); + for (const std::string &extra_header : request.extra_headers) { + http_header = curl_slist_append(http_header, extra_header.c_str()); } curl_easy_setopt(curl, CURLOPT_HTTPHEADER, http_header); @@ -393,7 +416,7 @@ HTTPFetchOngoing::~HTTPFetchOngoing() } -class CurlFetchThread : public JThread +class CurlFetchThread : public Thread { protected: enum RequestType { @@ -417,7 +440,8 @@ class CurlFetchThread : public JThread std::list m_queued_fetches; public: - CurlFetchThread(int parallel_limit) + CurlFetchThread(int parallel_limit) : + Thread("CurlFetch") { if (parallel_limit >= 1) m_parallel_limit = parallel_limit; @@ -616,13 +640,9 @@ class CurlFetchThread : public JThread } } - void * Thread() + void *run() { - ThreadStarted(); - log_register_thread("CurlFetchThread"); - DSTACK(__FUNCTION_NAME); - - porting::setThreadName("CurlFetchThread"); + DSTACK(FUNCTION_NAME); CurlHandlePool pool; @@ -634,7 +654,7 @@ class CurlFetchThread : public JThread FATAL_ERROR_IF(!m_all_ongoing.empty(), "Expected empty"); - while (!StopRequested()) { + while (!stopRequested()) { BEGIN_DEBUG_EXCEPTION_HANDLER /* @@ -683,12 +703,12 @@ class CurlFetchThread : public JThread else waitForIO(100); - END_DEBUG_EXCEPTION_HANDLER(errorstream) + END_DEBUG_EXCEPTION_HANDLER } // Call curl_multi_remove_handle and cleanup easy handles - for (size_t i = 0; i < m_all_ongoing.size(); ++i) { - delete m_all_ongoing[i]; + for (HTTPFetchOngoing *i : m_all_ongoing) { + delete i; } m_all_ongoing.clear(); @@ -716,15 +736,20 @@ void httpfetch_init(int parallel_limit) FATAL_ERROR_IF(res != CURLE_OK, "CURL init failed"); g_httpfetch_thread = new CurlFetchThread(parallel_limit); + + // Initialize g_callerid_randomness for httpfetch_caller_alloc_secure + u64 randbuf[2]; + porting::secure_rand_fill_buf(randbuf, sizeof(u64) * 2); + g_callerid_randomness = PcgRandom(randbuf[0], randbuf[1]); } void httpfetch_cleanup() { verbosestream<<"httpfetch_cleanup: cleaning up"<Stop(); + g_httpfetch_thread->stop(); g_httpfetch_thread->requestWakeUp(); - g_httpfetch_thread->Wait(); + g_httpfetch_thread->wait(); delete g_httpfetch_thread; curl_global_cleanup(); @@ -733,18 +758,17 @@ void httpfetch_cleanup() void httpfetch_async(const HTTPFetchRequest &fetch_request) { g_httpfetch_thread->requestFetch(fetch_request); - if (!g_httpfetch_thread->IsRunning()) - g_httpfetch_thread->Start(); + if (!g_httpfetch_thread->isRunning()) + g_httpfetch_thread->start(); } static void httpfetch_request_clear(unsigned long caller) { - if (g_httpfetch_thread->IsRunning()) { + if (g_httpfetch_thread->isRunning()) { Event event; g_httpfetch_thread->requestClear(caller, &event); event.wait(); - } - else { + } else { g_httpfetch_thread->requestClear(caller, NULL); } }