mirror of
https://github.com/Qv2ray/Qv2ray.git
synced 2025-05-21 11:20:49 +08:00
306 lines
11 KiB
C++
306 lines
11 KiB
C++
#ifdef QV2RAY_HAS_BACKWARD
|
|
#include "3rdparty/backward-cpp/backward.hpp"
|
|
#endif
|
|
#ifdef QV2RAY_CLI
|
|
#include "ui/cli/Qv2rayCliApplication.hpp"
|
|
#else
|
|
#include <QMessageBox>
|
|
#endif
|
|
#ifdef QV2RAY_GUI_QWIDGETS
|
|
#include "ui/widgets/Qv2rayWidgetApplication.hpp"
|
|
#endif
|
|
#ifdef QV2RAY_GUI_QML
|
|
#include "ui/qml/Qv2rayQMLApplication.hpp"
|
|
#endif
|
|
|
|
#include "utils/QvHelpers.hpp"
|
|
|
|
#include <QSslSocket>
|
|
#include <csignal>
|
|
|
|
#ifndef Q_OS_WIN
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
int globalArgc;
|
|
char **globalArgv;
|
|
|
|
void BootstrapMessageBox(const QString &title, const QString &text)
|
|
{
|
|
#ifdef QV2RAY_GUI
|
|
if (qApp)
|
|
{
|
|
QMessageBox::warning(nullptr, title, text);
|
|
}
|
|
else
|
|
{
|
|
QApplication p(globalArgc, globalArgv);
|
|
QMessageBox::warning(nullptr, title, text);
|
|
}
|
|
#else
|
|
std::cout << title.toStdString() << NEWLINE << text.toStdString() << std::endl;
|
|
#endif
|
|
}
|
|
|
|
const QString SayLastWords() noexcept
|
|
{
|
|
QStringList msg;
|
|
msg << "------- BEGIN QV2RAY CRASH REPORT -------";
|
|
#ifdef QV2RAY_HAS_BACKWARD
|
|
{
|
|
backward::StackTrace st;
|
|
backward::TraceResolver resolver;
|
|
st.load_here();
|
|
resolver.load_stacktrace(st);
|
|
//
|
|
for (size_t i = 0; i < st.size(); i++)
|
|
{
|
|
const auto &trace = resolver.resolve(st[i]);
|
|
const auto line = QString("#%1: [%2] %3 in %4")
|
|
.arg(i)
|
|
.arg(reinterpret_cast<size_t>(trace.addr))
|
|
.arg(trace.object_function.c_str())
|
|
.arg(trace.object_filename.c_str());
|
|
if (!trace.source.filename.empty())
|
|
{
|
|
const auto sourceFile = QString("%0:[%1:%2]").arg(trace.source.filename.c_str()).arg(trace.source.line).arg(trace.source.col);
|
|
msg << line + " --> " + sourceFile;
|
|
}
|
|
else
|
|
{
|
|
msg << line;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (KernelInstance)
|
|
{
|
|
msg << "Active Kernel Instances:";
|
|
const auto kernels = KernelInstance->GetActiveKernelProtocols();
|
|
msg << JsonToString(JsonStructHelper::Serialize(static_cast<QList<QString>>(kernels)).toArray(), QJsonDocument::Compact);
|
|
msg << "Current Connection:";
|
|
//
|
|
const auto currentConnection = KernelInstance->CurrentConnection();
|
|
msg << JsonToString(currentConnection.toJson(), QJsonDocument::Compact);
|
|
msg << NEWLINE;
|
|
//
|
|
if (ConnectionManager && !currentConnection.isEmpty())
|
|
{
|
|
msg << "Active Connection Settings:";
|
|
const auto connection = ConnectionManager->GetConnectionMetaObject(currentConnection.connectionId);
|
|
auto group = ConnectionManager->GetGroupMetaObject(currentConnection.groupId);
|
|
//
|
|
// Do not collect private data.
|
|
// msg << NEWLINE;
|
|
// msg << JsonToString(ConnectionManager->GetConnectionRoot(currentConnection.connectionId));
|
|
group.subscriptionOption.address = "HIDDEN";
|
|
//
|
|
msg << JsonToString(connection.toJson(), QJsonDocument::Compact);
|
|
msg << NEWLINE;
|
|
msg << "Group:";
|
|
msg << JsonToString(group.toJson(), QJsonDocument::Compact);
|
|
msg << NEWLINE;
|
|
}
|
|
}
|
|
if (PluginHost)
|
|
{
|
|
msg << "Plugins:";
|
|
const auto plugins = PluginHost->AllPlugins();
|
|
for (const auto &plugin : plugins)
|
|
{
|
|
const auto data = PluginHost->GetPlugin(plugin)->metadata;
|
|
QList<QString> dataList;
|
|
dataList << data.Name;
|
|
dataList << data.Author;
|
|
dataList << data.InternalName;
|
|
dataList << data.Description;
|
|
msg << JsonToString(JsonStructHelper::Serialize(dataList).toArray(), QJsonDocument::Compact);
|
|
}
|
|
msg << NEWLINE;
|
|
}
|
|
|
|
msg << "GlobalConfig:";
|
|
msg << JsonToString(GlobalConfig.toJson(), QJsonDocument::Compact);
|
|
msg << "------- END OF QV2RAY CRASH REPORT -------";
|
|
return msg.join(NEWLINE);
|
|
}
|
|
|
|
void signalHandler(int signum)
|
|
{
|
|
#ifndef Q_OS_WIN
|
|
if (signum == SIGTRAP)
|
|
{
|
|
exit(-99);
|
|
return;
|
|
}
|
|
#endif
|
|
std::cout << "Qv2ray: Interrupt signal (" << signum << ") received." << std::endl;
|
|
|
|
if (signum == SIGTERM)
|
|
{
|
|
if (qApp)
|
|
qApp->exit();
|
|
return;
|
|
}
|
|
std::cout << "Collecting StackTrace" << std::endl;
|
|
const auto msg = "Signal: " + QSTRN(signum) + NEWLINE + SayLastWords();
|
|
const auto filePath = QV2RAY_CONFIG_DIR + "bugreport/QvBugReport_" + QSTRN(system_clock::to_time_t(system_clock::now())) + ".stacktrace";
|
|
{
|
|
std::cout << msg.toStdString() << std::endl;
|
|
QDir().mkpath(QV2RAY_CONFIG_DIR + "bugreport/");
|
|
StringToFile(msg, filePath);
|
|
std::cout << "Backtrace saved in: " + filePath.toStdString() << std::endl;
|
|
}
|
|
if (qApp)
|
|
{
|
|
// qApp->clipboard()->setText(filePath);
|
|
QString message = QObject::tr("Qv2ray has encountered an uncaught exception: ") + NEWLINE + //
|
|
QObject::tr("Please report a bug via Github with the file located here: ") + NEWLINE NEWLINE + //
|
|
filePath;
|
|
BootstrapMessageBox("UNCAUGHT EXCEPTION", message);
|
|
}
|
|
#if defined Q_OS_WIN || defined QT_DEBUG
|
|
exit(-99);
|
|
#else
|
|
kill(getpid(), SIGTRAP);
|
|
#endif
|
|
}
|
|
|
|
#ifdef Q_OS_WIN
|
|
LONG WINAPI TopLevelExceptionHandler(PEXCEPTION_POINTERS)
|
|
{
|
|
signalHandler(-1);
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
|
}
|
|
#endif
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
globalArgc = argc;
|
|
globalArgv = argv;
|
|
// Register signal handlers.
|
|
signal(SIGABRT, signalHandler);
|
|
signal(SIGSEGV, signalHandler);
|
|
signal(SIGTERM, signalHandler);
|
|
#ifndef Q_OS_WIN
|
|
signal(SIGHUP, signalHandler);
|
|
signal(SIGKILL, signalHandler);
|
|
#else
|
|
// AddVectoredExceptionHandler(0, TopLevelExceptionHandler);
|
|
#endif
|
|
//
|
|
// This line must be called before any other ones, since we are using these
|
|
// values to identify instances.
|
|
QCoreApplication::setApplicationVersion(QV2RAY_VERSION_STRING);
|
|
//
|
|
#ifdef QT_DEBUG
|
|
QCoreApplication::setApplicationName("qv2ray_debug");
|
|
// QApplication::setApplicationDisplayName("Qv2ray - " + QObject::tr("Debug version"));
|
|
#else
|
|
QCoreApplication::setApplicationName("qv2ray");
|
|
#ifdef QV2RAY_GUI
|
|
QApplication::setApplicationDisplayName("Qv2ray");
|
|
#endif
|
|
#endif
|
|
LOG("LICENCE", NEWLINE //
|
|
"This program comes with ABSOLUTELY NO WARRANTY." NEWLINE //
|
|
"This is free software, and you are welcome to redistribute it" NEWLINE //
|
|
"under certain conditions." NEWLINE NEWLINE //
|
|
"Copyright (c) 2019-2020 Qv2ray Development Group." NEWLINE //
|
|
"Third-party libraries that have been used in Qv2ray can be found in the About page." NEWLINE)
|
|
|
|
#ifdef QT_DEBUG
|
|
std::cerr << "WARNING: ================ This is a debug build, many features are not stable enough. ================" << std::endl;
|
|
#endif
|
|
|
|
// parse the command line before starting as a Qt application
|
|
switch (Qv2rayApplicationManager::PreInitialize(argc, argv))
|
|
{
|
|
case PRE_INIT_RESULT_QUIT: return QVEXIT_NORMAL;
|
|
case PRE_INIT_RESULT_CONTINUE: break;
|
|
case PRE_INIT_RESULT_ERROR:
|
|
{
|
|
BootstrapMessageBox("Cannot Start Qv2ray!", "Early initialization failed!");
|
|
return QVEXIT_PRE_INITIALIZE_FAIL;
|
|
}
|
|
default: Q_UNREACHABLE();
|
|
}
|
|
#ifndef QV2RAY_QT6
|
|
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, true);
|
|
#endif
|
|
// noScaleFactors = disable HiDPI
|
|
if (StartupOption.noScaleFactor)
|
|
{
|
|
LOG(MODULE_INIT, "Force set QT_SCALE_FACTOR to 1.")
|
|
DEBUG(MODULE_UI, "Original QT_SCALE_FACTOR was: " + qEnvironmentVariable("QT_SCALE_FACTOR"))
|
|
qputenv("QT_SCALE_FACTOR", "1");
|
|
}
|
|
else
|
|
{
|
|
DEBUG(MODULE_INIT, "High DPI scaling is enabled.")
|
|
#ifndef QV2RAY_QT6
|
|
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
|
#endif
|
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
|
#ifdef QV2RAY_GUI
|
|
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
// Check OpenSSL version for auto-update and subscriptions
|
|
auto osslReqVersion = QSslSocket::sslLibraryBuildVersionString();
|
|
auto osslCurVersion = QSslSocket::sslLibraryVersionString();
|
|
LOG(MODULE_NETWORK, "Current OpenSSL version: " + osslCurVersion)
|
|
|
|
if (!QSslSocket::supportsSsl())
|
|
{
|
|
LOG(MODULE_NETWORK, "Required OpenSSL version: " + osslReqVersion)
|
|
LOG(MODULE_NETWORK, "OpenSSL library MISSING, Quitting.")
|
|
BootstrapMessageBox(QObject::tr("Dependency Missing"),
|
|
QObject::tr("Cannot find openssl libs") + NEWLINE +
|
|
QObject::tr("This could be caused by a missing of `openssl` package in your system.") + NEWLINE +
|
|
QObject::tr("If you are using an AppImage from Github Action, please report a bug.") + NEWLINE + //
|
|
NEWLINE + QObject::tr("Technical Details") + NEWLINE + //
|
|
"OSsl.Rq.V=" + osslReqVersion + NEWLINE + //
|
|
"OSsl.Cr.V=" + osslCurVersion);
|
|
BootstrapMessageBox(QObject::tr("Cannot start Qv2ray"), QObject::tr("Cannot start Qv2ray without OpenSSL"));
|
|
return QVEXIT_SSL_FAIL;
|
|
}
|
|
|
|
Qv2rayApplication app(argc, argv);
|
|
switch (app.Initialize())
|
|
{
|
|
case NORMAL: break;
|
|
case SINGLE_APPLICATION: return QVEXIT_SECONDARY_INSTANCE;
|
|
case FAILED:
|
|
{
|
|
app.MessageBoxWarn(nullptr, app.tr("Cannot start Qv2ray"), app.tr("Qv2ray early initialization failed."));
|
|
return QVEXIT_EARLY_SETUP_FAIL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Qv2ray Initialize, find possible config paths and verify them.
|
|
if (!app.FindAndCreateInitialConfiguration())
|
|
{
|
|
LOG(MODULE_INIT, "Cannot load or create initial configuration file.")
|
|
app.MessageBoxWarn(nullptr, app.tr("Cannot start Qv2ray"), app.tr("Cannot load config file."));
|
|
return QVEXIT_CONFIG_FILE_FAIL;
|
|
}
|
|
|
|
#ifndef Q_OS_WIN
|
|
signal(SIGUSR1, [](int) { ConnectionManager->RestartConnection(); });
|
|
signal(SIGUSR2, [](int) { ConnectionManager->StopConnection(); });
|
|
#endif
|
|
|
|
const auto rcode = app.RunQv2ray();
|
|
if (rcode == QVEXIT_NEW_VERSION)
|
|
{
|
|
LOG(MODULE_INIT, "Starting new version of Qv2ray: " + Qv2rayProcessArgument._qvNewVersionPath)
|
|
QProcess::startDetached(Qv2rayProcessArgument._qvNewVersionPath, {});
|
|
}
|
|
return rcode;
|
|
}
|