]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/httpfetch.cpp
Fix OSX builds (closes #6289, fixes #6270) (#6306)
[dragonfireclient.git] / src / httpfetch.cpp
index 1a19dd082a463aafbbe75981617261b78cffb15f..c6419a5d661d71b292ad9ab4a3be4c2a9d88a97e 100644 (file)
@@ -18,13 +18,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 */
 
 #include "socket.h" // for select()
-#include "porting.h" // for sleep_ms(), get_sysinfo()
+#include "porting.h" // for sleep_ms(), get_sysinfo(), secure_rand_fill_buf()
 #include "httpfetch.h"
 #include <iostream>
 #include <sstream>
 #include <list>
 #include <map>
-#include <errno.h>
+#include <cerrno>
+#include <mutex>
 #include "threading/event.h"
 #include "config.h"
 #include "exceptions.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"
 
-Mutex g_httpfetch_mutex;
+std::mutex g_httpfetch_mutex;
 std::map<unsigned long, std::queue<HTTPFetchResult> > 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() + ")";
 }
 
 
@@ -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 "
@@ -144,7 +170,8 @@ class CurlHandlePool
        std::list<CURL*> handles;
 
 public:
-       CurlHandlePool() {}
+       CurlHandlePool() = default;
+
        ~CurlHandlePool()
        {
                for (std::list<CURL*>::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
@@ -281,13 +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 (StringMap::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());
@@ -303,9 +330,8 @@ HTTPFetchOngoing::HTTPFetchOngoing(HTTPFetchRequest request_, CurlHandlePool *po
                // modified until CURLOPT_POSTFIELDS is cleared
        }
        // Set additional HTTP headers
-       for (std::vector<std::string>::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);
 
@@ -681,8 +707,8 @@ class CurlFetchThread : public Thread
                }
 
                // 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();
 
@@ -710,6 +736,11 @@ 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()