2025-08-06 19:00:30 -05:00

307 lines
11 KiB
C++

#pragma once
// Copyright (C) 2007-2021 EQ2Emulator Development Team, GPL v3 License
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <atomic>
#include <iostream>
#include <string>
#include <cstring>
#include <ctime>
#include <csignal>
#include <sstream>
#include <fstream>
#include <map>
#include "lworld.hpp"
#include "client.hpp"
#include "login_database.hpp"
#include "../common/log.hpp"
#include "../common/unix.hpp"
#include "../common/crc16.hpp"
#include "../common/types.hpp"
#include "../common/debug.hpp"
#include "../common/queue.hpp"
#include "../common/timer.hpp"
#include "../common/version.hpp"
#include "../common/separator.hpp"
#include "../common/web_server.hpp"
#include "../common/json_parser.hpp"
#include "../common/data_buffer.hpp"
#include "../common/config_reader.hpp"
#include "../common/misc_functions.hpp"
#include "../common/common_defines.hpp"
#include "../common/packet/packet_struct.hpp"
#include "../common/packet/packet_functions.hpp"
#include "../common/stream/eq_stream_factory.hpp"
void CatchSignal(int sig_num);
enum eServerMode
{
Standalone,
Master,
Slave,
Mesh
};
class NetConnection
{
public:
// Constructor - initializes all network connection parameters and default values
NetConnection()
{
port = 5999;
listening_socket = 0;
memset(masteraddress, 0, sizeof(masteraddress));
uplinkport = 0;
memset(uplinkaccount, 0, sizeof(uplinkaccount));
memset(uplinkpassword, 0, sizeof(uplinkpassword));
LoginMode = Standalone;
Uplink_WrongVersion = false;
numclients = 0;
numservers = 0;
allowAccountCreation = true;
// Full expansion support flag - controls available expansions
expansionFlag = 0x7CFF;
// Cities availability flag - controls which starting cities are available
citiesFlag = 0xFF;
// Default subscription level - controls character creation restrictions
defaultSubscriptionLevel = 0xFFFFFFFF;
// Enabled races flag - controls which races are selectable
enabledRaces = 0xFFFF;
web_loginport = 0;
login_webserver = nullptr;
login_running = false;
login_uptime = getCurrentTimestamp();
}
// Destructor - cleans up web server resources
~NetConnection()
{
safe_delete(login_webserver);
}
// Updates console window title with server status information
void UpdateWindowTitle(char* iNewTitle = 0)
{
// Linux systems don't support console title updates like Windows
// This is a no-op on Linux systems
}
// Reads and parses the login server configuration from JSON file
bool ReadLoginConfig()
{
JsonParser parser(MAIN_CONFIG_FILE);
if (!parser.IsLoaded()) {
LogWrite(INIT__ERROR, 0, "Init", "Failed to find %s in server directory..", MAIN_CONFIG_FILE);
return false;
}
std::string serverport = parser.getValue("loginconfig.serverport");
std::string serverip = parser.getValue("loginconfig.serverip");
if (!parser.convertStringToUnsignedShort(serverport, port)) {
LogWrite(INIT__ERROR, 0, "Init", "Failed to translate loginconfig.serverport..");
return false;
}
if (serverip.size() > 0) {
eqsf.listen_ip_address = new char[serverip.size() + 1];
strcpy(eqsf.listen_ip_address, serverip.c_str());
}
else {
safe_delete(eqsf.listen_ip_address);
eqsf.listen_ip_address = nullptr;
}
std::string acctcreate_str = parser.getValue("loginconfig.accountcreation");
int16 allow_acct = 0;
parser.convertStringToUnsignedShort(acctcreate_str, allow_acct);
allowAccountCreation = allow_acct > 0 ? true : false;
std::string expflag_str = parser.getValue("loginconfig.expansionflag");
parser.convertStringToUnsignedInt(expflag_str, expansionFlag);
std::string citiesflag_str = parser.getValue("loginconfig.citiesflag");
parser.convertStringToUnsignedChar(citiesflag_str, citiesFlag);
std::string defaultsublevel_str = parser.getValue("loginconfig.defaultsubscriptionlevel");
parser.convertStringToUnsignedInt(defaultsublevel_str, defaultSubscriptionLevel);
std::string enableraces_str = parser.getValue("loginconfig.enabledraces");
parser.convertStringToUnsignedInt(enableraces_str, enabledRaces);
web_loginaddress = parser.getValue("loginconfig.webloginaddress");
web_certfile = parser.getValue("loginconfig.webcertfile");
web_keyfile = parser.getValue("loginconfig.webkeyfile");
web_keypassword = parser.getValue("loginconfig.webkeypassword");
web_hardcodeuser = parser.getValue("loginconfig.webhardcodeuser");
web_hardcodepassword = parser.getValue("loginconfig.webhardcodepassword");
std::string webloginport_str = parser.getValue("loginconfig.webloginport");
parser.convertStringToUnsignedShort(webloginport_str, web_loginport);
LogWrite(INIT__INFO, 0, "Init", "%s loaded..", MAIN_CONFIG_FILE);
LogWrite(INIT__INFO, 0, "Init", "Database init begin..");
if (!database.Init()) {
LogWrite(INIT__ERROR, 0, "Init", "Database init FAILED!");
LogStop();
return false;
}
LogWrite(INIT__INFO, 0, "Init", "Loading opcodes 2.0..");
EQOpcodeVersions = database.GetVersions();
std::map<int16,int16>::iterator version_itr2;
int16 version1 = 0;
for (version_itr2 = EQOpcodeVersions.begin(); version_itr2 != EQOpcodeVersions.end(); version_itr2++) {
version1 = version_itr2->first;
EQOpcodeManager[version1] = new RegularOpcodeManager();
std::map<std::string, uint16> eq = database.GetOpcodes(version1);
if (!EQOpcodeManager[version1]->LoadOpcodes(&eq)) {
LogWrite(INIT__ERROR, 0, "Init", "Loading opcodes failed. Make sure you have sourced the opcodes.sql file!");
return false;
}
}
return true;
}
// Displays the EQ2Emulator welcome header with ASCII art and information
void WelcomeHeader()
{
printf("Module: %s, Version: %s", EQ2EMU_MODULE, CURRENT_VERSION);
printf("\n\nCopyright (C) 2007-2021 EQ2Emulator. https://www.eq2emu.com \n\n");
printf("EQ2Emulator is free software: you can redistribute it and/or modify\n");
printf("it under the terms of the GNU General Public License as published by\n");
printf("the Free Software Foundation, either version 3 of the License, or\n");
printf("(at your option) any later version.\n\n");
printf("EQ2Emulator is distributed in the hope that it will be useful,\n");
printf("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n");
printf("GNU General Public License for more details.\n\n");
printf(" /$$$$$$$$ /$$$$$$ /$$$$$$ /$$$$$$$$ \n");
printf("| $$_____/ /$$__ $$ /$$__ $$| $$_____/ \n");
printf("| $$ | $$ \\ $$|__/ \\ $$| $$ /$$$$$$/$$$$ /$$ /$$\n");
printf("| $$$$$ | $$ | $$ /$$$$$$/| $$$$$ | $$_ $$_ $$| $$ | $$\n");
printf("| $$__/ | $$ | $$ /$$____/ | $$__/ | $$ \\ $$ \\ $$| $$ | $$\n");
printf("| $$ | $$/$$ $$| $$ | $$ | $$ | $$ | $$| $$ | $$\n");
printf("| $$$$$$$$| $$$$$$/| $$$$$$$$| $$$$$$$$| $$ | $$ | $$| $$$$$$/\n");
printf("|________/ \\____ $$$|________/|________/|__/ |__/ |__/ \\______/ \n");
printf(" \\__/ \n\n");
printf(" Website : https://eq2emu.com \n");
printf(" Wiki : https://wiki.eq2emu.com \n");
printf(" Git : https://git.eq2emu.com \n");
printf(" Discord : https://discord.gg/5Cavm9NYQf \n\n");
printf("For more detailed logging, modify 'Level' param the log_config.xml file.\n\n");
fflush(stdout);
}
// Initializes and starts the web server for login status and world information
void InitWebServer(std::string web_ipaddr, int16 web_port, std::string cert_file, std::string key_file, std::string key_password, std::string hardcode_user, std::string hardcode_password)
{
if (web_ipaddr.size() > 0 && web_port > 0) {
try {
login_webserver = new WebServer(web_ipaddr, web_port, cert_file, key_file, key_password, hardcode_user, hardcode_password);
login_webserver->register_route("/status", NetConnection::Web_loginhandle_status);
login_webserver->register_route("/worlds", NetConnection::Web_loginhandle_worlds);
login_webserver->run();
LogWrite(INIT__INFO, 0, "Init", "Login Web Server is listening on %s:%u..", web_ipaddr.c_str(), web_port);
}
catch (const std::exception& e) {
LogWrite(INIT__ERROR, 0, "Init", "Login Web Server failed to listen on %s:%u due to reason %s", web_ipaddr.c_str(), web_port, e.what());
}
}
}
// Accessor methods for configuration values
int16 GetPort() { return port; }
void SetPort(int16 in_port) { port = in_port; }
eServerMode GetLoginMode() { return LoginMode; }
char* GetMasterAddress() { return masteraddress; }
int16 GetUplinkPort() { if (uplinkport != 0) return uplinkport; else return port; }
char* GetUplinkAccount() { return uplinkaccount; }
char* GetUplinkPassword() { return uplinkpassword; }
bool IsAllowingAccountCreation() { return allowAccountCreation; }
int32 GetExpansionFlag() { return expansionFlag; }
int8 GetCitiesFlag() { return citiesFlag; }
int32 GetDefaultSubscriptionLevel() { return defaultSubscriptionLevel; }
int32 GetEnabledRaces() { return enabledRaces; }
std::string GetWebLoginAddress() { return web_loginaddress; }
int16 GetWebLoginPort() { return web_loginport; }
std::string GetWebCertFile() { return web_certfile; }
std::string GetWebKeyFile() { return web_keyfile; }
std::string GetWebKeyPassword() { return web_keypassword; }
std::string GetWebHardcodeUser() { return web_hardcodeuser; }
std::string GetWebHardcodePassword() { return web_hardcodepassword; }
// Web server route handlers for status and world information
static void Web_loginhandle_status(const http::request<http::string_body>& req, http::response<http::string_body>& res);
static void Web_loginhandle_worlds(const http::request<http::string_body>& req, http::response<http::string_body>& res);
// Public server state variables
char address[1024];
int32 numclients;
int32 numservers;
bool login_running;
std::atomic<int64> login_uptime;
protected:
friend class LWorld;
bool Uplink_WrongVersion;
private:
// Network connection parameters
int16 port;
int listening_socket;
char masteraddress[300];
int16 uplinkport;
char uplinkaccount[300];
char uplinkpassword[300];
eServerMode LoginMode;
// Login server configuration flags
bool allowAccountCreation;
int32 expansionFlag;
int8 citiesFlag;
int32 defaultSubscriptionLevel;
int32 enabledRaces;
// Web server configuration
std::string web_loginaddress;
std::string web_certfile;
std::string web_keyfile;
std::string web_keypassword;
std::string web_hardcodeuser;
std::string web_hardcodepassword;
int16 web_loginport;
WebServer* login_webserver;
};
// Global variables - external declarations
extern EQStreamFactory eqsf;
extern std::map<int16,OpcodeManager*> EQOpcodeManager;
extern NetConnection net;
extern ClientList client_list;
extern LWorldList world_list;
extern LoginDatabase database;
extern ConfigReader configReader;
extern std::map<int16, int16> EQOpcodeVersions;
extern Timer statTimer;
extern volatile bool RunLoops;