curl: add verbose logging

and really verbose logging i you use --verbose-curl
This commit is contained in:
Megamouse 2021-11-10 23:34:39 +01:00
parent b736691bde
commit 2359ba9aed
5 changed files with 94 additions and 27 deletions

View File

@ -226,22 +226,23 @@ struct fatal_error_listener final : logs::listener
} }
}; };
constexpr auto arg_headless = "headless"; constexpr auto arg_headless = "headless";
constexpr auto arg_no_gui = "no-gui"; constexpr auto arg_no_gui = "no-gui";
constexpr auto arg_high_dpi = "hidpi"; constexpr auto arg_high_dpi = "hidpi";
constexpr auto arg_rounding = "dpi-rounding"; constexpr auto arg_rounding = "dpi-rounding";
constexpr auto arg_styles = "styles"; constexpr auto arg_styles = "styles";
constexpr auto arg_style = "style"; constexpr auto arg_style = "style";
constexpr auto arg_stylesheet = "stylesheet"; constexpr auto arg_stylesheet = "stylesheet";
constexpr auto arg_config = "config"; constexpr auto arg_config = "config";
constexpr auto arg_q_debug = "qDebug"; constexpr auto arg_q_debug = "qDebug";
constexpr auto arg_error = "error"; constexpr auto arg_error = "error";
constexpr auto arg_updating = "updating"; constexpr auto arg_updating = "updating";
constexpr auto arg_user_id = "user-id"; constexpr auto arg_user_id = "user-id";
constexpr auto arg_installfw = "installfw"; constexpr auto arg_installfw = "installfw";
constexpr auto arg_installpkg = "installpkg"; constexpr auto arg_installpkg = "installpkg";
constexpr auto arg_commit_db = "get-commit-db"; constexpr auto arg_commit_db = "get-commit-db";
constexpr auto arg_timer = "high-res-timer"; constexpr auto arg_timer = "high-res-timer";
constexpr auto arg_verbose_curl = "verbose-curl";
int find_arg(std::string arg, int& argc, char* argv[]) 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_updating, "For internal usage."));
parser.addOption(QCommandLineOption(arg_commit_db, "Update commits.lst cache. Optional arguments: <path> <sha>")); parser.addOption(QCommandLineOption(arg_commit_db, "Update commits.lst cache. Optional arguments: <path> <sha>"));
parser.addOption(QCommandLineOption(arg_timer, "Enable high resolution timer for better performance (windows)", "enabled", "1")); 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()); parser.process(app->arguments());
// Don't start up the full rpcs3 gui if we just want the version or help. // 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)) if (parser.isSet(version_option) || parser.isSet(help_option))
return 0; 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)) if (parser.isSet(arg_commit_db))
{ {
#ifdef _WIN32 #ifdef _WIN32
@ -619,7 +625,7 @@ int main(int argc, char** argv)
QByteArray buf; QByteArray buf;
// CURL handle to work with GitHub API // CURL handle to work with GitHub API
curl_handle curl; rpcs3::curl::curl_handle curl;
struct curl_slist* hhdr{}; struct curl_slist* hhdr{};
hhdr = curl_slist_append(hhdr, "Accept: application/vnd.github.v3+json"); hhdr = curl_slist_append(hhdr, "Accept: application/vnd.github.v3+json");
@ -657,10 +663,14 @@ int main(int argc, char** argv)
break; break;
} }
// Reset error buffer before we call curl_easy_perform
curl.reset_error_buffer();
err = curl_easy_perform(curl); err = curl_easy_perform(curl);
if (err != CURLE_OK) 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; break;
} }

View File

@ -8,16 +8,29 @@
LOG_CHANNEL(network_log, "NET"); LOG_CHANNEL(network_log, "NET");
namespace rpcs3::curl
{
curl_handle::curl_handle(QObject* parent) : QObject(parent) curl_handle::curl_handle(QObject* parent) : QObject(parent)
{ {
reset_error_buffer();
m_curl = curl_easy_init(); 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 #ifdef _WIN32
// This shouldn't be needed on linux // This shouldn't be needed on linux
const std::string path_to_cert = rpcs3::utils::get_exe_dir() + "cacert.pem"; 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 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)); if (err != CURLE_OK) network_log.error("curl_easy_setopt(CURLOPT_CAINFO, %s) error: %s", ansi_path, curl_easy_strerror(err));
#endif #endif
} }
@ -31,3 +44,25 @@ CURL* curl_handle::get_curl() const
{ {
return m_curl; 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<int>(code), curl_easy_strerror(code), m_error_buffer.data());
}
}
return fmt::format("Curl error (%d): %s", static_cast<int>(code), curl_easy_strerror(code));
}
}

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <array>
#include <QObject> #include <QObject>
#ifndef CURL_STATICLIB #ifndef CURL_STATICLIB
@ -7,11 +8,12 @@
#endif #endif
#include <curl/curl.h> #include <curl/curl.h>
namespace rpcs3::curl
{
static bool s_curl_verbose = false;
class curl_handle : public QObject class curl_handle : public QObject
{ {
private:
CURL* m_curl = nullptr;
public: public:
explicit curl_handle(QObject* parent = nullptr); explicit curl_handle(QObject* parent = nullptr);
~curl_handle(); ~curl_handle();
@ -22,4 +24,14 @@ public:
{ {
return get_curl(); 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<char, CURL_ERROR_SIZE> m_error_buffer;
}; };
}

View File

@ -19,7 +19,7 @@ usz curl_write_cb_compat(char* ptr, usz /*size*/, usz nmemb, void* userdata)
downloader::downloader(QWidget* parent) downloader::downloader(QWidget* parent)
: QObject(parent) : QObject(parent)
, m_parent(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] 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; m_curl_success = result == CURLE_OK;
if (!m_curl_success && !m_curl_abort) 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); network_log.error("%s", error);
Q_EMIT signal_download_error(QString::fromStdString(error)); Q_EMIT signal_download_error(QString::fromStdString(error));
} }

View File

@ -3,7 +3,14 @@
#include <QObject> #include <QObject>
#include "util/atomic.hpp" #include "util/atomic.hpp"
class curl_handle; namespace rpcs3
{
namespace curl
{
class curl_handle;
}
}
class progress_dialog; class progress_dialog;
class downloader : public QObject class downloader : public QObject
@ -35,7 +42,7 @@ Q_SIGNALS:
private: private:
QWidget* m_parent = nullptr; QWidget* m_parent = nullptr;
curl_handle* m_curl = nullptr; rpcs3::curl::curl_handle* m_curl = nullptr;
QByteArray m_curl_buf; QByteArray m_curl_buf;
atomic_t<bool> m_curl_abort = false; atomic_t<bool> m_curl_abort = false;
atomic_t<bool> m_curl_success = false; atomic_t<bool> m_curl_success = false;