mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-13 02:11:30 +00:00
[Loginserver] Health Checks (#1665)
* Health checks stash * Healthcheck work
This commit is contained in:
parent
e4138b871b
commit
6e26e8953c
@ -3,6 +3,7 @@
|
|||||||
#include "../common/event/task_scheduler.h"
|
#include "../common/event/task_scheduler.h"
|
||||||
#include "../common/event/event_loop.h"
|
#include "../common/event/event_loop.h"
|
||||||
#include "../common/net/dns.h"
|
#include "../common/net/dns.h"
|
||||||
|
#include "../common/string_util.h"
|
||||||
|
|
||||||
extern LoginServer server;
|
extern LoginServer server;
|
||||||
EQ::Event::TaskScheduler task_runner;
|
EQ::Event::TaskScheduler task_runner;
|
||||||
@ -377,16 +378,22 @@ uint32 AccountManagement::CheckExternalLoginserverUserCredentials(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
EQ::Net::DNSLookup(
|
auto s = SplitString(server.options.GetEQEmuLoginServerAddress(), ':');
|
||||||
"login.eqemulator.net", 5999, false, [&](const std::string &addr) {
|
if (s.size() == 2) {
|
||||||
if (addr.empty()) {
|
auto address = s[0];
|
||||||
ret = 0;
|
auto port = std::stoi(s[1]);
|
||||||
running = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
mgr.Connect(addr, 5999);
|
EQ::Net::DNSLookup(
|
||||||
}
|
address, port, false, [&](const std::string &addr) {
|
||||||
);
|
if (addr.empty()) {
|
||||||
|
ret = 0;
|
||||||
|
running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mgr.Connect(addr, port);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
|
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
@ -407,3 +414,114 @@ uint32 AccountManagement::CheckExternalLoginserverUserCredentials(
|
|||||||
|
|
||||||
return res.get();
|
return res.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32 AccountManagement::HealthCheckUserLogin()
|
||||||
|
{
|
||||||
|
std::string in_account_username = "healthcheckuser";
|
||||||
|
std::string in_account_password = "healthcheckpassword";
|
||||||
|
|
||||||
|
auto res = task_runner.Enqueue(
|
||||||
|
[&]() -> uint32 {
|
||||||
|
bool running = true;
|
||||||
|
uint32 ret = 0;
|
||||||
|
|
||||||
|
EQ::Net::DaybreakConnectionManager mgr;
|
||||||
|
std::shared_ptr<EQ::Net::DaybreakConnection> c;
|
||||||
|
|
||||||
|
mgr.OnNewConnection(
|
||||||
|
[&](std::shared_ptr<EQ::Net::DaybreakConnection> connection) {
|
||||||
|
c = connection;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
mgr.OnConnectionStateChange(
|
||||||
|
[&](
|
||||||
|
std::shared_ptr<EQ::Net::DaybreakConnection> conn,
|
||||||
|
EQ::Net::DbProtocolStatus from,
|
||||||
|
EQ::Net::DbProtocolStatus to
|
||||||
|
) {
|
||||||
|
if (EQ::Net::StatusConnected == to) {
|
||||||
|
EQ::Net::DynamicPacket p;
|
||||||
|
p.PutUInt16(0, 1); //OP_SessionReady
|
||||||
|
p.PutUInt32(2, 2);
|
||||||
|
c->QueuePacket(p);
|
||||||
|
}
|
||||||
|
else if (EQ::Net::StatusDisconnected == to) {
|
||||||
|
running = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
mgr.OnPacketRecv(
|
||||||
|
[&](std::shared_ptr<EQ::Net::DaybreakConnection> conn, const EQ::Net::Packet &p) {
|
||||||
|
auto opcode = p.GetUInt16(0);
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x0017: //OP_ChatMessage
|
||||||
|
{
|
||||||
|
size_t buffer_len =
|
||||||
|
in_account_username.length() + in_account_password.length() + 2;
|
||||||
|
|
||||||
|
std::unique_ptr<char[]> buffer(new char[buffer_len]);
|
||||||
|
|
||||||
|
strcpy(&buffer[0], in_account_username.c_str());
|
||||||
|
strcpy(&buffer[in_account_username.length() + 1], in_account_password.c_str());
|
||||||
|
|
||||||
|
size_t encrypted_len = buffer_len;
|
||||||
|
|
||||||
|
if (encrypted_len % 8 > 0) {
|
||||||
|
encrypted_len = ((encrypted_len / 8) + 1) * 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
EQ::Net::DynamicPacket p;
|
||||||
|
p.Resize(12 + encrypted_len);
|
||||||
|
p.PutUInt16(0, 2); //OP_Login
|
||||||
|
p.PutUInt32(2, 3);
|
||||||
|
|
||||||
|
eqcrypt_block(&buffer[0], buffer_len, (char *) p.Data() + 12, true);
|
||||||
|
c->QueuePacket(p);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0x0018: {
|
||||||
|
auto encrypt_size = p.Length() - 12;
|
||||||
|
if (encrypt_size % 8 > 0) {
|
||||||
|
encrypt_size = (encrypt_size / 8) * 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<char[]> decrypted(new char[encrypt_size]);
|
||||||
|
|
||||||
|
eqcrypt_block((char *) p.Data() + 12, encrypt_size, &decrypted[0], false);
|
||||||
|
|
||||||
|
EQ::Net::StaticPacket sp(&decrypted[0], encrypt_size);
|
||||||
|
auto response_error = sp.GetUInt16(1);
|
||||||
|
|
||||||
|
{
|
||||||
|
// we only care to see the response code
|
||||||
|
ret = response_error;
|
||||||
|
running = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
mgr.Connect("127.0.0.1", 5999);
|
||||||
|
|
||||||
|
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
|
||||||
|
auto &loop = EQ::EventLoop::Get();
|
||||||
|
while (running) {
|
||||||
|
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
|
||||||
|
if (std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count() > 2000) {
|
||||||
|
ret = 0;
|
||||||
|
running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
loop.Process();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return res.get();
|
||||||
|
}
|
||||||
|
|||||||
@ -89,6 +89,8 @@ public:
|
|||||||
uint32 in_account_id,
|
uint32 in_account_id,
|
||||||
const std::string &in_account_password_hash
|
const std::string &in_account_password_hash
|
||||||
);
|
);
|
||||||
|
|
||||||
|
static uint32 HealthCheckUserLogin();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -233,11 +233,16 @@ void Client::Handle_Login(const char *data, unsigned int size)
|
|||||||
user = components[1];
|
user = components[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// health checks
|
||||||
|
if (ProcessHealthCheck(user)) {
|
||||||
|
DoFailedLogin();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
LogInfo(
|
LogInfo(
|
||||||
"Attempting password based login [{0}] login [{1}] user [{2}]",
|
"Attempting password based login [{0}] login [{1}]",
|
||||||
user,
|
user,
|
||||||
db_loginserver,
|
db_loginserver
|
||||||
user
|
|
||||||
);
|
);
|
||||||
|
|
||||||
ParseAccountString(user, user, db_loginserver);
|
ParseAccountString(user, user, db_loginserver);
|
||||||
@ -376,6 +381,7 @@ void Client::AttemptLoginAccountCreation(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint32 account_id = AccountManagement::CheckExternalLoginserverUserCredentials(
|
uint32 account_id = AccountManagement::CheckExternalLoginserverUserCredentials(
|
||||||
user,
|
user,
|
||||||
pass
|
pass
|
||||||
@ -766,3 +772,11 @@ void Client::LoginProcessLoginResponse(const EQ::Net::Packet &p)
|
|||||||
m_login_connection->Close();
|
m_login_connection->Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
bool Client::ProcessHealthCheck(std::string username)
|
||||||
|
{
|
||||||
|
if (username == "healthcheckuser") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|||||||
@ -208,6 +208,7 @@ private:
|
|||||||
void LoginSendSessionReady();
|
void LoginSendSessionReady();
|
||||||
void LoginSendLogin();
|
void LoginSendLogin();
|
||||||
void LoginProcessLoginResponse(const EQ::Net::Packet &p);
|
void LoginProcessLoginResponse(const EQ::Net::Packet &p);
|
||||||
|
static bool ProcessHealthCheck(std::string username);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -38,6 +38,7 @@ namespace LoginserverCommandHandler {
|
|||||||
function_map["web-api-token:list"] = &LoginserverCommandHandler::ListLoginserverApiTokens;
|
function_map["web-api-token:list"] = &LoginserverCommandHandler::ListLoginserverApiTokens;
|
||||||
function_map["world-admin:create"] = &LoginserverCommandHandler::CreateLoginserverWorldAdminAccount;
|
function_map["world-admin:create"] = &LoginserverCommandHandler::CreateLoginserverWorldAdminAccount;
|
||||||
function_map["world-admin:update"] = &LoginserverCommandHandler::UpdateLoginserverWorldAdminAccountPassword;
|
function_map["world-admin:update"] = &LoginserverCommandHandler::UpdateLoginserverWorldAdminAccountPassword;
|
||||||
|
function_map["health:check-login"] = &LoginserverCommandHandler::HealthCheckLogin;
|
||||||
|
|
||||||
EQEmuCommand::HandleMenu(function_map, cmd, argc, argv);
|
EQEmuCommand::HandleMenu(function_map, cmd, argc, argv);
|
||||||
}
|
}
|
||||||
@ -281,4 +282,24 @@ namespace LoginserverCommandHandler {
|
|||||||
cmd(3).str()
|
cmd(3).str()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param argc
|
||||||
|
* @param argv
|
||||||
|
* @param cmd
|
||||||
|
* @param description
|
||||||
|
*/
|
||||||
|
void HealthCheckLogin(int argc, char **argv, argh::parser &cmd, std::string &description)
|
||||||
|
{
|
||||||
|
description = "Checks login health using a test user";
|
||||||
|
|
||||||
|
std::vector<std::string> arguments = {};
|
||||||
|
std::vector<std::string> options = {};
|
||||||
|
|
||||||
|
if (cmd[{"-h", "--help"}]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogInfo("[CLI] [HealthCheck] Response code [{}]", AccountManagement::HealthCheckUserLogin());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,6 +14,7 @@ namespace LoginserverCommandHandler {
|
|||||||
void UpdateLoginserverUserCredentials(int argc, char **argv, argh::parser &cmd, std::string &description);
|
void UpdateLoginserverUserCredentials(int argc, char **argv, argh::parser &cmd, std::string &description);
|
||||||
void CheckExternalLoginserverUserCredentials(int argc, char **argv, argh::parser &cmd, std::string &description);
|
void CheckExternalLoginserverUserCredentials(int argc, char **argv, argh::parser &cmd, std::string &description);
|
||||||
void UpdateLoginserverWorldAdminAccountPassword(int argc, char **argv, argh::parser &cmd, std::string &description);
|
void UpdateLoginserverWorldAdminAccountPassword(int argc, char **argv, argh::parser &cmd, std::string &description);
|
||||||
|
void HealthCheckLogin(int argc, char **argv, argh::parser &cmd, std::string &description);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -28,7 +28,7 @@ namespace LoginserverWebserver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Json::Value response;
|
Json::Value response;
|
||||||
auto iter = server.server_manager->getWorldServers().begin();
|
auto iter = server.server_manager->getWorldServers().begin();
|
||||||
while (iter != server.server_manager->getWorldServers().end()) {
|
while (iter != server.server_manager->getWorldServers().end()) {
|
||||||
Json::Value row;
|
Json::Value row;
|
||||||
row["server_long_name"] = (*iter)->GetServerLongName();
|
row["server_long_name"] = (*iter)->GetServerLongName();
|
||||||
@ -297,6 +297,24 @@ namespace LoginserverWebserver {
|
|||||||
LoginserverWebserver::SendResponse(response, res);
|
LoginserverWebserver::SendResponse(response, res);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
api.Get(
|
||||||
|
"/probes/healthcheck", [](const httplib::Request &request, httplib::Response &res) {
|
||||||
|
Json::Value response;
|
||||||
|
uint32 login_response = AccountManagement::HealthCheckUserLogin();
|
||||||
|
|
||||||
|
response["status"] = login_response;
|
||||||
|
if (login_response == 0) {
|
||||||
|
response["message"] = "Process unresponsive, exiting...";
|
||||||
|
LogInfo("Probes healthcheck unresponsive, exiting...");
|
||||||
|
}
|
||||||
|
|
||||||
|
LoginserverWebserver::SendResponse(response, res);
|
||||||
|
if (login_response == 0) {
|
||||||
|
std::exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -10,6 +10,7 @@
|
|||||||
#include "login_server.h"
|
#include "login_server.h"
|
||||||
#include "loginserver_webserver.h"
|
#include "loginserver_webserver.h"
|
||||||
#include "loginserver_command_handler.h"
|
#include "loginserver_command_handler.h"
|
||||||
|
#include "../common/string_util.h"
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -20,6 +21,7 @@ LoginServer server;
|
|||||||
EQEmuLogSys LogSys;
|
EQEmuLogSys LogSys;
|
||||||
bool run_server = true;
|
bool run_server = true;
|
||||||
|
|
||||||
|
void ResolveAddresses();
|
||||||
void CatchSignal(int sig_num)
|
void CatchSignal(int sig_num)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -118,11 +120,13 @@ void start_web_server()
|
|||||||
|
|
||||||
httplib::Server api;
|
httplib::Server api;
|
||||||
|
|
||||||
api.set_logger([](const auto& req, const auto& res) {
|
api.set_logger(
|
||||||
if (!req.path.empty()) {
|
[](const auto &req, const auto &res) {
|
||||||
LogInfo("[API] Request [{}] via [{}:{}]", req.path, req.remote_addr, req.remote_port);
|
if (!req.path.empty()) {
|
||||||
|
LogInfo("[API] Request [{}] via [{}:{}]", req.path, req.remote_addr, req.remote_port);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
|
|
||||||
LoginserverWebserver::RegisterRoutes(api);
|
LoginserverWebserver::RegisterRoutes(api);
|
||||||
api.listen("0.0.0.0", web_api_port);
|
api.listen("0.0.0.0", web_api_port);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user