From 2359ba9aed780cd004f98613582055423a2c9d63 Mon Sep 17 00:00:00 2001 From: Megamouse Date: Wed, 10 Nov 2021 23:34:39 +0100 Subject: [PATCH] curl: add verbose logging and really verbose logging i you use --verbose-curl --- rpcs3/main.cpp | 46 +++++++++++++++++++++-------------- rpcs3/rpcs3qt/curl_handle.cpp | 37 +++++++++++++++++++++++++++- rpcs3/rpcs3qt/curl_handle.h | 18 +++++++++++--- rpcs3/rpcs3qt/downloader.cpp | 9 ++++--- rpcs3/rpcs3qt/downloader.h | 11 +++++++-- 5 files changed, 94 insertions(+), 27 deletions(-) diff --git a/rpcs3/main.cpp b/rpcs3/main.cpp index fd9cd1efd0..f8a53c6d60 100644 --- a/rpcs3/main.cpp +++ b/rpcs3/main.cpp @@ -226,22 +226,23 @@ struct fatal_error_listener final : logs::listener } }; -constexpr auto arg_headless = "headless"; -constexpr auto arg_no_gui = "no-gui"; -constexpr auto arg_high_dpi = "hidpi"; -constexpr auto arg_rounding = "dpi-rounding"; -constexpr auto arg_styles = "styles"; -constexpr auto arg_style = "style"; -constexpr auto arg_stylesheet = "stylesheet"; -constexpr auto arg_config = "config"; -constexpr auto arg_q_debug = "qDebug"; -constexpr auto arg_error = "error"; -constexpr auto arg_updating = "updating"; -constexpr auto arg_user_id = "user-id"; -constexpr auto arg_installfw = "installfw"; -constexpr auto arg_installpkg = "installpkg"; -constexpr auto arg_commit_db = "get-commit-db"; -constexpr auto arg_timer = "high-res-timer"; +constexpr auto arg_headless = "headless"; +constexpr auto arg_no_gui = "no-gui"; +constexpr auto arg_high_dpi = "hidpi"; +constexpr auto arg_rounding = "dpi-rounding"; +constexpr auto arg_styles = "styles"; +constexpr auto arg_style = "style"; +constexpr auto arg_stylesheet = "stylesheet"; +constexpr auto arg_config = "config"; +constexpr auto arg_q_debug = "qDebug"; +constexpr auto arg_error = "error"; +constexpr auto arg_updating = "updating"; +constexpr auto arg_user_id = "user-id"; +constexpr auto arg_installfw = "installfw"; +constexpr auto arg_installpkg = "installpkg"; +constexpr auto arg_commit_db = "get-commit-db"; +constexpr auto arg_timer = "high-res-timer"; +constexpr auto arg_verbose_curl = "verbose-curl"; int find_arg(std::string arg, int& argc, char* argv[]) { @@ -536,12 +537,17 @@ int main(int argc, char** argv) parser.addOption(QCommandLineOption(arg_updating, "For internal usage.")); parser.addOption(QCommandLineOption(arg_commit_db, "Update commits.lst cache. Optional arguments: ")); parser.addOption(QCommandLineOption(arg_timer, "Enable high resolution timer for better performance (windows)", "enabled", "1")); + parser.addOption(QCommandLineOption(arg_verbose_curl, "Enable verbose curl logging.")); parser.process(app->arguments()); // Don't start up the full rpcs3 gui if we just want the version or help. if (parser.isSet(version_option) || parser.isSet(help_option)) return 0; + // Set curl to verbose if needed + rpcs3::curl::s_curl_verbose = parser.isSet(arg_verbose_curl); + + // Handle update of commit database if (parser.isSet(arg_commit_db)) { #ifdef _WIN32 @@ -619,7 +625,7 @@ int main(int argc, char** argv) QByteArray buf; // CURL handle to work with GitHub API - curl_handle curl; + rpcs3::curl::curl_handle curl; struct curl_slist* hhdr{}; hhdr = curl_slist_append(hhdr, "Accept: application/vnd.github.v3+json"); @@ -657,10 +663,14 @@ int main(int argc, char** argv) break; } + // Reset error buffer before we call curl_easy_perform + curl.reset_error_buffer(); + err = curl_easy_perform(curl); if (err != CURLE_OK) { - fprintf(stderr, "Curl error:\n%s", curl_easy_strerror(err)); + const std::string error_string = curl.get_verbose_error(err); + fprintf(stderr, "curl_easy_perform(): %s", error_string.c_str()); break; } diff --git a/rpcs3/rpcs3qt/curl_handle.cpp b/rpcs3/rpcs3qt/curl_handle.cpp index 55a876e6c0..6aad308f90 100644 --- a/rpcs3/rpcs3qt/curl_handle.cpp +++ b/rpcs3/rpcs3qt/curl_handle.cpp @@ -8,16 +8,29 @@ LOG_CHANNEL(network_log, "NET"); +namespace rpcs3::curl +{ + curl_handle::curl_handle(QObject* parent) : QObject(parent) { + reset_error_buffer(); + m_curl = curl_easy_init(); + CURLcode err = curl_easy_setopt(m_curl, CURLOPT_ERRORBUFFER, m_error_buffer.data()); + if (err != CURLE_OK) network_log.error("curl_easy_setopt(CURLOPT_ERRORBUFFER): %s", curl_easy_strerror(err)); + + m_uses_error_buffer = err == CURLE_OK; + + err = curl_easy_setopt(m_curl, CURLOPT_VERBOSE, s_curl_verbose); + if (err != CURLE_OK) network_log.error("curl_easy_setopt(CURLOPT_VERBOSE, %d): %s", s_curl_verbose, curl_easy_strerror(err)); + #ifdef _WIN32 // This shouldn't be needed on linux const std::string path_to_cert = rpcs3::utils::get_exe_dir() + "cacert.pem"; const std::string ansi_path = utf8_path_to_ansi_path(path_to_cert); - const CURLcode err = curl_easy_setopt(m_curl, CURLOPT_CAINFO, ansi_path.data()); + err = curl_easy_setopt(m_curl, CURLOPT_CAINFO, ansi_path.data()); if (err != CURLE_OK) network_log.error("curl_easy_setopt(CURLOPT_CAINFO, %s) error: %s", ansi_path, curl_easy_strerror(err)); #endif } @@ -31,3 +44,25 @@ CURL* curl_handle::get_curl() const { return m_curl; } + +void curl_handle::reset_error_buffer() +{ + ensure(m_error_buffer.size() == CURL_ERROR_SIZE); + m_error_buffer[0] = 0; +} + +std::string curl_handle::get_verbose_error(CURLcode code) +{ + if (m_uses_error_buffer) + { + ensure(m_error_buffer.size() == CURL_ERROR_SIZE); + if (m_error_buffer[0]) + { + return fmt::format("Curl error (%d): %s\nDetails: %s", static_cast(code), curl_easy_strerror(code), m_error_buffer.data()); + } + } + + return fmt::format("Curl error (%d): %s", static_cast(code), curl_easy_strerror(code)); +} + +} diff --git a/rpcs3/rpcs3qt/curl_handle.h b/rpcs3/rpcs3qt/curl_handle.h index 65abee5978..ad26d08f38 100644 --- a/rpcs3/rpcs3qt/curl_handle.h +++ b/rpcs3/rpcs3qt/curl_handle.h @@ -1,5 +1,6 @@ #pragma once +#include #include #ifndef CURL_STATICLIB @@ -7,11 +8,12 @@ #endif #include +namespace rpcs3::curl +{ +static bool s_curl_verbose = false; + class curl_handle : public QObject { -private: - CURL* m_curl = nullptr; - public: explicit curl_handle(QObject* parent = nullptr); ~curl_handle(); @@ -22,4 +24,14 @@ public: { return get_curl(); } + + void reset_error_buffer(); + std::string get_verbose_error(CURLcode code); + +private: + CURL* m_curl = nullptr; + bool m_uses_error_buffer = false; + std::array m_error_buffer; }; + +} diff --git a/rpcs3/rpcs3qt/downloader.cpp b/rpcs3/rpcs3qt/downloader.cpp index be3c3f40cc..c1d63ec83a 100644 --- a/rpcs3/rpcs3qt/downloader.cpp +++ b/rpcs3/rpcs3qt/downloader.cpp @@ -19,7 +19,7 @@ usz curl_write_cb_compat(char* ptr, usz /*size*/, usz nmemb, void* userdata) downloader::downloader(QWidget* parent) : QObject(parent) , m_parent(parent) - , m_curl(new curl_handle(this)) + , m_curl(new rpcs3::curl::curl_handle(this)) { } @@ -64,12 +64,15 @@ void downloader::start(const std::string& url, bool follow_location, bool show_p m_thread = QThread::create([this] { - const auto result = curl_easy_perform(m_curl->get_curl()); + // Reset error buffer before we call curl_easy_perform + m_curl->reset_error_buffer(); + + const CURLcode result = curl_easy_perform(m_curl->get_curl()); m_curl_success = result == CURLE_OK; if (!m_curl_success && !m_curl_abort) { - const std::string error = "Curl error: " + std::string{ curl_easy_strerror(result) }; + const std::string error = fmt::format("curl_easy_perform(): %s", m_curl->get_verbose_error(result)); network_log.error("%s", error); Q_EMIT signal_download_error(QString::fromStdString(error)); } diff --git a/rpcs3/rpcs3qt/downloader.h b/rpcs3/rpcs3qt/downloader.h index cde365f653..f87284dde3 100644 --- a/rpcs3/rpcs3qt/downloader.h +++ b/rpcs3/rpcs3qt/downloader.h @@ -3,7 +3,14 @@ #include #include "util/atomic.hpp" -class curl_handle; +namespace rpcs3 +{ + namespace curl + { + class curl_handle; + } +} + class progress_dialog; class downloader : public QObject @@ -35,7 +42,7 @@ Q_SIGNALS: private: QWidget* m_parent = nullptr; - curl_handle* m_curl = nullptr; + rpcs3::curl::curl_handle* m_curl = nullptr; QByteArray m_curl_buf; atomic_t m_curl_abort = false; atomic_t m_curl_success = false;