NOISSUE Resolve minecraft server using DNS SRV

This commit is contained in:
Janrupf 2021-05-22 16:14:25 +02:00
parent cc6cd0648a
commit 23a706bbae
16 changed files with 235 additions and 21 deletions

View File

@ -34,6 +34,8 @@
#include "multimc_logic_export.h" #include "multimc_logic_export.h"
#include "minecraft/launch/MinecraftServerTarget.h"
class QDir; class QDir;
class Task; class Task;
class LaunchTask; class LaunchTask;
@ -221,9 +223,9 @@ public:
bool reloadSettings(); bool reloadSettings();
/** /**
* 'print' a verbose desription of the instance into a QStringList * 'print' a verbose description of the instance into a QStringList
*/ */
virtual QStringList verboseDescription(AuthSessionPtr session) = 0; virtual QStringList verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) = 0;
Status currentStatus() const; Status currentStatus() const;

View File

@ -124,6 +124,8 @@ set(NET_SOURCES
# Game launch logic # Game launch logic
set(LAUNCH_SOURCES set(LAUNCH_SOURCES
launch/steps/LookupServerAddress.cpp
launch/steps/LookupServerAddress.h
launch/steps/PostLaunchCommand.cpp launch/steps/PostLaunchCommand.cpp
launch/steps/PostLaunchCommand.h launch/steps/PostLaunchCommand.h
launch/steps/PreLaunchCommand.cpp launch/steps/PreLaunchCommand.cpp
@ -236,6 +238,7 @@ set(MINECRAFT_SOURCES
minecraft/launch/ExtractNatives.h minecraft/launch/ExtractNatives.h
minecraft/launch/LauncherPartLaunch.cpp minecraft/launch/LauncherPartLaunch.cpp
minecraft/launch/LauncherPartLaunch.h minecraft/launch/LauncherPartLaunch.h
minecraft/launch/MinecraftServerTarget.h
minecraft/launch/PrintInstanceInfo.cpp minecraft/launch/PrintInstanceInfo.cpp
minecraft/launch/PrintInstanceInfo.h minecraft/launch/PrintInstanceInfo.h
minecraft/launch/ReconstructAssets.cpp minecraft/launch/ReconstructAssets.cpp

View File

@ -67,7 +67,7 @@ public:
{ {
return false; return false;
} }
QStringList verboseDescription(AuthSessionPtr session) override QStringList verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) override
{ {
QStringList out; QStringList out;
out << "Null instance - placeholder."; out << "Null instance - placeholder.";

View File

@ -0,0 +1,95 @@
#include "LookupServerAddress.h"
#include <launch/LaunchTask.h>
LookupServerAddress::LookupServerAddress(LaunchTask *parent) :
LaunchStep(parent), m_dnsLookup(new QDnsLookup(this))
{
connect(m_dnsLookup, &QDnsLookup::finished, this, &LookupServerAddress::on_dnsLookupFinished);
m_dnsLookup->setType(QDnsLookup::SRV);
}
void LookupServerAddress::setLookupAddress(const QString &lookupAddress)
{
m_lookupAddress = lookupAddress;
m_dnsLookup->setName(QString("_minecraft._tcp.%1").arg(lookupAddress));
}
void LookupServerAddress::setPort(quint16 port)
{
m_port = port;
}
void LookupServerAddress::setOutputAddressPtr(MinecraftServerTargetPtr output)
{
m_output = std::move(output);
}
bool LookupServerAddress::abort()
{
m_dnsLookup->abort();
emitFailed("Aborted");
return true;
}
void LookupServerAddress::executeTask()
{
m_dnsLookup->lookup();
}
void LookupServerAddress::on_dnsLookupFinished()
{
if (isFinished())
{
// Aborted
return;
}
if (m_dnsLookup->error() != QDnsLookup::NoError)
{
emit logLine(QString("Failed to resolve server address (this is NOT an error!) %1: %2\n")
.arg(m_dnsLookup->name(), m_dnsLookup->errorString()), MessageLevel::MultiMC);
resolve(m_lookupAddress, m_port); // Technically the task failed, however, we don't abort the launch
// and leave it up to minecraft to fail (or maybe not) when connecting
return;
}
const auto records = m_dnsLookup->serviceRecords();
if (records.empty())
{
emit logLine(
QString("Failed to resolve server address %1: the DNS lookup succeeded, but no records were returned.\n")
.arg(m_dnsLookup->name()), MessageLevel::Warning);
resolve(m_lookupAddress, m_port); // Technically the task failed, however, we don't abort the launch
// and leave it up to minecraft to fail (or maybe not) when connecting
return;
}
const auto &firstRecord = records.at(0);
if (firstRecord.port() != m_port && m_port != 0)
{
emit logLine(
QString("DNS record for %1 suggested %2 as server port, but user supplied %3. Using user override,"
" but the port may be wrong!\n").arg(m_dnsLookup->name(), QString::number(firstRecord.port()), QString::number(m_port)),
MessageLevel::Warning);
}
else if (m_port == 0)
{
m_port = firstRecord.port();
}
emit logLine(QString("Resolved server address %1 to %2 with port %3\n").arg(
m_dnsLookup->name(), firstRecord.target(), QString::number(m_port)),MessageLevel::MultiMC);
resolve(firstRecord.target(), m_port);
}
void LookupServerAddress::resolve(const QString &address, quint16 port)
{
m_output->address = address;
m_output->port = port;
emitSucceeded();
m_dnsLookup->deleteLater();
}

View File

@ -0,0 +1,51 @@
/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <launch/LaunchStep.h>
#include <QObjectPtr.h>
#include <QDnsLookup>
#include "minecraft/launch/MinecraftServerTarget.h"
class LookupServerAddress: public LaunchStep {
Q_OBJECT
public:
explicit LookupServerAddress(LaunchTask *parent);
virtual ~LookupServerAddress() {};
virtual void executeTask();
virtual bool abort();
virtual bool canAbort() const
{
return true;
}
void setLookupAddress(const QString &lookupAddress);
void setPort(quint16 port);
void setOutputAddressPtr(MinecraftServerTargetPtr output);
private slots:
void on_dnsLookupFinished();
private:
void resolve(const QString &address, quint16 port);
QDnsLookup *m_dnsLookup;
QString m_lookupAddress;
quint16 m_port;
MinecraftServerTargetPtr m_output;
};

View File

@ -12,6 +12,7 @@
#include <java/JavaVersion.h> #include <java/JavaVersion.h>
#include "launch/LaunchTask.h" #include "launch/LaunchTask.h"
#include "launch/steps/LookupServerAddress.h"
#include "launch/steps/PostLaunchCommand.h" #include "launch/steps/PostLaunchCommand.h"
#include "launch/steps/Update.h" #include "launch/steps/Update.h"
#include "launch/steps/PreLaunchCommand.h" #include "launch/steps/PreLaunchCommand.h"
@ -400,7 +401,8 @@ static QString replaceTokensIn(QString text, QMap<QString, QString> with)
return result; return result;
} }
QStringList MinecraftInstance::processMinecraftArgs(AuthSessionPtr session) const QStringList MinecraftInstance::processMinecraftArgs(
AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) const
{ {
auto profile = m_components->getProfile(); auto profile = m_components->getProfile();
QString args_pattern = profile->getMinecraftArguments(); QString args_pattern = profile->getMinecraftArguments();
@ -409,10 +411,10 @@ QStringList MinecraftInstance::processMinecraftArgs(AuthSessionPtr session) cons
args_pattern += " --tweakClass " + tweaker; args_pattern += " --tweakClass " + tweaker;
} }
if (m_settings->get("JoinServerOnLaunch").toBool()) if (serverToJoin && !serverToJoin->address.isEmpty())
{ {
args_pattern += " --server " + m_settings->get("JoinServerOnLaunchAddress").toString(); args_pattern += " --server " + serverToJoin->address;
args_pattern += " --port " + m_settings->get("JoinServerOnLaunchPort").toString(); args_pattern += " --port " + QString::number(serverToJoin->port);
} }
QMap<QString, QString> token_mapping; QMap<QString, QString> token_mapping;
@ -451,7 +453,7 @@ QStringList MinecraftInstance::processMinecraftArgs(AuthSessionPtr session) cons
return parts; return parts;
} }
QString MinecraftInstance::createLaunchScript(AuthSessionPtr session) QString MinecraftInstance::createLaunchScript(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin)
{ {
QString launchScript; QString launchScript;
@ -473,7 +475,7 @@ QString MinecraftInstance::createLaunchScript(AuthSessionPtr session)
} }
// generic minecraft params // generic minecraft params
for (auto param : processMinecraftArgs(session)) for (auto param : processMinecraftArgs(session, serverToJoin))
{ {
launchScript += "param " + param + "\n"; launchScript += "param " + param + "\n";
} }
@ -523,7 +525,7 @@ QString MinecraftInstance::createLaunchScript(AuthSessionPtr session)
return launchScript; return launchScript;
} }
QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session) QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin)
{ {
QStringList out; QStringList out;
out << "Main Class:" << " " + getMainClass() << ""; out << "Main Class:" << " " + getMainClass() << "";
@ -638,7 +640,7 @@ QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session)
out << ""; out << "";
} }
auto params = processMinecraftArgs(nullptr); auto params = processMinecraftArgs(nullptr, serverToJoin);
out << "Params:"; out << "Params:";
out << " " + params.join(' '); out << " " + params.join(' ');
out << ""; out << "";
@ -844,6 +846,18 @@ shared_qobject_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPt
process->appendStep(new CreateGameFolders(pptr)); process->appendStep(new CreateGameFolders(pptr));
} }
MinecraftServerTargetPtr serverToJoin = std::make_shared<MinecraftServerTarget>();
if (m_settings->get("JoinServerOnLaunch").toBool())
{
// Resolve server address to join on launch
auto *step = new LookupServerAddress(pptr);
step->setLookupAddress(m_settings->get("JoinServerOnLaunchAddress").toString());
step->setPort(m_settings->get("JoinServerOnLaunchPort").toInt());
step->setOutputAddressPtr(serverToJoin);
process->appendStep(step);
}
// run pre-launch command if that's needed // run pre-launch command if that's needed
if(getPreLaunchCommand().size()) if(getPreLaunchCommand().size())
{ {
@ -875,7 +889,7 @@ shared_qobject_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPt
// print some instance info here... // print some instance info here...
{ {
process->appendStep(new PrintInstanceInfo(pptr, session)); process->appendStep(new PrintInstanceInfo(pptr, session, serverToJoin));
} }
// extract native jars if needed // extract native jars if needed
@ -896,6 +910,7 @@ shared_qobject_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPt
auto step = new LauncherPartLaunch(pptr); auto step = new LauncherPartLaunch(pptr);
step->setWorkingDirectory(gameRoot()); step->setWorkingDirectory(gameRoot());
step->setAuthSession(session); step->setAuthSession(session);
step->setServerToJoin(serverToJoin);
process->appendStep(step); process->appendStep(step);
} }
else if (method == "DirectJava") else if (method == "DirectJava")
@ -903,6 +918,7 @@ shared_qobject_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPt
auto step = new DirectJavaLaunch(pptr); auto step = new DirectJavaLaunch(pptr);
step->setWorkingDirectory(gameRoot()); step->setWorkingDirectory(gameRoot());
step->setAuthSession(session); step->setAuthSession(session);
step->setServerToJoin(serverToJoin);
process->appendStep(step); process->appendStep(step);
} }
} }

View File

@ -5,6 +5,7 @@
#include <QProcess> #include <QProcess>
#include <QDir> #include <QDir>
#include "multimc_logic_export.h" #include "multimc_logic_export.h"
#include "minecraft/launch/MinecraftServerTarget.h"
class ModFolderModel; class ModFolderModel;
class WorldList; class WorldList;
@ -78,9 +79,9 @@ public:
shared_qobject_ptr<Task> createUpdateTask(Net::Mode mode) override; shared_qobject_ptr<Task> createUpdateTask(Net::Mode mode) override;
shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr account) override; shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr account) override;
QStringList extraArguments() const override; QStringList extraArguments() const override;
QStringList verboseDescription(AuthSessionPtr session) override; QStringList verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) override;
QList<Mod> getJarMods() const; QList<Mod> getJarMods() const;
QString createLaunchScript(AuthSessionPtr session); QString createLaunchScript(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin);
/// get arguments passed to java /// get arguments passed to java
QStringList javaArguments() const; QStringList javaArguments() const;
@ -107,7 +108,7 @@ public:
virtual QString getMainClass() const; virtual QString getMainClass() const;
// FIXME: remove // FIXME: remove
virtual QStringList processMinecraftArgs(AuthSessionPtr account) const; virtual QStringList processMinecraftArgs(AuthSessionPtr account, MinecraftServerTargetPtr serverToJoin) const;
virtual JavaVersion getJavaVersion() const; virtual JavaVersion getJavaVersion() const;

View File

@ -55,7 +55,7 @@ void DirectJavaLaunch::executeTask()
// make detachable - this will keep the process running even if the object is destroyed // make detachable - this will keep the process running even if the object is destroyed
m_process.setDetachable(true); m_process.setDetachable(true);
auto mcArgs = minecraftInstance->processMinecraftArgs(m_session); auto mcArgs = minecraftInstance->processMinecraftArgs(m_session, m_serverToJoin);
args.append(mcArgs); args.append(mcArgs);
QString wrapperCommandStr = instance->getWrapperCommand().trimmed(); QString wrapperCommandStr = instance->getWrapperCommand().trimmed();

View File

@ -19,6 +19,8 @@
#include <LoggedProcess.h> #include <LoggedProcess.h>
#include <minecraft/auth/AuthSession.h> #include <minecraft/auth/AuthSession.h>
#include "MinecraftServerTarget.h"
class DirectJavaLaunch: public LaunchStep class DirectJavaLaunch: public LaunchStep
{ {
Q_OBJECT Q_OBJECT
@ -38,6 +40,12 @@ public:
{ {
m_session = session; m_session = session;
} }
void setServerToJoin(MinecraftServerTargetPtr serverToJoin)
{
m_serverToJoin = std::move(serverToJoin);
}
private slots: private slots:
void on_state(LoggedProcess::State state); void on_state(LoggedProcess::State state);
@ -45,5 +53,6 @@ private:
LoggedProcess m_process; LoggedProcess m_process;
QString m_command; QString m_command;
AuthSessionPtr m_session; AuthSessionPtr m_session;
MinecraftServerTargetPtr m_serverToJoin;
}; };

View File

@ -59,7 +59,7 @@ void LauncherPartLaunch::executeTask()
auto instance = m_parent->instance(); auto instance = m_parent->instance();
std::shared_ptr<MinecraftInstance> minecraftInstance = std::dynamic_pointer_cast<MinecraftInstance>(instance); std::shared_ptr<MinecraftInstance> minecraftInstance = std::dynamic_pointer_cast<MinecraftInstance>(instance);
m_launchScript = minecraftInstance->createLaunchScript(m_session); m_launchScript = minecraftInstance->createLaunchScript(m_session, m_serverToJoin);
QStringList args = minecraftInstance->javaArguments(); QStringList args = minecraftInstance->javaArguments();
QString allArgs = args.join(", "); QString allArgs = args.join(", ");
emit logLine("Java Arguments:\n[" + m_parent->censorPrivateInfo(allArgs) + "]\n\n", MessageLevel::MultiMC); emit logLine("Java Arguments:\n[" + m_parent->censorPrivateInfo(allArgs) + "]\n\n", MessageLevel::MultiMC);

View File

@ -19,6 +19,8 @@
#include <LoggedProcess.h> #include <LoggedProcess.h>
#include <minecraft/auth/AuthSession.h> #include <minecraft/auth/AuthSession.h>
#include "MinecraftServerTarget.h"
class LauncherPartLaunch: public LaunchStep class LauncherPartLaunch: public LaunchStep
{ {
Q_OBJECT Q_OBJECT
@ -39,6 +41,11 @@ public:
m_session = session; m_session = session;
} }
void setServerToJoin(MinecraftServerTargetPtr serverToJoin)
{
m_serverToJoin = std::move(serverToJoin);
}
private slots: private slots:
void on_state(LoggedProcess::State state); void on_state(LoggedProcess::State state);
@ -47,5 +54,7 @@ private:
QString m_command; QString m_command;
AuthSessionPtr m_session; AuthSessionPtr m_session;
QString m_launchScript; QString m_launchScript;
MinecraftServerTargetPtr m_serverToJoin;
bool mayProceed = false; bool mayProceed = false;
}; };

View File

@ -0,0 +1,25 @@
/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <memory>
struct MinecraftServerTarget {
QString address;
quint16 port;
};
typedef std::shared_ptr<MinecraftServerTarget> MinecraftServerTargetPtr;

View File

@ -101,6 +101,6 @@ void PrintInstanceInfo::executeTask()
#endif #endif
logLines(log, MessageLevel::MultiMC); logLines(log, MessageLevel::MultiMC);
logLines(instance->verboseDescription(m_session), MessageLevel::MultiMC); logLines(instance->verboseDescription(m_session, m_serverToJoin), MessageLevel::MultiMC);
emitSucceeded(); emitSucceeded();
} }

View File

@ -18,13 +18,15 @@
#include <launch/LaunchStep.h> #include <launch/LaunchStep.h>
#include <memory> #include <memory>
#include "minecraft/auth/AuthSession.h" #include "minecraft/auth/AuthSession.h"
#include "minecraft/launch/MinecraftServerTarget.h"
// FIXME: temporary wrapper for existing task. // FIXME: temporary wrapper for existing task.
class PrintInstanceInfo: public LaunchStep class PrintInstanceInfo: public LaunchStep
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit PrintInstanceInfo(LaunchTask *parent, AuthSessionPtr session) : LaunchStep(parent), m_session(session) {}; explicit PrintInstanceInfo(LaunchTask *parent, AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) :
LaunchStep(parent), m_session(session), m_serverToJoin(serverToJoin) {};
virtual ~PrintInstanceInfo(){}; virtual ~PrintInstanceInfo(){};
virtual void executeTask(); virtual void executeTask();
@ -34,5 +36,6 @@ public:
} }
private: private:
AuthSessionPtr m_session; AuthSessionPtr m_session;
MinecraftServerTargetPtr m_serverToJoin;
}; };

View File

@ -225,7 +225,7 @@ QString LegacyInstance::getStatusbarDescription()
return tr("Instance from previous versions."); return tr("Instance from previous versions.");
} }
QStringList LegacyInstance::verboseDescription(AuthSessionPtr session) QStringList LegacyInstance::verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin)
{ {
QStringList out; QStringList out;

View File

@ -125,7 +125,7 @@ public:
} }
QString getStatusbarDescription() override; QString getStatusbarDescription() override;
QStringList verboseDescription(AuthSessionPtr session) override; QStringList verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) override;
QProcessEnvironment createEnvironment() override QProcessEnvironment createEnvironment() override
{ {