307 lines
11 KiB
C++
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; |