implement states until session setup

mod download to be implemented fully
This commit is contained in:
Lion Kortlepel 2024-01-21 22:54:15 +01:00
parent 8eb8a80d54
commit 03dc3e3505
No known key found for this signature in database
GPG Key ID: 4322FF2B4C71259B
9 changed files with 143 additions and 5 deletions

3
.gitmodules vendored
View File

@ -0,0 +1,3 @@
[submodule "deps/BeamMP-Protocol"]
path = deps/BeamMP-Protocol
url = https://github.com/BeamMP/BeamMP-Protocol

View File

@ -32,6 +32,7 @@ set(PRJ_HEADERS
src/Hashing.h
src/Compression.h
src/Config.h
src/ServerNetwork.h
)
# add all source files (.cpp) to this, except the one with main()
set(PRJ_SOURCES
@ -45,6 +46,7 @@ set(PRJ_SOURCES
src/Version.cpp
src/Hashing.cpp
src/Config.cpp
src/ServerNetwork.cpp
)
# set the source file containing main()
set(PRJ_MAIN src/main.cpp)

View File

@ -71,9 +71,7 @@ function(set_project_warnings project_name)
-Werror=write-strings
-Werror=strict-aliasing -fstrict-aliasing
-Werror=missing-declarations
-Werror=missing-field-initializers
-Werror=ctor-dtor-privacy
-Werror=switch-default
-Werror=unused-result
-Werror=implicit-fallthrough
-Wmissing-include-dirs

1
deps/BeamMP-Protocol vendored Submodule

@ -0,0 +1 @@
Subproject commit ff4a2f5472b997da8947a8b2769a942ccc2d2b20

View File

@ -886,3 +886,7 @@ void Launcher::udp_send(const std::string& data) {
to_send.insert(to_send.end(), vec.begin(), vec.end());
m_udp_socket.send_to(buffer(to_send.data(), to_send.size()), m_udp_endpoint);
}
std::string Launcher::get_public_key() {
return m_identity->PublicKey;
}

View File

@ -31,6 +31,8 @@ public:
void start_network();
std::string get_public_key();
private:
/// Thread main function for the http(s) proxy thread.
void proxy_main();

View File

@ -1,9 +1,12 @@
#include "ServerNetwork.h"
#include "ClientInfo.h"
#include "Identity.h"
#include "ImplementationInfo.h"
#include "Launcher.h"
#include "ProtocolVersion.h"
#include "ServerInfo.h"
#include "Util.h"
#include <nlohmann/json.hpp>
#include <spdlog/spdlog.h>
ServerNetwork::ServerNetwork(Launcher& launcher, const ip::tcp::endpoint& ep)
@ -30,6 +33,7 @@ void ServerNetwork::run() {
.purpose = bmp::Purpose::ProtocolVersion,
.raw_data = std::vector<uint8_t>(6),
};
spdlog::trace("Protocol version: v{}.{}.{}", 1, 0, 0);
struct bmp::ProtocolVersion version {
.version = {
.major = 1,
@ -47,6 +51,14 @@ void ServerNetwork::run() {
}
void ServerNetwork::handle_packet(const bmp::Packet& packet) {
// handle ping immediately
if (m_state > bmp::State::Identification && packet.purpose == bmp::Purpose::Ping) {
bmp::Packet pong {
.purpose = bmp::Purpose::Ping,
};
tcp_write(pong);
return;
}
switch (m_state) {
case bmp::State::None:
m_state = bmp::State::Identification;
@ -55,8 +67,10 @@ void ServerNetwork::handle_packet(const bmp::Packet& packet) {
handle_identification(packet);
break;
case bmp::State::Authentication:
handle_authentication(packet);
break;
case bmp::State::ModDownload:
handle_mod_download(packet);
break;
case bmp::State::SessionSetup:
break;
@ -67,6 +81,79 @@ void ServerNetwork::handle_packet(const bmp::Packet& packet) {
}
}
void ServerNetwork::handle_mod_download(const bmp::Packet& packet) {
switch (packet.purpose) {
case bmp::Purpose::ModsInfo: {
auto data = packet.get_readable_data();
auto mods_info = nlohmann::json::parse(data.begin(), data.end());
spdlog::info("Got info about {} mod(s)", mods_info.size());
for (const auto& mod : mods_info) {
spdlog::warn("Mod download not implemented, but data is: {}", mod.dump(4));
}
// TODO: implement mod download
// for now we just pretend we're all good!
bmp::Packet ok {
.purpose = bmp::Purpose::ModsSyncDone,
};
spdlog::info("Done syncing mods");
tcp_write(ok);
break;
}
case bmp::Purpose::StateChangeSessionSetup: {
spdlog::info("Starting session setup");
m_state = bmp::State::SessionSetup;
break;
}
default:
spdlog::error("Got 0x{:x} in state {}. This is not allowed. Disconnecting", uint16_t(packet.purpose), int(m_state));
// todo: disconnect gracefully
break;
}
}
void ServerNetwork::handle_authentication(const bmp::Packet& packet) {
switch (packet.purpose) {
case bmp::Purpose::AuthOk: {
spdlog::info("Authentication succeeded");
uint32_t player_id;
bmp::deserialize(player_id, packet.get_readable_data());
spdlog::debug("Player id: {}", player_id);
break;
}
case bmp::Purpose::AuthFailed: {
auto data = packet.get_readable_data();
spdlog::error("Authentication failed: {}", std::string(data.begin(), data.end()));
break;
}
case bmp::Purpose::PlayerRejected: {
auto data = packet.get_readable_data();
spdlog::error("Server rejected me: {}", std::string(data.begin(), data.end()));
break;
}
case bmp::Purpose::StartUDP: {
bmp::deserialize(m_udp_magic, packet.get_readable_data());
spdlog::debug("UDP start, got magic 0x{:x}", m_udp_magic);
m_udp_ep = ip::udp::endpoint(m_tcp_ep.address(), m_tcp_ep.port());
m_udp_socket.open(m_tcp_ep.address().is_v4() ? ip::udp::v4() : ip::udp::v6());
auto copy = bmp::Packet {
.purpose = bmp::Purpose::StartUDP,
.raw_data = packet.get_readable_data(),
};
udp_write(copy);
break;
}
case bmp::Purpose::StateChangeModDownload: {
spdlog::info("Starting mod sync");
m_state = bmp::State::ModDownload;
break;
}
default:
spdlog::error("Got 0x{:x} in state {}. This is not allowed. Disconnecting", uint16_t(packet.purpose), int(m_state));
// todo: disconnect gracefully
break;
}
}
void ServerNetwork::handle_identification(const bmp::Packet& packet) {
switch (packet.purpose) {
case bmp::Purpose::ProtocolVersionOk: {
@ -106,6 +193,13 @@ void ServerNetwork::handle_identification(const bmp::Packet& packet) {
case bmp::Purpose::StateChangeAuthentication: {
spdlog::debug("Starting authentication");
m_state = bmp::State::Authentication;
// TODO: make the launcher provide login properly!
auto pubkey = m_launcher.get_public_key();
bmp::Packet pubkey_packet {
.purpose = bmp::Purpose::PlayerPublicKey,
.raw_data = std::vector<uint8_t>(pubkey.begin(), pubkey.end())
};
tcp_write(pubkey_packet);
break;
}
default:

View File

@ -31,6 +31,8 @@ private:
void handle_packet(const bmp::Packet& packet);
void handle_identification(const bmp::Packet& packet);
void handle_authentication(const bmp::Packet& packet);
void handle_mod_download(const bmp::Packet& packet);
io_context m_io {};
ip::tcp::socket m_tcp_socket { m_io };
@ -38,6 +40,8 @@ private:
bmp::State m_state {};
uint64_t m_udp_magic {};
Launcher& m_launcher;
ip::tcp::endpoint m_tcp_ep;

View File

@ -1,5 +1,8 @@
#include "Launcher.h"
#include "Platform.h"
#include "ServerNetwork.h"
#include <boost/system/detail/errc.hpp>
#include <boost/system/detail/error_category.hpp>
#include <iostream>
#include <thread>
@ -16,8 +19,10 @@ int main(int argc, char** argv) {
bool enable_dev = false;
int custom_port = 0;
std::string_view invalid_arg;
std::string all_args = std::string { argv[0] } + " ";
for (int i = 1; i < argc; ++i) {
std::string_view arg(argv[i]);
all_args += "'" + std::string(arg) + "' ";
std::string_view next(i + 1 < argc ? argv[i + 1] : "");
// --debug flag enables debug printing in console
if (arg == "--debug") {
@ -37,18 +42,30 @@ int main(int argc, char** argv) {
}
setup_logger(enable_debug || enable_dev);
spdlog::debug("Debug enabled");
spdlog::trace("BeamMP Launcher invoked as: {}", all_args);
if (enable_debug) {
spdlog::debug("Debug mode enabled");
}
if (enable_dev) {
spdlog::debug("Development mode enabled");
}
if (custom_port != 0) {
spdlog::debug("Custom port set: {}", custom_port);
}
if (!invalid_arg.empty()) {
spdlog::warn("Invalid argument passed via commandline switches: '{}'. This argument was ignored.", invalid_arg);
spdlog::warn("One or more invalid argument(s) passed via commandline switches, last one: '{}'. This argument was ignored.", invalid_arg);
}
plat::clear_screen();
plat::set_console_title(fmt::format("BeamMP Launcher v{}.{}.{}", PRJ_VERSION_MAJOR, PRJ_VERSION_MINOR, PRJ_VERSION_PATCH));
spdlog::trace("BeamMP Launcher v{}.{}.{}", PRJ_VERSION_MAJOR, PRJ_VERSION_MINOR, PRJ_VERSION_PATCH);
spdlog::info("BeamMP Launcher v{}.{}.{} is a PRE-RELEASE build. Please report any errors immediately at https://github.com/BeamMP/BeamMP-Launcher.",
PRJ_VERSION_MAJOR, PRJ_VERSION_MINOR, PRJ_VERSION_PATCH);
/*
Launcher launcher {};
std::filesystem::path arg0(argv[0]);
@ -73,7 +90,19 @@ int main(int argc, char** argv) {
}
launcher.start_network();
*/
Launcher launcher {};
std::filesystem::path arg0(argv[0]);
launcher.set_exe_name(arg0.filename().generic_string());
launcher.set_exe_path(arg0.parent_path());
try {
ServerNetwork sn(launcher, ip::tcp::endpoint(ip::address::from_string("127.0.0.1"), 30814));
sn.run();
} catch (const std::exception& e) {
spdlog::error("Connection to server closed: {}", e.what());
}
spdlog::info("Shutting down.");
}
@ -88,11 +117,12 @@ void setup_logger(bool debug) {
auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("Launcher.log", true);
file_sink->set_level(spdlog::level::trace);
file_sink->set_pattern("[%H:%M:%S.%e] [%t] [%L] %v");
default_logger = std::make_shared<spdlog::logger>(spdlog::logger("default", { console_sink, file_sink }));
default_logger->set_level(spdlog::level::trace);
default_logger->flush_on(spdlog::level::info);
default_logger->flush_on(spdlog::level::trace);
spdlog::set_default_logger(default_logger);