diff --git a/src/common/application.cpp b/src/common/application.cpp index 0a5f7cec9ae..699f0e8d61f 100644 --- a/src/common/application.cpp +++ b/src/common/application.cpp @@ -20,11 +20,13 @@ */ #include "application.h" + #include "debug.h" #include "logging.h" #include "lua.h" #include "settings.h" #include "taskmgr.h" +#include "xirand.h" #ifdef _WIN32 #include @@ -41,24 +43,26 @@ Application::Application(std::string const& serverName, int argc, char** argv) SetConsoleTitleA(fmt::format("{}-server", serverName_).c_str()); #endif - gArgParser->add_argument("--log") + argParser_->add_argument("--log") .default_value(fmt::format("log/{}-server.log", serverName_)); try { - gArgParser->parse_args(argc, argv); + argParser_->parse_args(argc, argv); } catch (const std::runtime_error& err) { std::cerr << err.what() << "\n"; - std::cerr << *gArgParser << "\n"; + std::cerr << *argParser_ << "\n"; std::exit(1); } - auto logName = gArgParser->get("--log"); + auto logName = argParser_->get("--log"); logging::InitializeLog(serverName_, logName, false); - settings::init(); + settings::init(lua_); + + xirand::seed(); ShowInfo("Begin %s-server Init...", serverName); @@ -72,20 +76,46 @@ Application::Application(std::string const& serverName, int argc, char** argv) ShowInfo("The %s-server is ready to work...", serverName); ShowInfo("======================================================================="); +} - // clang-format off - gConsoleService = std::make_unique(); - - gConsoleService->RegisterCommand("exit", "Terminate the program.", - [&](std::vector& inputs) +void Application::run() +{ + ShowInfo("starting io_context"); + + // This busy loop looks nasty, however -- + // https://think-async.com/Asio/asio-1.24.0/doc/asio/reference/io_service.html + // + // If an exception is thrown from a handler, the exception is allowed to propagate through the throwing thread's invocation of + // run(), run_one(), run_for(), run_until(), poll() or poll_one(). No other threads that are calling any of these functions are affected. + // It is then the responsibility of the application to catch the exception. + while (Application::isRunning()) { - fmt::print("> Goodbye!\n"); - m_RequestExit = true; - }); - // clang-format on + try + { + // NOTE: io_context.run() takes over and blocks this thread. Anything after this point will only fire + // if io_context finishes! + ioContext_.run(); + break; + } + catch (std::exception& e) + { + // TODO: make a list of "allowed exceptions", the rest can/should cause shutdown. + ShowError(fmt::format("Inner fatal: {}", e.what())); + } + } } bool Application::isRunning() { return !requestExit_; } + +auto Application::lua() -> sol::state_view +{ + return lua_; +} + +auto Application::ioContext() -> asio::io_context& +{ + return ioContext_; +} diff --git a/src/common/application.h b/src/common/application.h index 51b9224d756..2e17433d1e7 100644 --- a/src/common/application.h +++ b/src/common/application.h @@ -43,16 +43,19 @@ class Application Application& operator=(Application&&) = delete; void run(); + bool isRunning(); + + auto lua() -> sol::state_view; + auto ioContext() -> asio::io_context&; protected: std::string serverName_; std::atomic requestExit_; - sol::lua_state lua_; + sol::state lua_; asio::io_context ioContext_; std::unique_ptr argParser_; std::unique_ptr consoleService_; - }; diff --git a/src/common/cbasetypes.h b/src/common/cbasetypes.h index f92451ff7af..27cbfa9ee67 100644 --- a/src/common/cbasetypes.h +++ b/src/common/cbasetypes.h @@ -49,6 +49,12 @@ inline void destroy_arr(T*& ptr) ptr = nullptr; } +template +T& ref(U* buf, std::size_t index) +{ + return *reinterpret_cast(reinterpret_cast(buf) + index); +} + #include using namespace std::literals::chrono_literals; diff --git a/src/common/console_service.cpp b/src/common/console_service.cpp index 860f4478b69..f37a5a9c68e 100644 --- a/src/common/console_service.cpp +++ b/src/common/console_service.cpp @@ -22,7 +22,6 @@ #include "console_service.h" #include "database.h" -#include "lua.h" #include @@ -131,18 +130,17 @@ ConsoleService::ConsoleService() } }); - RegisterCommand("lua", "Provides a Lua REPL", - [](std::vector& inputs) - { - if (inputs.size() >= 2) - { - // Remove "lua" from the front of the inputs - inputs = std::vector(inputs.begin() + 1, inputs.end()); - - auto input = fmt::format("local var = {}; if type(var) ~= \"nil\" then print(var) end", fmt::join(inputs, " ")); - lua.safe_script(input); - } - }); + // RegisterCommand("lua", "Provides a Lua REPL", + // [](std::vector& inputs) + // { + // if (inputs.size() >= 2) + // { + // // Remove "lua" from the front of the inputs + // inputs = std::vector(inputs.begin() + 1, inputs.end()); + // auto input = fmt::format("local var = {}; if type(var) ~= \"nil\" then print(var) end", fmt::join(inputs, " ")); + // lua.safe_script(input); + // } + // }); RegisterCommand("crash", "Crash the process", [](std::vector& inputs) diff --git a/src/common/lua.cpp b/src/common/lua.cpp index cef5b8ac91b..273e1fb9ed2 100644 --- a/src/common/lua.cpp +++ b/src/common/lua.cpp @@ -30,10 +30,12 @@ /** * @brief Load the bare minimum required to use Lua. */ -auto lua_init() -> sol::state lua +auto lua_init() -> sol::state { TracyZoneScoped; + sol::state lua; + lua.open_libraries(); // Globally require bit library @@ -64,6 +66,8 @@ auto lua_init() -> sol::state lua result.get()["start"]; ShowInfo("Started script debugger"); } + + return lua; } /** @@ -137,11 +141,11 @@ std::string lua_to_string_depth(sol::state_view lua, const sol::object& obj, std { if (keyObj.get_type() == sol::type::string) { - stringVec.emplace_back(fmt::format("{}{}: {}", indent, lua_to_string_depth(keyObj, 0), lua_to_string_depth(valObj, depth + 1))); + stringVec.emplace_back(fmt::format("{}{}: {}", indent, lua_to_string_depth(lua, keyObj, 0), lua_to_string_depth(lua, valObj, depth + 1))); } else { - stringVec.emplace_back(fmt::format("{}{}", indent, lua_to_string_depth(valObj, depth + 1))); + stringVec.emplace_back(fmt::format("{}{}", indent, lua_to_string_depth(lua, valObj, depth + 1))); } } @@ -167,7 +171,7 @@ std::string lua_to_string_depth(sol::state_view lua, const sol::object& obj, std /** * @brief */ -std::string lua_to_string(sol::variadic_args va) +std::string lua_to_string(sol::state_view lua, sol::variadic_args va) { TracyZoneScoped; @@ -184,7 +188,7 @@ std::string lua_to_string(sol::variadic_args va) } else { - vec.emplace_back(lua_to_string_depth(va[i], 0)); + vec.emplace_back(lua_to_string_depth(lua, va[i], 0)); } } @@ -194,14 +198,14 @@ std::string lua_to_string(sol::variadic_args va) /** * @brief */ -void lua_print(sol::variadic_args va) +void lua_print(sol::state_view lua, sol::variadic_args va) { TracyZoneScoped; - ShowLua(lua_to_string(va).c_str()); + ShowLua(lua_to_string(lua, va).c_str()); } -std::string lua_fmt(const std::string& fmtStr, sol::variadic_args va) +std::string lua_fmt(sol::state_view lua, const std::string& fmtStr, sol::variadic_args va) { fmt::dynamic_format_arg_store store; for (auto const& arg : va) @@ -232,7 +236,7 @@ std::string lua_fmt(const std::string& fmtStr, sol::variadic_args va) } default: { - store.push_back(lua_to_string_depth(arg, 0)); + store.push_back(lua_to_string_depth(lua, arg, 0)); break; } } diff --git a/src/common/lua.h b/src/common/lua.h index 26bda198868..d3cab2c60aa 100644 --- a/src/common/lua.h +++ b/src/common/lua.h @@ -27,8 +27,8 @@ auto lua_init() -> sol::state; auto lua_to_string_depth(sol::state_view lua, const sol::object& obj, std::size_t depth) -> std::string; -auto lua_to_string(sol::variadic_args va) -> std::string; -void lua_print(sol::variadic_args va); -auto lua_fmt(const std::string& fmtStr, sol::variadic_args va) -> std::string; +auto lua_to_string(sol::state_view lua, sol::variadic_args va) -> std::string; +void lua_print(sol::state_view lua, sol::variadic_args va); +auto lua_fmt(sol::state_view lua, const std::string& fmtStr, sol::variadic_args va) -> std::string; #endif // _LUA_H diff --git a/src/common/settings.cpp b/src/common/settings.cpp index dd21e8da128..3de89f05b0e 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -36,6 +36,11 @@ namespace settings namespace detail { std::unordered_map settingsMap; + + auto getSettingsMap() -> std::unordered_map& + { + return settingsMap; + } } // We need this to figure out which environment variables are numbers diff --git a/src/common/settings.h b/src/common/settings.h index 1566652ac7f..ca99009cba3 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -83,7 +83,7 @@ namespace settings // arg = type held inside the variant std::visit( - overloaded{ + detail::overloaded{ [&](bool const& arg) { if constexpr (std::is_same_v) diff --git a/src/common/sql.cpp b/src/common/sql.cpp index 8fb3b1fc5d0..56ec7eff4ea 100644 --- a/src/common/sql.cpp +++ b/src/common/sql.cpp @@ -360,7 +360,7 @@ int32 SqlConnection::QueryStr(const char* query) auto endTime = hires_clock::now(); auto dTime = std::chrono::duration_cast(endTime - startTime); - if (gProcessLoaded && settings::get("logging.SQL_SLOW_QUERY_LOG_ENABLE")) + if (settings::get("logging.SQL_SLOW_QUERY_LOG_ENABLE")) { if (dTime > std::chrono::milliseconds(settings::get("logging.SQL_SLOW_QUERY_ERROR_TIME"))) { diff --git a/src/login/auth_session.cpp b/src/login/auth_session.cpp index 0b78e233767..92c8589ee73 100644 --- a/src/login/auth_session.cpp +++ b/src/login/auth_session.cpp @@ -21,7 +21,6 @@ #include "auth_session.h" -#include "common/socket.h" // for ref #include "common/utils.h" #include @@ -70,7 +69,7 @@ void auth_session::start() void auth_session::do_read() { // clang-format off - socket_.async_read_some(asio::buffer(data_, max_length), + socket_.async_read_some(asio::buffer(buffer_.data(), buffer_.size()), [this, self = shared_from_this()](std::error_code ec, std::size_t length) { if (!ec) @@ -88,11 +87,11 @@ void auth_session::do_read() void auth_session::read_func() { - const auto newModeFlag = ref(data_, 0) == 0xFF; + const auto newModeFlag = ref(buffer_.data(), 0) == 0xFF; if (!newModeFlag) { ShowDebug("Old xiloader connected. Not supported."); - ref(data_, 0) = LOGIN_ERROR; + ref(buffer_.data(), 0) = LOGIN_ERROR; do_write(1); return; } @@ -102,10 +101,11 @@ void auth_session::read_func() char usernameBuffer[17] = {}; char passwordBuffer[33] = {}; - std::memcpy(usernameBuffer, data_ + 0x09, 16); - std::memcpy(passwordBuffer, data_ + 0x19, 32); + std::memcpy(usernameBuffer, buffer_.data() + 0x09, 16); + std::memcpy(passwordBuffer, buffer_.data() + 0x19, 32); + // 1 byte of command at 0x39 - const std::string version(data_ + 0x61, 5); + const std::string version(reinterpret_cast(buffer_.data() + 0x61), 5); std::string username{ usernameBuffer }; std::string password{ passwordBuffer }; @@ -116,13 +116,13 @@ void auth_session::read_func() // Major and minor version changes should be breaking, patch should not. if (strncmp(version.c_str(), SUPPORTED_XILOADER_VERSION, 3) != 0) { - ref(data_, 0) = LOGIN_ERROR_VERSION_UNSUPPORTED; + ref(buffer_.data(), 0) = LOGIN_ERROR_VERSION_UNSUPPORTED; do_write(1); return; } - const int8 code = ref(data_, 0x39); + const int8 code = ref(buffer_.data(), 0x39); DebugSockets(fmt::format("auth code: {} from {}", code, ipAddress)); @@ -170,7 +170,7 @@ void auth_session::read_func() // It's a BCrypt hash, so we can validate it. if (!BCrypt::validatePassword(password, passHash)) { - ref(data_, 0) = LOGIN_ERROR; + ref(buffer_.data(), 0) = LOGIN_ERROR; do_write(1); return; } @@ -185,7 +185,7 @@ void auth_session::read_func() { if (rset->get(passColumn) != passHash) { - ref(data_, 0) = LOGIN_ERROR; + ref(buffer_.data(), 0) = LOGIN_ERROR; do_write(1); return; } @@ -195,7 +195,7 @@ void auth_session::read_func() db::preparedStmt("UPDATE accounts SET accounts.password = ? WHERE accounts.login = ?", passHash, username); if (!BCrypt::validatePassword(password, passHash)) { - ref(data_, 0) = LOGIN_ERROR; + ref(buffer_.data(), 0) = LOGIN_ERROR; do_write(1); return; } @@ -271,14 +271,14 @@ void auth_session::read_func() }*/ // Success - std::memset(data_, 0, 49); - ref(data_, 0) = LOGIN_SUCCESS; - ref(data_, 1) = accountID; + std::memset(buffer_.data(), 0, 49); + ref(buffer_.data(), 0) = LOGIN_SUCCESS; + ref(buffer_.data(), 1) = accountID; unsigned char hash[16]; uint32 hashData = std::time(nullptr) ^ getpid(); md5(reinterpret_cast(&hashData), hash, sizeof(hashData)); - std::memcpy(data_ + 5, hash, 16); + std::memcpy(buffer_.data() + 5, hash, 16); do_write(21); @@ -288,13 +288,13 @@ void auth_session::read_func() } else if (status & ACCOUNT_STATUS_CODE::BANNED) { - ref(data_, 0) = LOGIN_FAIL; + ref(buffer_.data(), 0) = LOGIN_FAIL; do_write(33); } } else // No account match { - ref(data_, 0) = LOGIN_ERROR; + ref(buffer_.data(), 0) = LOGIN_ERROR; do_write(1); } } @@ -308,7 +308,7 @@ void auth_session::read_func() { ShowWarningFmt("login_parse: New account attempt <{}> but is disabled in settings.", username); - ref(data_, 0) = LOGIN_ERROR_CREATE_DISABLED; + ref(buffer_.data(), 0) = LOGIN_ERROR_CREATE_DISABLED; do_write(1); return; } @@ -317,7 +317,7 @@ void auth_session::read_func() const auto rset = db::preparedStmt("SELECT accounts.id FROM accounts WHERE accounts.login = ?", username); if (!rset) { - ref(data_, 0) = LOGIN_ERROR_CREATE; + ref(buffer_.data(), 0) = LOGIN_ERROR_CREATE; do_write(1); return; } @@ -334,7 +334,7 @@ void auth_session::read_func() } else { - ref(data_, 0) = LOGIN_ERROR_CREATE; + ref(buffer_.data(), 0) = LOGIN_ERROR_CREATE; do_write(1); return; } @@ -356,18 +356,18 @@ void auth_session::read_func() accid, username, BCrypt::generateHash(password), strtimecreate, static_cast(ACCOUNT_STATUS_CODE::NORMAL), static_cast(ACCOUNT_PRIVILEGE_CODE::USER)); if (!rset2) { - ref(data_, 0) = LOGIN_ERROR_CREATE; + ref(buffer_.data(), 0) = LOGIN_ERROR_CREATE; do_write(1); return; } - ref(data_, 0) = LOGIN_SUCCESS_CREATE; + ref(buffer_.data(), 0) = LOGIN_SUCCESS_CREATE; do_write(1); return; } else { - ref(data_, 0) = LOGIN_ERROR_CREATE_TAKEN; + ref(buffer_.data(), 0) = LOGIN_ERROR_CREATE_TAKEN; do_write(1); return; } @@ -393,7 +393,7 @@ void auth_session::read_func() // It's a BCrypt hash, so we can validate it. if (!BCrypt::validatePassword(password, passHash)) { - ref(data_, 0) = LOGIN_ERROR_CHANGE_PASSWORD; + ref(buffer_.data(), 0) = LOGIN_ERROR_CHANGE_PASSWORD; do_write(1); return; } @@ -407,7 +407,7 @@ void auth_session::read_func() { if (rset->get(0) != passHash) { - ref(data_, 0) = LOGIN_ERROR_CHANGE_PASSWORD; + ref(buffer_.data(), 0) = LOGIN_ERROR_CHANGE_PASSWORD; do_write(1); return; } @@ -417,7 +417,7 @@ void auth_session::read_func() db::preparedStmt("UPDATE accounts SET accounts.password = ? WHERE accounts.login = ?", passHash.c_str(), username); if (!BCrypt::validatePassword(password, passHash)) { - ref(data_, 0) = LOGIN_ERROR_CHANGE_PASSWORD; + ref(buffer_.data(), 0) = LOGIN_ERROR_CHANGE_PASSWORD; do_write(1); return; } @@ -432,7 +432,7 @@ void auth_session::read_func() if (rset == nullptr || rset->rowsCount() == 0) { ShowWarningFmt("login_parse: user <{}> could not be found using the provided information. Aborting.", username); - ref(data_, 0) = LOGIN_ERROR; + ref(buffer_.data(), 0) = LOGIN_ERROR; do_write(1); return; } @@ -445,19 +445,19 @@ void auth_session::read_func() if (status & ACCOUNT_STATUS_CODE::BANNED) { ShowInfoFmt("login_parse: banned user <{}> detected. Aborting.", username); - ref(data_, 0) = LOGIN_ERROR_CHANGE_PASSWORD; + ref(buffer_.data(), 0) = LOGIN_ERROR_CHANGE_PASSWORD; do_write(1); } if (status & ACCOUNT_STATUS_CODE::NORMAL) { // Account info verified, grab password - std::string updated_password(data_ + 0x40, 32); + std::string updated_password(reinterpret_cast(buffer_.data() + 0x40), 32); if (updated_password == "") { ShowWarningFmt("login_parse: Empty password: Could not update password for user <{}>.", username); - ref(data_, 0) = LOGIN_ERROR_CHANGE_PASSWORD; + ref(buffer_.data(), 0) = LOGIN_ERROR_CHANGE_PASSWORD; do_write(1); return; } @@ -471,13 +471,13 @@ void auth_session::read_func() if (!rset2) { ShowWarningFmt("login_parse: Error trying to update password in database for user <{}>.", username); - ref(data_, 0) = LOGIN_ERROR_CHANGE_PASSWORD; + ref(buffer_.data(), 0) = LOGIN_ERROR_CHANGE_PASSWORD; do_write(1); return; } - memset(data_, 0, 33); - ref(data_, 0) = LOGIN_SUCCESS_CHANGE_PASSWORD; + std::memset(buffer_.data(), 0, 33); + ref(buffer_.data(), 0) = LOGIN_SUCCESS_CHANGE_PASSWORD; do_write(33); ShowInfoFmt("login_parse: password updated for account {} successfully.", accid); @@ -496,7 +496,7 @@ void auth_session::read_func() void auth_session::do_write(std::size_t length) { // clang-format off - asio::async_write(socket_, asio::buffer(data_, length), + asio::async_write(socket_, asio::buffer(buffer_.data(), length), [this, self = shared_from_this()](std::error_code ec, std::size_t /*length*/) { if (!ec) diff --git a/src/login/auth_session.h b/src/login/auth_session.h index e6c55f1460d..aedc7abb0fa 100644 --- a/src/login/auth_session.h +++ b/src/login/auth_session.h @@ -94,8 +94,8 @@ DECLARE_FORMAT_AS_UNDERLYING(ACCOUNT_PRIVILEGE_CODE); class auth_session : public handler_session { public: - auth_session(asio::ssl::stream socket) - : handler_session(std::move(socket)) + auth_session(Application& application, asio::ssl::stream socket) + : handler_session(application, std::move(socket)) { DebugSockets(fmt::format("auth_session from {}", ipAddress)); } diff --git a/src/login/connect_server.cpp b/src/login/connect_server.cpp index 741f127328e..1fa153e72a4 100644 --- a/src/login/connect_server.cpp +++ b/src/login/connect_server.cpp @@ -24,29 +24,6 @@ ConnectServer::ConnectServer(int argc, char** argv) : Application("connect", argc, argv) { - // clang-format off - gConsoleService->RegisterCommand("stats", "Print server runtime statistics", - [](std::vector& inputs) - { - size_t uniqueIPs = loginHelpers::getAuthenticatedSessions().size(); - size_t uniqueAccounts = 0; - - for (auto& ipAddrMap: loginHelpers::getAuthenticatedSessions()) - { - uniqueAccounts += loginHelpers::getAuthenticatedSessions()[ipAddrMap.first].size(); - } - ShowInfo("Serving %u IP addresses with %u accounts\n", uniqueIPs, uniqueAccounts); - }); - - gConsoleService->RegisterCommand("exit", "Safely close the login server", - [&](std::vector& inputs) - { - m_RequestExit = true; - io_context.stop(); - gConsoleService->stop(); - }); - // clang-format on - #ifndef _WIN32 rlimit limits{}; @@ -63,52 +40,19 @@ ConnectServer::ConnectServer(int argc, char** argv) } } #endif - xirand::seed(); - - try - { - // Generate a self signed cert if one doesn't exist. - certificateHelpers::generateSelfSignedCert(); - - ShowInfo("creating ports"); - // Handler creates session of type T for specific port on connection. - handler auth(io_context, settings::get("network.LOGIN_AUTH_PORT")); - handler view(io_context, settings::get("network.LOGIN_VIEW_PORT")); - handler data(io_context, settings::get("network.LOGIN_DATA_PORT")); - asio::steady_timer cleanup_callback(io_context, std::chrono::minutes(15)); + // Generate a self signed cert if one doesn't exist. + certificateHelpers::generateSelfSignedCert(); - cleanup_callback.async_wait(std::bind(&ConnectServer::periodicCleanup, this, std::placeholders::_1, &cleanup_callback)); + ShowInfo("creating ports"); - // NOTE: io_context.run() takes over and blocks this thread. Anything after this point will only fire - // if io_context finishes! - ShowInfo("starting io_context"); + // Handler creates session of type T for specific port on connection. + handler auth(*this, ioContext_, settings::get("network.LOGIN_AUTH_PORT")); + handler view(*this, ioContext_, settings::get("network.LOGIN_VIEW_PORT")); + handler data(*this, ioContext_, settings::get("network.LOGIN_DATA_PORT")); - // This busy loop looks nasty, however -- - // https://think-async.com/Asio/asio-1.24.0/doc/asio/reference/io_service.html - /* If an exception is thrown from a handler, the exception is allowed to propagate through the throwing thread's invocation of - run(), run_one(), run_for(), run_until(), poll() or poll_one(). No other threads that are calling any of these functions are affected. - It is then the responsibility of the application to catch the exception. - */ - - while (Application::IsRunning()) - { - try - { - io_context.run(); - break; - } - catch (std::exception& e) - { - // TODO: make a list of "allowed exceptions", the rest can/should cause shutdown. - ShowError(fmt::format("Inner fatal: {}", e.what())); - } - } - } - catch (std::exception& e) - { - ShowError(fmt::format("Outer fatal: {}", e.what())); - } + // asio::steady_timer cleanup_callback(ioContext_, std::chrono::minutes(15)); + // cleanup_callback.async_wait(std::bind(&ConnectServer::periodicCleanup, this, std::placeholders::_1, &cleanup_callback)); } void ConnectServer::periodicCleanup(const asio::error_code& error, asio::steady_timer* timer) @@ -148,7 +92,7 @@ void ConnectServer::periodicCleanup(const asio::error_code& error, asio::steady_ } } - if (Application::IsRunning()) + if (Application::isRunning()) { // reset timer timer->expires_at(timer->expiry() + std::chrono::minutes(15)); diff --git a/src/login/connect_server.h b/src/login/connect_server.h index 3939726f019..87deef2bac3 100644 --- a/src/login/connect_server.h +++ b/src/login/connect_server.h @@ -68,19 +68,6 @@ class ConnectServer final : public Application public: ConnectServer(int argc, char** argv); - ~ConnectServer() override - { - // Everything should be handled with RAII - } - - // TODO: Currently never called. Need io_context asio::steady_timer callback with taskmgr to control timing? - void Tick() override - { - Application::Tick(); - - // Connect Server specific things - } - // This cleanup function is to periodically poll for auth sessions that were successful but xiloader failed to actually launch FFXI // When this happens, the data/view socket are never opened and will never be cleaned up normally. // Auth is closed before any other sessions are open, so the data/view cleanups aren't sufficient diff --git a/src/login/data_session.cpp b/src/login/data_session.cpp index a8b4c1b67ab..d412d3512ae 100644 --- a/src/login/data_session.cpp +++ b/src/login/data_session.cpp @@ -25,7 +25,7 @@ void data_session::read_func() { - std::string sessionHash = loginHelpers::getHashFromPacket(ipAddress, data_); + std::string sessionHash = loginHelpers::getHashFromPacket(ipAddress, buffer_.data()); if (sessionHash == "") { @@ -41,11 +41,11 @@ void data_session::read_func() session_t& session = loginHelpers::get_authenticated_session(ipAddress, sessionHash); if (!session.data_session) { - session.data_session = std::make_shared(std::forward>(socket_)); + session.data_session = std::make_shared(application_, std::forward>(socket_)); session.data_session->sessionHash = sessionHash; } - uint8 code = ref(data_, 0); + uint8 code = ref(buffer_.data(), 0); DebugSockets(fmt::format("data code: {} from {}", code, ipAddress)); switch (code) @@ -53,11 +53,11 @@ void data_session::read_func() case 0xA1: // 161 { auto maintMode = settings::get("login.MAINT_MODE"); - uint32 recievedAcccountID = ref(data_, 1); + uint32 recievedAcccountID = ref(buffer_.data(), 1); if (session.accountID == recievedAcccountID) { - session.serverIP = ref(data_, 5); + session.serverIP = ref(buffer_.data(), 5); uint32 numContentIds = 0; @@ -195,27 +195,27 @@ void data_session::read_func() // from logging in or creating new characters if (maintMode > 0 && i == 0) { - if (auto data = session.view_session.get()) + if (auto viewSession = session.view_session.get()) { - loginHelpers::generateErrorMessage(data->data_, loginErrors::errorCode::COULD_NOT_CONNECT_TO_LOBBY_SERVER); - data->do_write(0x24); + loginHelpers::generateErrorMessage(viewSession->buffer_.data(), loginErrors::errorCode::COULD_NOT_CONNECT_TO_LOBBY_SERVER); + viewSession->do_write(0x24); } ShowWarning(fmt::format("char:({}) attmpted login during maintenance mode (0xA2). Sending error to client.", session.accountID)); return; } - if (auto data = session.data_session.get()) + if (auto dataSession = session.data_session.get()) { uList[0] = 0x03; // Send character list command in xiloader uList[1] = characterInfoResponse.characters; // xiloader interprets this as the number of characters in the list - std::memset(data->data_, 0, sizeof(data_)); - std::memcpy(data->data_, uList, 0x148); + std::memset(dataSession->buffer_.data(), 0, sizeof(buffer_.data())); + std::memcpy(dataSession->buffer_.data(), uList, 0x148); - data->do_write(0x148); + dataSession->do_write(0x148); } - if (auto data = session.view_session.get()) + if (auto viewSession = session.view_session.get()) { // size of packet + 1 uint32 + the actually set number of characters uint32_t size = sizeof(packet_t) + sizeof(uint32_t) + sizeof(lpkt_chr_info_sub2) * characterInfoResponse.characters; @@ -226,9 +226,9 @@ void data_session::read_func() loginPackets::copyHashIntoPacket(characterInfoResponse, hash); - std::memset(data->data_, 0, sizeof(data_)); - std::memcpy(data->data_, &characterInfoResponse, size); - data->do_write(size); + std::memset(viewSession->buffer_.data(), 0, sizeof(buffer_.data())); + std::memcpy(viewSession->buffer_.data(), &characterInfoResponse, size); + viewSession->do_write(size); } } } @@ -237,7 +237,7 @@ void data_session::read_func() { // Some kind of magic regarding the blowfish keys uint8 key3[20] = {}; - std::memcpy(key3, data_ + 1, sizeof(key3)); + std::memcpy(key3, buffer_.data() + 1, sizeof(key3)); // https://github.com/atom0s/XiPackets/blob/main/lobby/S2C_0x000B_ResponseNextLogin.md lpkt_next_login characterSelectionResponse = {}; @@ -251,7 +251,7 @@ void data_session::read_func() { ShowWarning(fmt::format("data_session: login data corrupt (0xA2). Disconnecting client {}", ipAddress)); - loginHelpers::generateErrorMessage(data_, loginErrors::errorCode::COULD_NOT_CONNECT_TO_LOBBY_SERVER); + loginHelpers::generateErrorMessage(buffer_.data(), loginErrors::errorCode::COULD_NOT_CONNECT_TO_LOBBY_SERVER); do_write(0x24); socket_.lowest_layer().close(); return; @@ -362,11 +362,11 @@ void data_session::read_func() if (hasActiveSession) { ShowWarning(fmt::format("data_session: account {} is already logged in.", session.accountID)); - if (auto data = session.view_session.get()) + if (auto viewSession = session.view_session.get()) { // Send error message to the client. - loginHelpers::generateErrorMessage(data->data_, loginErrors::errorCode::UNABLE_TO_CONNECT_TO_WORLD_SERVER); // "Unable to connect to world server. Specified operation failed" - data->do_write(0x24); + loginHelpers::generateErrorMessage(viewSession->buffer_.data(), loginErrors::errorCode::UNABLE_TO_CONNECT_TO_WORLD_SERVER); // "Unable to connect to world server. Specified operation failed" + viewSession->do_write(0x24); return; } @@ -394,11 +394,11 @@ void data_session::read_func() session.accountID, charid, session_key, ZoneIP, ZonePort, accountIP, session.versionMismatch ? 1 : 0)) { - if (auto data = session.view_session.get()) + if (auto viewSession = session.view_session.get()) { // Send error message to the client. - loginHelpers::generateErrorMessage(data->data_, loginErrors::errorCode::UNABLE_TO_CONNECT_TO_WORLD_SERVER); // "Unable to connect to world server. Specified operation failed" - data->do_write(0x24); + loginHelpers::generateErrorMessage(viewSession->buffer_.data(), loginErrors::errorCode::UNABLE_TO_CONNECT_TO_WORLD_SERVER); // "Unable to connect to world server. Specified operation failed" + viewSession->do_write(0x24); return; } } @@ -408,22 +408,22 @@ void data_session::read_func() } else { - if (auto data = session.view_session.get()) + if (auto viewSession = session.view_session.get()) { // Send error message to the client. - loginHelpers::generateErrorMessage(data->data_, loginErrors::errorCode::COULD_NOT_CONNECT_TO_LOBBY_SERVER); - data->do_write(0x24); + loginHelpers::generateErrorMessage(viewSession->buffer_.data(), loginErrors::errorCode::COULD_NOT_CONNECT_TO_LOBBY_SERVER); + viewSession->do_write(0x24); return; } } } else { - if (auto data = session.view_session.get()) + if (auto viewSession = session.view_session.get()) { // Send error message to the client. - loginHelpers::generateErrorMessage(data->data_, loginErrors::errorCode::UNABLE_TO_CONNECT_TO_WORLD_SERVER); // "Unable to connect to world server. Specified operation failed" - data->do_write(0x24); + loginHelpers::generateErrorMessage(viewSession->buffer_.data(), loginErrors::errorCode::UNABLE_TO_CONNECT_TO_WORLD_SERVER); // "Unable to connect to world server. Specified operation failed" + viewSession->do_write(0x24); return; } } @@ -433,13 +433,13 @@ void data_session::read_func() loginPackets::copyHashIntoPacket(characterSelectionResponse, Hash); - if (auto data = session.view_session.get()) + if (auto viewSession = session.view_session.get()) { - std::memcpy(data->data_, &characterSelectionResponse, sizeof(characterSelectionResponse)); - data->do_write(sizeof(characterSelectionResponse)); + std::memcpy(viewSession->buffer_.data(), &characterSelectionResponse, sizeof(characterSelectionResponse)); + viewSession->do_write(sizeof(characterSelectionResponse)); - data->socket_.lowest_layer().shutdown(asio::socket_base::shutdown_both); // Client waits for us to close the socket - data->socket_.lowest_layer().close(); + viewSession->socket_.lowest_layer().shutdown(asio::socket_base::shutdown_both); // Client waits for us to close the socket + viewSession->socket_.lowest_layer().close(); session.view_session = nullptr; } @@ -469,9 +469,9 @@ void data_session::read_func() case 0xFE: // 254 { // Reply with nothing to keep xiloader spinning, may not be needed. - if (auto data = session.data_session.get()) + if (auto dataSession = session.data_session.get()) { - data->do_write(0); + dataSession->do_write(0); } } break; diff --git a/src/login/data_session.h b/src/login/data_session.h index bdbf34937c0..265f76d56e7 100644 --- a/src/login/data_session.h +++ b/src/login/data_session.h @@ -33,8 +33,8 @@ class data_session : public handler_session { public: - data_session(asio::ssl::stream socket) - : handler_session(std::move(socket)) + data_session(Application& application, asio::ssl::stream socket) + : handler_session(application, std::move(socket)) { DebugSockets("data_session from IP %s", ipAddress); } diff --git a/src/login/handler.h b/src/login/handler.h index 0dfe529f531..b663ede4d68 100644 --- a/src/login/handler.h +++ b/src/login/handler.h @@ -33,8 +33,9 @@ template class handler { public: - handler(asio::io_context& io_context, unsigned int port) - : acceptor_(io_context, asio::ip::tcp::endpoint(asio::ip::tcp::v4(), port)) + handler(Application& application, asio::io_context& io_context, unsigned int port) + : application_(application) + , acceptor_(io_context, asio::ip::tcp::endpoint(asio::ip::tcp::v4(), port)) , sslContext_(asio::ssl::context::tls_server) { acceptor_.set_option(asio::socket_base::reuse_address(true)); @@ -52,23 +53,23 @@ class handler { // clang-format off acceptor_.async_accept( - [this](std::error_code ec, asio::ip::tcp::socket socket) + [this, &application = application_](std::error_code ec, asio::ip::tcp::socket socket) { if (!ec) { if constexpr (std::is_same_v) { - auto auth_handler = std::make_shared(asio::ssl::stream(std::move(socket), sslContext_)); + auto auth_handler = std::make_shared(application, asio::ssl::stream(std::move(socket), sslContext_)); auth_handler->start(); } else if constexpr (std::is_same_v) { - auto view_handler = std::make_shared(asio::ssl::stream(std::move(socket), sslContext_)); + auto view_handler = std::make_shared(application, asio::ssl::stream(std::move(socket), sslContext_)); view_handler->start(); } else if constexpr (std::is_same_v) { - auto data_handler = std::make_shared(asio::ssl::stream(std::move(socket), sslContext_)); + auto data_handler = std::make_shared(application, asio::ssl::stream(std::move(socket), sslContext_)); data_handler->start(); } } @@ -82,6 +83,7 @@ class handler // clang-format on } + Application& application_; asio::ip::tcp::acceptor acceptor_; asio::ssl::context sslContext_; }; diff --git a/src/login/handler_session.cpp b/src/login/handler_session.cpp index 294c7b8c763..7114ffebfc5 100644 --- a/src/login/handler_session.cpp +++ b/src/login/handler_session.cpp @@ -21,8 +21,9 @@ #include "handler_session.h" -handler_session::handler_session(asio::ssl::stream socket) +handler_session::handler_session(Application& application, asio::ssl::stream socket) : socket_(std::move(socket)) +, application_(application) { asio::error_code ec = {}; socket_.lowest_layer().set_option(asio::socket_base::reuse_address(true)); @@ -58,7 +59,7 @@ void handler_session::start() void handler_session::do_read() { // clang-format off - socket_.next_layer().async_read_some(asio::buffer(data_, max_length), + socket_.next_layer().async_read_some(asio::buffer(buffer_.data(), buffer_.size()), [this, self = shared_from_this()](std::error_code ec, std::size_t length) { if (!ec) @@ -77,7 +78,7 @@ void handler_session::do_read() void handler_session::do_write(std::size_t length) { // clang-format off - asio::async_write(socket_.next_layer(), asio::buffer(data_, length), + asio::async_write(socket_.next_layer(), asio::buffer(buffer_.data(), buffer_.size()), [this, self = shared_from_this()](std::error_code ec, std::size_t /*length*/) { if (!ec) diff --git a/src/login/handler_session.h b/src/login/handler_session.h index 5778ff95608..081f2c7d962 100644 --- a/src/login/handler_session.h +++ b/src/login/handler_session.h @@ -21,27 +21,30 @@ #pragma once +#include "common/application.h" + #include #include #include #include +#include +#include + class handler_session : public std::enable_shared_from_this { public: - handler_session(asio::ssl::stream socket); - + handler_session(Application& application, asio::ssl::stream socket); virtual ~handler_session() = default; void start(); void do_read(); + void do_write(std::size_t length); virtual void handle_error(std::error_code ec, std::shared_ptr self) = 0; - void do_write(std::size_t length); - virtual void read_func() = 0; virtual void write_func() = 0; @@ -50,10 +53,7 @@ class handler_session asio::ssl::stream socket_; - // TODO: Use std::array - enum - { - max_length = 4096 - }; - char data_[max_length] = {}; + std::array buffer_; + + Application& application_; }; diff --git a/src/login/login_helpers.cpp b/src/login/login_helpers.cpp index 51e18680dd6..7ee1e926286 100644 --- a/src/login/login_helpers.cpp +++ b/src/login/login_helpers.cpp @@ -65,7 +65,7 @@ namespace loginHelpers } // https://github.com/atom0s/XiPackets/blob/main/lobby/S2C_0x0004_ResponseError.md - void generateErrorMessage(char* packet, uint16 errorCode) + void generateErrorMessage(uint8* packet, uint16 errorCode) { std::memset(packet, 0, 0x24); @@ -220,7 +220,7 @@ namespace loginHelpers return 0; } - int32 createCharacter(session_t& session, char* buf) + int32 createCharacter(session_t& session, uint8* buf) { char_mini createchar; @@ -290,9 +290,9 @@ namespace loginHelpers return 0; } - std::string getHashFromPacket(std::string const& ip_str, char* data) + std::string getHashFromPacket(std::string const& ip_str, uint8* data) { - std::string hash = std::string(data + 12, 16); + std::string hash = std::string((const char*)data + 12, 16); if (authenticatedSessions_[ip_str].find(hash) == authenticatedSessions_[ip_str].end()) { diff --git a/src/login/login_helpers.h b/src/login/login_helpers.h index 9b5ed035d71..c259cc7dcd9 100644 --- a/src/login/login_helpers.h +++ b/src/login/login_helpers.h @@ -25,7 +25,6 @@ #include #include -#include // for ref #include #include @@ -88,7 +87,7 @@ namespace loginHelpers uint32 str2ip(const char* ip_str); // https://github.com/atom0s/XiPackets/blob/main/lobby/S2C_0x0004_ResponseError.md - void generateErrorMessage(char* packet, uint16 errorCode); + void generateErrorMessage(uint8* packet, uint16 errorCode); uint16 generateExpansionBitmask(); @@ -96,9 +95,9 @@ namespace loginHelpers int32 saveCharacter(uint32 accid, uint32 charid, char_mini* createchar); - int32 createCharacter(session_t& session, char* buf); + int32 createCharacter(session_t& session, uint8* buf); - void PrintPacket(const char* data, uint32 size); + void PrintPacket(uint8* data, uint32 size); - std::string getHashFromPacket(std::string const& ip_str, char* data); + std::string getHashFromPacket(std::string const& ip_str, uint8* data); } // namespace loginHelpers diff --git a/src/login/view_session.cpp b/src/login/view_session.cpp index b7262799ff9..2d0b23deb65 100644 --- a/src/login/view_session.cpp +++ b/src/login/view_session.cpp @@ -29,9 +29,11 @@ void view_session::read_func() { - uint8 code = ref(data_, 8); + auto lua = application_.lua(); - std::string sessionHash = loginHelpers::getHashFromPacket(ipAddress, data_); + uint8 code = ref(buffer_.data(), 8); + + std::string sessionHash = loginHelpers::getHashFromPacket(ipAddress, buffer_.data()); if (sessionHash == "") { @@ -41,7 +43,7 @@ void view_session::read_func() session_t& session = loginHelpers::get_authenticated_session(ipAddress, sessionHash); if (!session.view_session) { - session.view_session = std::make_shared(std::forward>(socket_)); + session.view_session = std::make_shared(application_, std::forward>(socket_)); } session.view_session->sessionHash = sessionHash; @@ -51,9 +53,9 @@ void view_session::read_func() { case 0x07: // 07: "Notifying lobby server of current selections." { - auto requestedCharacterID = ref(data_, 28); + auto requestedCharacterID = ref(buffer_.data(), 28); char requestedCharacter[PacketNameLength] = {}; - std::memcpy(&requestedCharacter, data_ + 36, PacketNameLength - 1); + std::memcpy(&requestedCharacter, buffer_.data() + 36, PacketNameLength - 1); uint32 accountID = 0; @@ -80,8 +82,8 @@ void view_session::read_func() if (auto data = session.data_session) { - std::memset(data->data_, 0, 0x05); - data->data_[0] = 0x02; + std::memset(data->buffer_.data(), 0, 0x05); + data->buffer_.data()[0] = 0x02; data->do_write(0x05); } } @@ -90,29 +92,29 @@ void view_session::read_func() { if (!settings::get("login.CHARACTER_DELETION")) { - loginHelpers::generateErrorMessage(data_, loginErrors::errorCode::COULD_NOT_CONNECT_TO_LOBBY_SERVER); + loginHelpers::generateErrorMessage(buffer_.data(), loginErrors::errorCode::COULD_NOT_CONNECT_TO_LOBBY_SERVER); do_write(0x24); return; } - memset(data_, 0, 0x20); - data_[0] = 0x20; // size + std::memset(buffer_.data(), 0, 0x20); + buffer_.data()[0] = 0x20; // size - data_[4] = 0x49; // I - data_[5] = 0x58; // X - data_[6] = 0x46; // F - data_[7] = 0x46; // F + buffer_.data()[4] = 0x49; // I + buffer_.data()[5] = 0x58; // X + buffer_.data()[6] = 0x46; // F + buffer_.data()[7] = 0x46; // F - data_[8] = 0x03; // result + buffer_.data()[8] = 0x03; // result unsigned char hash[16]; - md5(reinterpret_cast(data_), hash, 0x20); - std::memcpy(data_ + 12, hash, 16); + md5(reinterpret_cast(buffer_.data()), hash, 0x20); + std::memcpy(buffer_.data() + 12, hash, 16); do_write(0x20); - uint32 charID = ref(data_, 0x20); + uint32 charID = ref(buffer_.data(), 0x20); ShowInfo(fmt::format("attempt to delete char:<{}> from ip:<{}>", charID, ipAddress)); @@ -143,7 +145,7 @@ void view_session::read_func() case 0x21: // 33: Registering character name onto the lobby server { // creating new char - if (loginHelpers::createCharacter(session, data_) == -1) + if (loginHelpers::createCharacter(session, buffer_.data()) == -1) { socket_.lowest_layer().close(); return; @@ -152,21 +154,21 @@ void view_session::read_func() session.justCreatedNewChar = true; ShowInfo(fmt::format("char <{}> was successfully created on account {}", session.requestedNewCharacterName, session.accountID)); - memset(data_, 0, 0x20); + std::memset(buffer_.data(), 0, 0x20); - data_[0] = 0x20; // size + buffer_.data()[0] = 0x20; // size - data_[4] = 0x49; // I - data_[5] = 0x58; // X - data_[6] = 0x46; // F - data_[7] = 0x46; // F + buffer_.data()[4] = 0x49; // I + buffer_.data()[5] = 0x58; // X + buffer_.data()[6] = 0x46; // F + buffer_.data()[7] = 0x46; // F - data_[8] = 0x03; // result + buffer_.data()[8] = 0x03; // result unsigned char hash[16]; - md5(reinterpret_cast(data_), hash, 0x20); - std::memcpy(data_ + 12, hash, 16); + md5(buffer_.data(), hash, 0x20); + std::memcpy(buffer_.data() + 12, hash, 16); do_write(0x20); } @@ -174,11 +176,11 @@ void view_session::read_func() case 0x22: // 34: Checking name and Gold World Pass { // block creation of character if in maintenance mode or generally disabled - auto maintMode = settings::get("login.MAINT_MODE"); - auto enableCharacterCreation = settings::get("login.CHARACTER_CREATION"); + const auto maintMode = settings::get("login.MAINT_MODE"); + const auto enableCharacterCreation = settings::get("login.CHARACTER_CREATION"); if (maintMode > 0 || !enableCharacterCreation) { - loginHelpers::generateErrorMessage(data_, loginErrors::errorCode::FAILED_TO_REGISTER_WITH_THE_NAME_SERVER); + loginHelpers::generateErrorMessage(buffer_.data(), loginErrors::errorCode::FAILED_TO_REGISTER_WITH_THE_NAME_SERVER); do_write(0x24); return; } @@ -186,7 +188,7 @@ void view_session::read_func() { // creating new char char CharName[PacketNameLength] = {}; - std::memcpy(CharName, data_ + 32, PacketNameLength - 1); + std::memcpy(CharName, buffer_.data() + 32, PacketNameLength - 1); std::optional invalidNameReason = std::nullopt; @@ -245,6 +247,7 @@ void view_session::read_func() // TODO: Don't raw-access Lua like this outside of Lua helper code. // (optional) Check if the name contains any words on the bad word list + auto loginSettingsTable = lua["xi"]["settings"]["login"].get(); if (auto badWordsList = loginSettingsTable.get_or("BANNED_WORDS_LIST", sol::lua_nil); badWordsList.valid()) { @@ -266,7 +269,7 @@ void view_session::read_func() // Send error code: // The character name you entered is unavailable. Please choose another name. // TODO: This message is displayed in Japanese, needs fixing. - loginHelpers::generateErrorMessage(data_, loginErrors::errorCode::CHARACTER_NAME_UNAVAILABLE); + loginHelpers::generateErrorMessage(buffer_.data(), loginErrors::errorCode::CHARACTER_NAME_UNAVAILABLE); do_write(0x24); return; } @@ -275,20 +278,20 @@ void view_session::read_func() // copy charname session.requestedNewCharacterName = CharName; - memset(data_, 0, 0x20); - data_[0] = 0x20; // size + std::memset(buffer_.data(), 0, 0x20); + buffer_.data()[0] = 0x20; // size - data_[4] = 0x49; // I - data_[5] = 0x58; // X - data_[6] = 0x46; // F - data_[7] = 0x46; // F + buffer_.data()[4] = 0x49; // I + buffer_.data()[5] = 0x58; // X + buffer_.data()[6] = 0x46; // F + buffer_.data()[7] = 0x46; // F - data_[8] = 0x03; // result + buffer_.data()[8] = 0x03; // result unsigned char hash[16]; - md5(reinterpret_cast(data_), hash, 0x20); - std::memcpy(data_ + 12, hash, 16); + md5(buffer_.data(), hash, 0x20); + std::memcpy(buffer_.data() + 12, hash, 16); do_write(0x20); } @@ -297,7 +300,7 @@ void view_session::read_func() break; case 0x26: // 38: Version + Expansions, "Setting up connection." { - std::string client_ver_data((data_ + 0x74), 6); // Full length is 10 but we drop last 4. This contains "E" in the english client. Perhaps this can be used as a hint for language? + std::string client_ver_data(reinterpret_cast(buffer_.data() + 0x74), 6); // Full length is 10 but we drop last 4. This contains "E" in the english client. Perhaps this can be used as a hint for language? client_ver_data = client_ver_data + "xx_x"; // And then we replace those last 4 DebugSockets(fmt::format("Version: {} from {}", client_ver_data, ipAddress)); @@ -340,10 +343,10 @@ void view_session::read_func() if (fatalMismatch) { - if (auto data = session.view_session.get()) + if (auto viewSession = session.view_session.get()) { - loginHelpers::generateErrorMessage(data->data_, loginErrors::errorCode::GAMES_DATA_HAS_BEEN_UPDATED); // "The games data has been updated" - data->do_write(0x24); + loginHelpers::generateErrorMessage(viewSession->buffer_.data(), loginErrors::errorCode::GAMES_DATA_HAS_BEEN_UPDATED); // "The games data has been updated" + viewSession->do_write(0x24); return; } } @@ -368,34 +371,34 @@ void view_session::read_func() ref(packet.data(), 32) = loginHelpers::generateExpansionBitmask(); ref(packet.data(), 36) = loginHelpers::generateFeatureBitmask(); - std::memset(data_, 0, 0x28); - std::memcpy(data_, packet.data(), 0x28); + std::memset(buffer_.data(), 0, 0x28); + std::memcpy(buffer_.data(), packet.data(), 0x28); // Hash the packet data and then write the value of the hash into the packet. unsigned char hash[16]; - md5(reinterpret_cast(data_), hash, 0x28); - std::memcpy(data_ + 12, hash, 16); + md5(buffer_.data(), hash, 0x28); + std::memcpy(buffer_.data() + 12, hash, 16); DebugSockets("view_session: Sending version and expansions info to account %d", session.accountID); - if (auto data = session.view_session.get()) + if (auto dataSession = session.view_session.get()) { - std::memcpy(data->data_, data_, 0x28); - data->do_write(0x28); + std::memcpy(dataSession->buffer_.data(), buffer_.data(), 0x28); + dataSession->do_write(0x28); } } break; case 0x1F: // 31: "Acquiring Player Data" { - if (auto data = session.data_session.get()) + if (auto dataSession = session.data_session.get()) { - std::memset(data->data_, 0, 5); - data->data_[0] = 0x01; - data->do_write(0x05); + std::memset(dataSession->buffer_.data(), 0, 5); + dataSession->buffer_.data()[0] = 0x01; + dataSession->do_write(0x05); } else { - loginHelpers::generateErrorMessage(data_, loginErrors::errorCode::COULD_NOT_CONNECT_TO_LOBBY_SERVER); // "Could not connect to lobby server.\nPlease check this title's news for announcements." + loginHelpers::generateErrorMessage(buffer_.data(), loginErrors::errorCode::COULD_NOT_CONNECT_TO_LOBBY_SERVER); // "Could not connect to lobby server.\nPlease check this title's news for announcements." do_write(0x24); // This used to error, but this case is probably not valid after sessionHash. // TODO: is this this else block still needed? return; } @@ -403,7 +406,7 @@ void view_session::read_func() break; case 0x24: // 36: "Acquiring FINAL FANTASY XI server data" { - std::memset(data_, 0, 0x40); + std::memset(buffer_.data(), 0, 0x40); auto serverName = settings::get("main.SERVER_NAME"); lpkt_world_list worldList = {}; @@ -419,7 +422,7 @@ void view_session::read_func() worldList.world_name[0].no = 0x20; std::memcpy(worldList.world_name[0].name, serverName.c_str(), std::clamp(serverName.length(), 0, 15)); - if (auto data = session.view_session.get()) + if (auto dataSession = session.view_session.get()) { worldList.packet_size = sizeof(packet_t) + sizeof(uint32_t) + sizeof(lpkt_world_name) * worldList.sumofworld; @@ -427,8 +430,8 @@ void view_session::read_func() md5(reinterpret_cast(&worldList), Hash, worldList.packet_size); loginPackets::copyHashIntoPacket(worldList, Hash); - std::memcpy(data->data_, &worldList, worldList.packet_size); - data->do_write(worldList.packet_size); + std::memcpy(dataSession->buffer_.data(), &worldList, worldList.packet_size); + dataSession->do_write(worldList.packet_size); } } break; diff --git a/src/login/view_session.h b/src/login/view_session.h index a71247e7ffb..dfc425a9d97 100644 --- a/src/login/view_session.h +++ b/src/login/view_session.h @@ -38,8 +38,8 @@ class view_session : public handler_session { public: - view_session(asio::ssl::stream socket) - : handler_session(std::move(socket)) + view_session(Application& application, asio::ssl::stream socket) + : handler_session(application, std::move(socket)) { DebugSockets("view_session from IP %s", ipAddress); } diff --git a/src/map/packets/basic.h b/src/map/packets/basic.h index 603db2c149e..11de2d31e1e 100644 --- a/src/map/packets/basic.h +++ b/src/map/packets/basic.h @@ -23,7 +23,6 @@ #define _BASICPACKET_H #include "common/cbasetypes.h" -#include "common/socket.h" #include "common/tracy.h" #include diff --git a/src/search/packets/auction_history.cpp b/src/search/packets/auction_history.cpp index 5ba2560a957..d8f5a0eb97a 100644 --- a/src/search/packets/auction_history.cpp +++ b/src/search/packets/auction_history.cpp @@ -21,7 +21,6 @@ #include #include "common/logging.h" -#include "common/socket.h" #include "data_loader.h" diff --git a/src/search/packets/auction_list.cpp b/src/search/packets/auction_list.cpp index 12095ea5316..3df935545e9 100644 --- a/src/search/packets/auction_list.cpp +++ b/src/search/packets/auction_list.cpp @@ -21,7 +21,6 @@ #include #include "common/logging.h" -#include "common/socket.h" #include "data_loader.h" diff --git a/src/search/packets/linkshell_list.cpp b/src/search/packets/linkshell_list.cpp index dc301f16091..af25fd8f15c 100644 --- a/src/search/packets/linkshell_list.cpp +++ b/src/search/packets/linkshell_list.cpp @@ -20,7 +20,6 @@ */ #include "common/logging.h" -#include "common/socket.h" #include "common/utils.h" #include "data_loader.h" diff --git a/src/search/packets/party_list.cpp b/src/search/packets/party_list.cpp index 0899a9e77eb..6009cd9dea1 100644 --- a/src/search/packets/party_list.cpp +++ b/src/search/packets/party_list.cpp @@ -20,7 +20,6 @@ */ #include "common/logging.h" -#include "common/socket.h" #include "common/utils.h" #include "data_loader.h" diff --git a/src/search/packets/search_comment.cpp b/src/search/packets/search_comment.cpp index ccf4a54f5d7..fdece1a2cb3 100644 --- a/src/search/packets/search_comment.cpp +++ b/src/search/packets/search_comment.cpp @@ -2,37 +2,26 @@ #include "search_comment.h" #include "common/logging.h" -#include "common/socket.h" #include "common/utils.h" SearchCommentPacket::SearchCommentPacket(uint32 playerId, std::string const& comment) { - ref(data, 0x08) = 154; // Search comment packet size - ref(data, 0x0A) = 0x80; // Search server packet - ref(data, 0x0B) = 0x88; // Packet type + ref(buffer_.data(), 0x08) = 154; // Search comment packet size + ref(buffer_.data(), 0x0A) = 0x80; // Search server packet + ref(buffer_.data(), 0x0B) = 0x88; // Packet type - ref(data, 0x0E) = 0x01; + ref(buffer_.data(), 0x0E) = 0x01; - ref(data, 0x18) = playerId; + ref(buffer_.data(), 0x18) = playerId; - ref(data, 0x1C) = 124; // Comment length + ref(buffer_.data(), 0x1C) = 124; // Comment length // Add comment bytes - memcpy(&data[0x1E], comment.c_str(), comment.length()); + std::memcpy(&buffer_.data()[0x1E], comment.c_str(), comment.length()); // Fill rest with whitespace - memset(&data[0x1E + comment.length()], ' ', 123 - comment.length()); + std::memset(&buffer_.data()[0x1E + comment.length()], ' ', 123 - comment.length()); // End comment with 0 byte - data[0x9A] = 0; -} - -uint8* SearchCommentPacket::GetData() -{ - return data; -} - -uint16 SearchCommentPacket::GetSize() -{ - return 204; + buffer_.data()[0x9A] = 0; } diff --git a/src/search/packets/search_comment.h b/src/search/packets/search_comment.h index 7f8dffae613..cb33296f854 100644 --- a/src/search/packets/search_comment.h +++ b/src/search/packets/search_comment.h @@ -3,6 +3,8 @@ #define _SEARCH_COMMENT_PACKET_H_ #include "common/cbasetypes.h" + +#include #include class SearchCommentPacket @@ -10,11 +12,8 @@ class SearchCommentPacket public: SearchCommentPacket(uint32 playerId, std::string const& comment); - uint8* GetData(); - uint16 GetSize(); - private: - uint8 data[204]{}; + std::array buffer_{}; }; #endif diff --git a/src/search/packets/search_list.cpp b/src/search/packets/search_list.cpp index a00bb38791c..f344cb38fc2 100644 --- a/src/search/packets/search_list.cpp +++ b/src/search/packets/search_list.cpp @@ -20,7 +20,6 @@ */ #include "common/logging.h" -#include "common/socket.h" #include "common/utils.h" #include "data_loader.h" diff --git a/src/search/search_handler.cpp b/src/search/search_handler.cpp index d93f6892383..37527d2f5ed 100644 --- a/src/search/search_handler.cpp +++ b/src/search/search_handler.cpp @@ -21,8 +21,7 @@ #include "search_handler.h" #include "common/md52.h" -#include "common/socket.h" // for ref -#include "common/utils.h" // for unpack/pack bits +#include "common/utils.h" // for unpack/pack bits #include "data_loader.h" #include #include diff --git a/src/search/search_handler.h b/src/search/search_handler.h index cc8ea6058fc..76a77fef229 100644 --- a/src/search/search_handler.h +++ b/src/search/search_handler.h @@ -48,28 +48,22 @@ class search_handler { public: search_handler(asio::ip::tcp::socket socket, asio::io_context& io_context, shared_guarded>& IPAddressesInUseList, shared_guarded>& IPAddressWhitelist); - ~search_handler(); void start(); void do_read(); + void do_write(); void handle_error(std::error_code ec, std::shared_ptr self); - void do_write(); - void read_func(uint16_t length); +protected: std::string ipAddress; // Store IP address in class -- once the file handle is invalid this can no longer be obtained from socket_ asio::ip::tcp::socket socket_; - // TODO: Use std::array - enum - { - max_length = 4096 - }; - uint8_t data_[max_length] = {}; + std::array buffer_; // Blowfish key // clang-format off diff --git a/src/search/search_server.cpp b/src/search/search_server.cpp index 8748657deac..f050e95ed34 100644 --- a/src/search/search_server.cpp +++ b/src/search/search_server.cpp @@ -45,9 +45,9 @@ SearchServer::SearchServer(int argc, char** argv) [&](std::vector& inputs) { fmt::print("> Goodbye!"); - m_RequestExit = true; - io_context.stop(); - gConsoleService->stop(); + requestExit_ = true; + ioContext_.stop(); + consoleService_->stop(); }); // clang-format on @@ -67,71 +67,38 @@ SearchServer::SearchServer(int argc, char** argv) } } #endif - xirand::seed(); - try - { - ShowInfo("creating ports"); - - // clang-format off - const auto search_handler_handler = handler(io_context, settings::get("network.SEARCH_PORT"), [&](asio::ip::tcp::socket socket) { - const auto handler = std::make_shared(std::move(socket), io_context, IPAddressesInUse_, IPAddressWhitelist_); - handler->start(); - }); - // clang-format on - - // AH cleanup callback. May not be used if settings doesn't enable it. - asio::steady_timer cleanup_callback(io_context, std::chrono::seconds(settings::get("search.EXPIRE_INTERVAL"))); + ShowInfo("creating ports"); - if (settings::get("search.EXPIRE_AUCTIONS")) - { - ShowInfo("AH task to return items older than %u days is running", settings::get("search.EXPIRE_DAYS")); - - ahCleanup(); - - cleanup_callback.async_wait(std::bind(&SearchServer::periodicCleanup, this, std::placeholders::_1, &cleanup_callback)); - } + // clang-format off + const auto search_handler_handler = handler(io_context, settings::get("network.SEARCH_PORT"), [&](asio::ip::tcp::socket socket) { + const auto handler = std::make_shared(std::move(socket), io_context, IPAddressesInUse_, IPAddressWhitelist_); + handler->start(); + }); + // clang-format on - sol::table accessWhitelist = lua["xi"]["settings"]["search"]["ACCESS_WHITELIST"].get_or_create(); - for (auto const& [_, value] : accessWhitelist) - { - // clang-format off - auto str = value.as(); - IPAddressWhitelist_.write([str](auto& ipWhitelist) - { - ipWhitelist.insert(str); - }); - // clang-format on - } + // AH cleanup callback. May not be used if settings doesn't enable it. + asio::steady_timer cleanup_callback(io_context, std::chrono::seconds(settings::get("search.EXPIRE_INTERVAL"))); - // NOTE: io_context.run() takes over and blocks this thread. Anything after this point will only fire - // if io_context finishes! - ShowInfo("starting io_context"); + if (settings::get("search.EXPIRE_AUCTIONS")) + { + ShowInfo("AH task to return items older than %u days is running", settings::get("search.EXPIRE_DAYS")); - // This busy loop looks nasty, however -- - // https://think-async.com/Asio/asio-1.24.0/doc/asio/reference/io_service.html - /* If an exception is thrown from a handler, the exception is allowed to propagate through the throwing thread's invocation of - run(), run_one(), run_for(), run_until(), poll() or poll_one(). No other threads that are calling any of these functions are affected. - It is then the responsibility of the application to catch the exception. - */ + ahCleanup(); - while (Application::IsRunning()) - { - try - { - io_context.run(); - break; - } - catch (std::exception& e) - { - // TODO: make a list of "allowed exceptions", the rest can/should cause shutdown. - ShowError(fmt::format("Inner fatal: {}", e.what())); - } - } + cleanup_callback.async_wait(std::bind(&SearchServer::periodicCleanup, this, std::placeholders::_1, &cleanup_callback)); } - catch (std::exception& e) + + sol::table accessWhitelist = lua["xi"]["settings"]["search"]["ACCESS_WHITELIST"].get_or_create(); + for (auto const& [_, value] : accessWhitelist) { - ShowError(fmt::format("Outer fatal: {}", e.what())); + // clang-format off + auto str = value.as(); + IPAddressWhitelist_.write([str](auto& ipWhitelist) + { + ipWhitelist.insert(str); + }); + // clang-format on } } @@ -147,7 +114,7 @@ void SearchServer::periodicCleanup(const asio::error_code& error, asio::steady_t { ahCleanup(); - if (Application::IsRunning()) + if (Application::isRunning()) { // reset timer timer->expires_at(timer->expiry() + std::chrono::seconds(settings::get("search.EXPIRE_INTERVAL"))); diff --git a/src/search/search_server.h b/src/search/search_server.h index e567eda1f14..4a6871512b2 100644 --- a/src/search/search_server.h +++ b/src/search/search_server.h @@ -46,22 +46,9 @@ class SearchServer final : public Application public: SearchServer(int argc, char** argv); - ~SearchServer() override - { - // Everything should be handled with RAII - } - void periodicCleanup(const asio::error_code& error, asio::steady_timer* timer); - void ahCleanup(); - // TODO: Currently never called. Need io_context asio::steady_timer callback with taskmgr to control timing? - void Tick() override - { - Application::Tick(); - - // Search Server specific things - } private: // A single IP should only have one request in flight at a time, so we are going to // be tracking the IP addresses of incoming requests and if we haven't cleared the