[Logging] Netcode Logging Unify (#2443)

* [Logging] Unify netcode logging

* More tweaks, generator

* Exclude OP_SpecialMesg at callback level

* Consolidate packet loggers

* Log at EQStream level instead of proxy

* Fix C->S

* Server to server logging

* C-S for Loginserver

* Hook UCS for C->S

* Update eqemu_logsys.h

* World C->S logging

* Translate opcodes through patch system for client to server

* Additional logging requests

* Add detailed opcode translation logging

* vStringFormat resiliency

* Translate loginserver C->S

* Simplify out message string (reduce copies) and ignore legacy formats

* Update eqemu_logsys.cpp

* Log file format

* Handle deprecated categories
This commit is contained in:
Chris Miles 2022-09-28 03:42:09 -05:00 committed by GitHub
parent 9d766bf5dc
commit 19791195e5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 875 additions and 1157 deletions

View File

@ -218,13 +218,13 @@ class EQStream : public EQStreamInterface {
void init(bool resetSession=true);
public:
EQStream() { init(); remote_ip = 0; remote_port = 0; State = UNESTABLISHED;
StreamType = UnknownStream; compressed = true; encoded = false; app_opcode_size = 2;
bytes_sent = 0; bytes_recv = 0; create_time = Timer::GetTimeSeconds(); sessionAttempts = 0;
EQStream() { init(); remote_ip = 0; remote_port = 0; State = UNESTABLISHED;
StreamType = UnknownStream; compressed = true; encoded = false; app_opcode_size = 2;
bytes_sent = 0; bytes_recv = 0; create_time = Timer::GetTimeSeconds(); sessionAttempts = 0;
streamactive = false; }
EQStream(sockaddr_in addr) { init(); remote_ip = addr.sin_addr.s_addr;
remote_port = addr.sin_port; State = UNESTABLISHED; StreamType = UnknownStream;
compressed = true; encoded = false; app_opcode_size = 2; bytes_sent = 0; bytes_recv = 0;
EQStream(sockaddr_in addr) { init(); remote_ip = addr.sin_addr.s_addr;
remote_port = addr.sin_port; State = UNESTABLISHED; StreamType = UnknownStream;
compressed = true; encoded = false; app_opcode_size = 2; bytes_sent = 0; bytes_recv = 0;
create_time = Timer::GetTimeSeconds(); }
virtual ~EQStream() { RemoveData(); SetState(CLOSED); }
void SetMaxLen(uint32 length) { MaxLen=length; }
@ -243,6 +243,11 @@ class EQStream : public EQStreamInterface {
virtual void SetOpcodeManager(OpcodeManager **opm) { OpMgr = opm; }
virtual OpcodeManager* GetOpcodeManager() const
{
return (*OpMgr);
};
void CheckTimeout(uint32 now, uint32 timeout=30);
bool HasOutgoingData();
void Process(const unsigned char *data, const uint32 length);

View File

@ -30,7 +30,7 @@ struct EQStreamManagerInterfaceOptions
//World seems to support both compression and xor zone supports one or the others.
//Enforce one or the other in the convienence construct
//Login I had trouble getting to recognize compression at all
//Login I had trouble getting to recognize compression at all
//but that might be because it was still a bit buggy when i was testing that.
if (compressed) {
daybreak_options.encode_passes[0] = EQ::Net::EncodeCompression;
@ -100,6 +100,7 @@ public:
virtual MatchState CheckSignature(const Signature *sig) { return MatchFailed; }
virtual EQStreamState GetState() = 0;
virtual void SetOpcodeManager(OpcodeManager **opm) = 0;
virtual OpcodeManager* GetOpcodeManager() const = 0;
virtual const EQ::versions::ClientVersion ClientVersion() const { return EQ::versions::ClientVersion::Unknown; }
virtual Stats GetStats() const = 0;
virtual void ResetStats() = 0;

View File

@ -38,12 +38,8 @@ void EQStreamProxy::SetOpcodeManager(OpcodeManager **opm)
}
void EQStreamProxy::QueuePacket(const EQApplicationPacket *p, bool ack_req) {
if(p == nullptr)
if (p == nullptr) {
return;
if (p->GetOpcode() != OP_SpecialMesg) {
Log(Logs::General, Logs::PacketServerClient, "[%s - 0x%04x] [Size: %u]", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size());
Log(Logs::General, Logs::PacketServerClientWithDump, "[%s - 0x%04x] [Size: %u] %s", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size(), DumpPacketToString(p).c_str());
}
EQApplicationPacket *newp = p->Copy();
@ -112,3 +108,8 @@ bool EQStreamProxy::CheckState(EQStreamState state) {
return false;
}
OpcodeManager *EQStreamProxy::GetOpcodeManager() const
{
return (*m_opcodes);
}

View File

@ -34,13 +34,15 @@ public:
virtual Stats GetStats() const;
virtual void ResetStats();
virtual EQStreamManagerInterface* GetManager() const;
virtual OpcodeManager* GetOpcodeManager() const;
protected:
std::shared_ptr<EQStreamInterface> const m_stream; //we own this stream object.
const StructStrategy *const m_structs; //we do not own this object.
//this is a pointer to a pointer to make it less likely that a packet will
//reference an invalid opcode manager when they are being reloaded.
OpcodeManager **const m_opcodes; //we do not own this object.
OpcodeManager **const m_opcodes;
//we do not own this object.
};
#endif /*EQSTREAMPROXY_H_*/

View File

@ -212,21 +212,6 @@ bool EQEmuLogSys::IsRfc5424LogCategory(uint16 log_category)
);
}
/**
* @param log_category
* @param in_message
* @return
*/
std::string EQEmuLogSys::FormatOutMessageString(
uint16 log_category,
const std::string &in_message
)
{
std::string return_string = "[" + GetPlatformName() + "] ";
return return_string + "[" + Logs::LogCategoryName[log_category] + "] " + in_message;
}
/**
* @param debug_level
* @param log_category
@ -423,24 +408,10 @@ void EQEmuLogSys::Out(
...
)
{
bool log_to_console = log_settings[log_category].log_to_console > 0 &&
log_settings[log_category].log_to_console >= debug_level;
bool log_to_file = log_settings[log_category].log_to_file > 0 &&
log_settings[log_category].log_to_file >= debug_level;
bool log_to_gmsay = log_settings[log_category].log_to_gmsay > 0 &&
log_settings[log_category].log_to_gmsay >= debug_level &&
log_category != Logs::LogCategory::Netcode &&
(EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformZone ||
EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformWorld);
bool log_to_discord = EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformZone &&
log_settings[log_category].log_to_discord > 0 &&
log_settings[log_category].log_to_discord >= debug_level &&
log_settings[log_category].discord_webhook_id > 0 &&
log_settings[log_category].discord_webhook_id < MAX_DISCORD_WEBHOOK_ID;
auto l = GetLogsEnabled(debug_level, log_category);
// bail out if nothing to log
const bool nothing_to_log = !log_to_console && !log_to_file && !log_to_gmsay && !log_to_discord;
if (nothing_to_log) {
if (!l.log_enabled) {
return;
}
@ -449,23 +420,39 @@ void EQEmuLogSys::Out(
prefix = fmt::format("[{0}::{1}:{2}] ", base_file_name(file), func, line);
}
va_list args;
va_start(args, message);
std::string output_message = vStringFormat(message, args);
va_end(args);
// remove this when we remove all legacy logs
bool ignore_log_legacy_format = (
log_category == Logs::Netcode ||
log_category == Logs::PacketServerClient ||
log_category == Logs::PacketClientServer ||
log_category == Logs::PacketServerToServer
);
std::string output_debug_message = EQEmuLogSys::FormatOutMessageString(log_category, prefix + output_message);
if (log_to_console) {
EQEmuLogSys::ProcessConsoleMessage(log_category, output_debug_message);
// remove this when we remove all legacy logs
std::string output_message = message;
if (!ignore_log_legacy_format) {
va_list args;
va_start(args, message);
output_message = vStringFormat(message, args);
va_end(args);
}
if (log_to_gmsay) {
if (l.log_to_console_enabled) {
EQEmuLogSys::ProcessConsoleMessage(
log_category,
fmt::format("[{}] [{}] {}", GetPlatformName(), Logs::LogCategoryName[log_category], prefix + output_message)
);
}
if (l.log_to_gmsay_enabled) {
m_on_log_gmsay_hook(log_category, output_message);
}
if (log_to_file) {
EQEmuLogSys::ProcessLogWrite(log_category, output_debug_message);
if (l.log_to_file_enabled) {
EQEmuLogSys::ProcessLogWrite(
log_category,
fmt::format("[{}] [{}] {}", GetPlatformName(), Logs::LogCategoryName[log_category], prefix + output_message)
);
}
if (log_to_discord && m_on_log_discord_hook) {
if (l.log_to_discord_enabled && m_on_log_discord_hook) {
m_on_log_discord_hook(log_category, log_settings[log_category].discord_webhook_id, output_message);
}
}
@ -479,7 +466,7 @@ void EQEmuLogSys::SetCurrentTimeStamp(char *time_stamp)
struct tm *time_info;
time(&raw_time);
time_info = localtime(&raw_time);
strftime(time_stamp, 80, "[%m-%d-%Y :: %H:%M:%S]", time_info);
strftime(time_stamp, 80, "[%m-%d-%Y %H:%M:%S]", time_info);
}
/**
@ -642,10 +629,19 @@ EQEmuLogSys *EQEmuLogSys::LoadLogDatabaseSettings()
// Auto inject categories that don't exist in the database...
for (int i = Logs::AA; i != Logs::MaxCategoryID; i++) {
if (std::find(db_categories.begin(), db_categories.end(), i) == db_categories.end()) {
bool is_missing_in_database = std::find(db_categories.begin(), db_categories.end(), i) == db_categories.end();
bool is_deprecated_category = Strings::Contains(fmt::format("{}", Logs::LogCategoryName[i]), "Deprecated");
if (!is_missing_in_database && is_deprecated_category) {
LogInfo("Logging category [{}] ({}) is now deprecated, deleting from database", Logs::LogCategoryName[i], i);
LogsysCategoriesRepository::DeleteOne(*m_database, i);
}
if (is_missing_in_database && !is_deprecated_category) {
LogInfo(
"Automatically adding new log category [{0}]",
Logs::LogCategoryName[i]
"Automatically adding new log category [{}] ({})",
Logs::LogCategoryName[i],
i
);
auto new_category = LogsysCategoriesRepository::NewEntity();
@ -696,13 +692,13 @@ void EQEmuLogSys::InjectTablesIfNotExist()
CREATE TABLE discord_webhooks
(
id INT auto_increment primary key NULL,
webhook_name varchar(100) NULL,
webhook_url varchar(255) NULL,
created_at DATETIME NULL,
deleted_at DATETIME NULL
) ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_general_ci;
webhook_name varchar(100) NULL,
webhook_url varchar(255) NULL,
created_at DATETIME NULL,
deleted_at DATETIME NULL
) ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_general_ci;
)
);
}
@ -713,15 +709,15 @@ void EQEmuLogSys::InjectTablesIfNotExist()
m_database->QueryDatabase(
SQL(
CREATE TABLE `logsys_categories` (
`log_category_id` int(11) NOT NULL,
`log_category_description` varchar(150) DEFAULT NULL,
`log_to_console` smallint(11) DEFAULT 0,
`log_to_file` smallint(11) DEFAULT 0,
`log_to_gmsay` smallint(11) DEFAULT 0,
`log_to_discord` smallint(11) DEFAULT 0,
`discord_webhook_id` int(11) DEFAULT 0,
PRIMARY KEY (`log_category_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
`log_category_id` int(11) NOT NULL,
`log_category_description` varchar(150) DEFAULT NULL,
`log_to_console` smallint(11) DEFAULT 0,
`log_to_file` smallint(11) DEFAULT 0,
`log_to_gmsay` smallint(11) DEFAULT 0,
`log_to_discord` smallint(11) DEFAULT 0,
`discord_webhook_id` int(11) DEFAULT 0,
PRIMARY KEY (`log_category_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
)
);
}
@ -732,3 +728,31 @@ const EQEmuLogSys::DiscordWebhooks *EQEmuLogSys::GetDiscordWebhooks() const
return m_discord_webhooks;
}
EQEmuLogSys::LogEnabled EQEmuLogSys::GetLogsEnabled(const Logs::DebugLevel &debug_level, const uint16 &log_category)
{
auto e = LogEnabled{};
e.log_to_console_enabled = log_settings[log_category].log_to_console > 0 &&
log_settings[log_category].log_to_console >= debug_level;
e.log_to_file_enabled = log_settings[log_category].log_to_file > 0 &&
log_settings[log_category].log_to_file >= debug_level;
e.log_to_gmsay_enabled = log_settings[log_category].log_to_gmsay > 0 &&
log_settings[log_category].log_to_gmsay >= debug_level &&
log_category != Logs::LogCategory::Netcode &&
(EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformZone ||
EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformWorld);
e.log_to_discord_enabled = EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformZone &&
log_settings[log_category].log_to_discord > 0 &&
log_settings[log_category].log_to_discord >= debug_level &&
log_settings[log_category].discord_webhook_id > 0 &&
log_settings[log_category].discord_webhook_id < MAX_DISCORD_WEBHOOK_ID;
e.log_enabled =
e.log_to_console_enabled || e.log_to_file_enabled || e.log_to_gmsay_enabled || e.log_to_discord_enabled;
return e;
}
bool EQEmuLogSys::IsLogEnabled(const Logs::DebugLevel &debug_level, const uint16 &log_category)
{
return GetLogsEnabled(debug_level, log_category).log_enabled;
}

View File

@ -54,7 +54,7 @@ namespace Logs {
AI,
Aggro,
Attack,
PacketClientServer,
DeprecatedCS,
Combat,
Commands,
Crash,
@ -88,10 +88,10 @@ namespace Logs {
MySQLQuery,
Mercenaries,
QuestDebug,
PacketServerClient,
PacketClientServerUnhandled,
PacketServerClientWithDump,
PacketClientServerWithDump,
DeprecatedSC,
DeprecatedCSU,
DeprecatedSCD,
DeprecatedCSD,
Loginserver,
ClientLogin,
HeadlessClient,
@ -132,6 +132,9 @@ namespace Logs {
Hate,
Discord,
Faction,
PacketServerClient,
PacketClientServer,
PacketServerToServer,
MaxCategoryID /* Don't Remove this */
};
@ -144,7 +147,7 @@ namespace Logs {
"AI",
"Aggro",
"Attack",
"Packet :: Client -> Server",
"Deprecated",
"Combat",
"Commands",
"Crash",
@ -178,10 +181,10 @@ namespace Logs {
"MySQL Query",
"Mercenaries",
"Quest Debug",
"Packet :: Server -> Client",
"Packet :: Client -> Server Unhandled",
"Packet :: Server -> Client (Dump)",
"Packet :: Client -> Server (Dump)",
"Deprecated",
"Deprecated",
"Deprecated",
"Deprecated",
"Login Server",
"Client Login",
"Headless Client",
@ -222,6 +225,9 @@ namespace Logs {
"Hate",
"Discord",
"Faction",
"Packet-S->C",
"Packet-C->S",
"Packet-S->S"
};
}
@ -313,6 +319,17 @@ public:
*/
LogSettings log_settings[Logs::LogCategory::MaxCategoryID]{};
struct LogEnabled {
bool log_to_file_enabled;
bool log_to_console_enabled;
bool log_to_gmsay_enabled;
bool log_to_discord_enabled;
bool log_enabled;
};
LogEnabled GetLogsEnabled(const Logs::DebugLevel &debug_level, const uint16 &log_category);
bool IsLogEnabled(const Logs::DebugLevel &debug_level, const uint16 &log_category);
struct DiscordWebhooks {
int id;
std::string webhook_name;
@ -361,7 +378,6 @@ private:
int m_log_platform = 0;
std::string m_platform_file_name;
std::string FormatOutMessageString(uint16 log_category, const std::string &in_message);
std::string GetLinuxConsoleColorFromCategory(uint16 log_category);
uint16 GetWindowsConsoleColorFromCategory(uint16 log_category);

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,7 @@
#include "../event/task.h"
#include "../data_verification.h"
#include "crc32.h"
#include "../eqemu_logsys.h"
#include <zlib.h>
#include <fmt/format.h>
#include <sstream>
@ -308,6 +309,8 @@ EQ::Net::DaybreakConnection::DaybreakConnection(DaybreakConnectionManager *owner
m_combined[1] = OP_Combined;
m_last_session_stats = Clock::now();
m_outgoing_budget = owner->m_options.outgoing_data_rate;
LogNetcode("New session [{}] with encode key [{}]", m_connect_code, HostToNetwork(m_encode_key));
}
//new connection made as client
@ -466,7 +469,7 @@ void EQ::Net::DaybreakConnection::ProcessPacket(Packet &p)
for (int i = 1; i >= 0; --i) {
switch (m_encode_passes[i]) {
case EncodeXOR:
if (temp.GetInt8(0) == 0)
if (temp.GetInt8(0) == 0)
Decode(temp, DaybreakHeader::size(), temp.Length() - DaybreakHeader::size());
else
Decode(temp, 1, temp.Length() - 1);
@ -630,6 +633,8 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p)
DynamicPacket p;
p.PutSerialize(0, reply);
InternalSend(p);
LogNetcode("[OP_SessionRequest] Session [{}] started with encode key [{}]", m_connect_code, HostToNetwork(m_encode_key));
}
break;
@ -647,6 +652,12 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p)
m_encode_passes[1] = (DaybreakEncodeType)reply.encode_pass2;
m_max_packet_size = reply.max_packet_size;
ChangeStatus(StatusConnected);
LogNetcode(
"[OP_SessionResponse] Session [{}] refresh with encode key [{}]",
m_connect_code,
HostToNetwork(m_encode_key)
);
}
}
break;
@ -771,6 +782,12 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p)
SendDisconnect();
}
LogNetcode(
"[OP_SessionDisconnect] Session [{}] disconnect with encode key [{}]",
m_connect_code,
HostToNetwork(m_encode_key)
);
ChangeStatus(StatusDisconnecting);
break;
}
@ -835,6 +852,7 @@ bool EQ::Net::DaybreakConnection::ValidateCRC(Packet &p)
}
if (p.Length() < (size_t)m_crc_bytes) {
LogNetcode("Session [{}] ignored packet (crc bytes invalid on session)", m_connect_code);
return false;
}
@ -1078,7 +1096,7 @@ void EQ::Net::DaybreakConnection::ProcessResend(int stream)
if (m_status == DbProtocolStatus::StatusDisconnected) {
return;
}
auto resends = 0;
auto now = Clock::now();
auto s = &m_streams[stream];
@ -1113,7 +1131,7 @@ void EQ::Net::DaybreakConnection::ProcessResend(int stream)
Close();
return;
}
if ((size_t)time_since_last_send.count() > entry.second.resend_delay) {
auto &p = entry.second.packet;
if (p.Length() >= DaybreakHeader::size()) {
@ -1406,8 +1424,8 @@ void EQ::Net::DaybreakConnection::InternalQueuePacket(Packet &p, int stream_id,
sent.first_sent = Clock::now();
sent.times_resent = 0;
sent.resend_delay = EQ::Clamp(
static_cast<size_t>((m_rolling_ping * m_owner->m_options.resend_delay_factor) + m_owner->m_options.resend_delay_ms),
m_owner->m_options.resend_delay_min,
static_cast<size_t>((m_rolling_ping * m_owner->m_options.resend_delay_factor) + m_owner->m_options.resend_delay_ms),
m_owner->m_options.resend_delay_min,
m_owner->m_options.resend_delay_max);
stream->sent_packets.insert(std::make_pair(stream->sequence_out, sent));
stream->sequence_out++;

View File

@ -65,6 +65,15 @@ EQ::Net::EQStream::~EQStream()
}
void EQ::Net::EQStream::QueuePacket(const EQApplicationPacket *p, bool ack_req) {
LogPacketServerClient(
"[{}] [{:#06x}] Size [{}] {}",
OpcodeManager::EmuToName(p->GetOpcode()),
(*m_opcode_manager)->EmuToEQ(p->GetOpcode()),
p->Size(),
(LogSys.IsLogEnabled(Logs::Detail, Logs::PacketServerClient) ? DumpPacketToString(p) : "")
);
if (m_opcode_manager && *m_opcode_manager) {
uint16 opcode = 0;
if (p->GetOpcodeBypass() != 0) {

View File

@ -57,6 +57,10 @@ namespace EQ
virtual void SetOpcodeManager(OpcodeManager **opm) {
m_opcode_manager = opm;
}
virtual OpcodeManager * GetOpcodeManager() const
{
return (*m_opcode_manager);
};
virtual Stats GetStats() const;
virtual void ResetStats();

View File

@ -135,7 +135,7 @@ void EQ::Net::ServertalkServerConnection::ProcessReadBuffer()
auto leg_opcode = *(uint16_t*)&m_buffer[current];
auto leg_size = *(uint16_t*)&m_buffer[current + 2] - 4;
//this creates a small edge case where the exact size of a
//this creates a small edge case where the exact size of a
//packet from the modern protocol can't be "43061256"
//so in send we pad it one byte if that's the case
if (leg_opcode == ServerOP_NewLSInfo && leg_size == sizeof(ServerNewLSInfo_Struct)) {
@ -319,6 +319,16 @@ void EQ::Net::ServertalkServerConnection::ProcessMessage(EQ::Net::Packet &p)
size_t message_len = length;
EQ::Net::StaticPacket packet(&data[0], message_len);
const auto is_detail_enabled = LogSys.IsLogEnabled(Logs::Detail, Logs::PacketServerToServer);
if (opcode != ServerOP_KeepAlive || is_detail_enabled) {
LogPacketServerToServer(
"[{:#06x}] Size [{}] {}",
opcode,
packet.Length(),
(is_detail_enabled ? "\n" + packet.ToString() : "")
);
}
auto cb = m_message_callbacks.find(opcode);
if (cb != m_message_callbacks.end()) {
cb->second(opcode, packet);

View File

@ -184,6 +184,9 @@ uint16 RegularOpcodeManager::EmuToEQ(const EmuOpcode emu_op) {
MOpcodes.lock();
res = emu_to_eq[emu_op];
MOpcodes.unlock();
LogNetcodeDetail("[Opcode Manager] Translate emu [{}] ({:#06x}) eq [{:#06x}]", OpcodeNames[emu_op], emu_op, res);
#ifdef DEBUG_TRANSLATE
fprintf(stderr, "M Translate Emu %s (%d) to EQ 0x%.4x\n", OpcodeNames[emu_op], emu_op, res);
#endif

View File

@ -26,13 +26,13 @@ bool Client::Process()
{
EQApplicationPacket *app = m_connection->PopPacket();
while (app) {
if (server.options.IsTraceOn()) {
LogDebug("Application packet received from client (size {0})", app->Size());
}
if (server.options.IsDumpInPacketsOn()) {
DumpPacket(app);
}
LogPacketClientServer(
"[{}] [{:#06x}] Size [{}] {}",
OpcodeManager::EmuToName(app->GetOpcode()),
m_connection->GetOpcodeManager()->EmuToEQ(app->GetOpcode()),
app->Size(),
(LogSys.IsLogEnabled(Logs::Detail, Logs::PacketClientServer) ? DumpPacketToString(app) : "")
);
if (m_client_status == cs_failed_to_login) {
delete app;
@ -42,9 +42,7 @@ bool Client::Process()
switch (app->GetOpcode()) {
case OP_SessionReady: {
if (server.options.IsTraceOn()) {
LogInfo("Session ready received from client");
}
LogInfo("Session ready received from client account {}", GetClientDescription());
Handle_SessionReady((const char *) app->pBuffer, app->Size());
break;
}
@ -54,9 +52,7 @@ bool Client::Process()
break;
}
if (server.options.IsTraceOn()) {
LogInfo("Login received from client");
}
LogInfo("Login received from client {}", GetClientDescription());
Handle_Login((const char *) app->pBuffer, app->Size());
break;
@ -67,9 +63,7 @@ bool Client::Process()
break;
}
if (server.options.IsTraceOn()) {
LogDebug("Server list request received from client");
}
LogInfo("Server list request received from client {}", GetClientDescription());
SendServerListPacket(*(uint32_t *) app->pBuffer);
break;
@ -84,11 +78,9 @@ bool Client::Process()
break;
}
default: {
if (LogSys.log_settings[Logs::PacketClientServerUnhandled].is_category_enabled == 1) {
char dump[64];
app->build_header_dump(dump);
LogError("Recieved unhandled application packet from the client: [{}]", dump);
}
char dump[64];
app->build_header_dump(dump);
LogError("Received unhandled application packet from the client: [{}]", dump);
}
}
@ -128,10 +120,6 @@ void Client::Handle_SessionReady(const char *data, unsigned int size)
buf->base_reply.success = true;
buf->base_reply.error_str_id = 0x65; // 101 "No Error"
if (server.options.IsDumpOutPacketsOn()) {
DumpPacket(outapp);
}
m_connection->QueuePacket(outapp);
delete outapp;
}
@ -290,14 +278,12 @@ void Client::Handle_Play(const char *data)
auto server_id_in = (unsigned int) play->server_number;
auto sequence_in = (unsigned int) play->base_header.sequence;
if (server.options.IsTraceOn()) {
LogInfo(
"Play received from client [{0}] server number {1} sequence {2}",
GetAccountName(),
server_id_in,
sequence_in
);
}
LogInfo(
"[Handle_Play] Play received from client [{}] server number [{}] sequence [{}]",
GetAccountName(),
server_id_in,
sequence_in
);
m_play_server_id = (unsigned int) play->server_number;
m_play_sequence_id = sequence_in;
@ -310,21 +296,14 @@ void Client::Handle_Play(const char *data)
*/
void Client::SendServerListPacket(uint32 seq)
{
auto outapp = server.server_manager->CreateServerListPacket(this, seq);
auto app = server.server_manager->CreateServerListPacket(this, seq);
if (server.options.IsDumpOutPacketsOn()) {
DumpPacket(outapp.get());
}
m_connection->QueuePacket(outapp.get());
m_connection->QueuePacket(app.get());
}
void Client::SendPlayResponse(EQApplicationPacket *outapp)
{
if (server.options.IsTraceOn()) {
LogDebug("Sending play response for {0}", GetAccountName());
// server_log->LogPacket(log_network_trace, (const char*)outapp->pBuffer, outapp->size);
}
LogInfo("Sending play response for {}", GetClientDescription());
m_connection->QueuePacket(outapp);
}
@ -422,10 +401,6 @@ void Client::DoFailedLogin()
outapp.WriteData(&base_header, sizeof(base_header));
outapp.WriteData(&encrypted_buffer, sizeof(encrypted_buffer));
if (server.options.IsDumpOutPacketsOn()) {
DumpPacket(&outapp);
}
m_connection->QueuePacket(&outapp);
m_client_status = cs_failed_to_login;
}
@ -576,10 +551,6 @@ void Client::DoSuccessfulLogin(
outapp->WriteData(&base_header, sizeof(base_header));
outapp->WriteData(&encrypted_buffer, sizeof(encrypted_buffer));
if (server.options.IsDumpOutPacketsOn()) {
DumpPacket(outapp.get());
}
m_connection->QueuePacket(outapp.get());
m_client_status = cs_logged_in;
@ -596,7 +567,7 @@ void Client::SendExpansionPacketData(PlayerLoginReply_Struct& plrs)
if (server.options.IsDisplayExpansions()) {
int32_t expansion = server.options.GetMaxExpansions();
int32_t owned_expansion = (expansion << 1) | 1;
@ -839,3 +810,17 @@ bool Client::ProcessHealthCheck(std::string username)
return false;
}
std::string Client::GetClientDescription()
{
in_addr in{};
in.s_addr = GetConnection()->GetRemoteIP();
std::string client_ip = inet_ntoa(in);
return fmt::format(
"account_name [{}] account_id ({}) ip_address [{}]",
GetAccountName(),
GetAccountID(),
client_ip
);
}

View File

@ -51,7 +51,7 @@ public:
* @param size
*/
void Handle_Login(const char *data, unsigned int size);
/**
* Sends the expansion data packet
*
@ -111,6 +111,12 @@ public:
*/
std::string GetAccountName() const { return m_account_name; }
/**
* Returns a description for the client for logging
* @return std::string
*/
std::string GetClientDescription();
/**
* Gets the key generated at login for this client
*

View File

@ -45,15 +45,6 @@ void LoadServerConfig()
server.config = EQ::JsonConfigFile::Load("login.json");
LogInfo("Config System Init");
/**
* Logging
*/
server.options.Trace(server.config.GetVariableBool("logging", "trace", false));
server.options.WorldTrace(server.config.GetVariableBool("logging", "world_trace", false));
server.options.DumpInPackets(server.config.GetVariableBool("logging", "dump_packets_in", false));
server.options.DumpOutPackets(server.config.GetVariableBool("logging", "dump_packets_out", false));
/**
* Worldservers
*/
@ -63,7 +54,7 @@ void LoadServerConfig()
"reject_duplicate_servers",
false
)
);
);
server.options.SetShowPlayerCount(server.config.GetVariableBool("worldservers", "show_player_count", false));
server.options.AllowUnregistered(
server.config.GetVariableBool(
@ -90,8 +81,18 @@ void LoadServerConfig()
/**
* Expansion Display Settings
*/
server.options.DisplayExpansions(server.config.GetVariableBool("client_configuration", "display_expansions", false)); //disable by default
server.options.MaxExpansions(server.config.GetVariableInt("client_configuration", "max_expansions_mask", 67108863)); //enable display of all expansions
server.options.DisplayExpansions(
server.config.GetVariableBool(
"client_configuration",
"display_expansions",
false
)); //disable by default
server.options.MaxExpansions(
server.config.GetVariableInt(
"client_configuration",
"max_expansions_mask",
67108863
)); //enable display of all expansions
/**
* Account
@ -181,7 +182,7 @@ int main(int argc, char **argv)
LoadDatabaseConnection();
LogSys.LoadLogSettingsDefaults();
LogSys.log_settings[Logs::Debug].log_to_console = static_cast<uint8>(Logs::General);
LogSys.log_settings[Logs::Debug].log_to_console = static_cast<uint8>(Logs::General);
LogSys.log_settings[Logs::Debug].is_category_enabled = 1;
LoginserverCommandHandler::CommandHandler(argc, argv);
@ -258,10 +259,6 @@ int main(int argc, char **argv)
web_api_thread.detach();
}
LogInfo("[Config] [Logging] IsTraceOn [{0}]", server.options.IsTraceOn());
LogInfo("[Config] [Logging] IsWorldTraceOn [{0}]", server.options.IsWorldTraceOn());
LogInfo("[Config] [Logging] IsDumpInPacketsOn [{0}]", server.options.IsDumpInPacketsOn());
LogInfo("[Config] [Logging] IsDumpOutPacketsOn [{0}]", server.options.IsDumpOutPacketsOn());
LogInfo("[Config] [Account] CanAutoCreateAccounts [{0}]", server.options.CanAutoCreateAccounts());
LogInfo("[Config] [Client_Configuration] DisplayExpansions [{0}]", server.options.IsDisplayExpansions());
LogInfo("[Config] [Client_Configuration] MaxExpansions [{0}]", server.options.GetMaxExpansions());

View File

@ -13,9 +13,6 @@ public:
*/
Options() :
allow_unregistered(true),
trace(false),
dump_in_packets(false),
dump_out_packets(false),
display_expansions(false),
max_expansions_mask(0),
encryption_mode(5),
@ -42,46 +39,6 @@ public:
*/
inline bool IsUnregisteredAllowed() const { return allow_unregistered; }
/**
* Sets trace.
*/
inline void Trace(bool b) { trace = b; }
/**
* Returns the value of trace.
*/
inline bool IsTraceOn() const { return trace; }
/**
* Sets trace.
*/
inline void WorldTrace(bool b) { world_trace = b; }
/**
* Returns the value of trace.
*/
inline bool IsWorldTraceOn() const { return world_trace; }
/**
* Sets dump_in_packets.
*/
inline void DumpInPackets(bool b) { dump_in_packets = b; }
/**
* Returns the value of dump_in_packets.
*/
inline bool IsDumpInPacketsOn() const { return dump_in_packets; }
/**
* Sets dump_out_packets.
*/
inline void DumpOutPackets(bool b) { dump_out_packets = b; }
/**
* Returns the value of dump_out_packets.
*/
inline bool IsDumpOutPacketsOn() const { return dump_out_packets; }
/**
* Sets encryption_mode.
*/
@ -148,10 +105,6 @@ public:
private:
bool allow_unregistered;
bool trace;
bool world_trace;
bool dump_in_packets;
bool dump_out_packets;
bool display_expansions;
bool reject_duplicate_servers;
bool world_dev_test_servers_list_bottom;

View File

@ -180,21 +180,23 @@ void ServerManager::SendUserToWorldRequest(
EQ::Net::DynamicPacket outapp;
outapp.Resize(sizeof(UsertoWorldRequest_Struct));
auto *user_to_world_request = (UsertoWorldRequest_Struct *) outapp.Data();
user_to_world_request->worldid = server_id;
user_to_world_request->lsaccountid = client_account_id;
strncpy(user_to_world_request->login, &client_loginserver[0], 64);
auto *r = (UsertoWorldRequest_Struct *) outapp.Data();
r->worldid = server_id;
r->lsaccountid = client_account_id;
strncpy(r->login, &client_loginserver[0], 64);
(*iter)->GetConnection()->Send(ServerOP_UsertoWorldReq, outapp);
found = true;
if (server.options.IsDumpInPacketsOn()) {
LogInfo("{0}", outapp.ToString());
}
LogNetcode(
"[UsertoWorldRequest] [Size: {}]\n{}",
outapp.Length(),
outapp.ToString()
);
}
++iter;
}
if (!found && server.options.IsTraceOn()) {
if (!found) {
LogError("Client requested a user to world but supplied an invalid id of {0}", server_id);
}
}

View File

@ -79,17 +79,12 @@ void WorldServer::Reset()
*/
void WorldServer::ProcessNewLSInfo(uint16_t opcode, const EQ::Net::Packet &packet)
{
if (server.options.IsWorldTraceOn()) {
LogDebug(
"Application packet received from server: [{0}], (size {1})",
opcode,
packet.Length()
);
}
if (server.options.IsDumpInPacketsOn()) {
DumpPacket(opcode, packet);
}
LogNetcode(
"[ProcessNewLSInfo] Application packet received from server [{:#04x}] [Size: {}]\n{}",
opcode,
packet.Length(),
packet.ToString()
);
if (packet.Length() < sizeof(ServerNewLSInfo_Struct)) {
LogError(
@ -129,18 +124,13 @@ void WorldServer::ProcessNewLSInfo(uint16_t opcode, const EQ::Net::Packet &packe
*/
void WorldServer::ProcessLSStatus(uint16_t opcode, const EQ::Net::Packet &packet)
{
Log(
Logs::Detail,
Logs::Netcode,
"Application packet received from server: 0x%.4X, (size %u)",
LogNetcode(
"[ProcessLSStatus] Application packet received from server [{:#04x}] [Size: {}]\n{}",
opcode,
packet.Length()
packet.Length(),
packet.ToString()
);
if (server.options.IsDumpInPacketsOn()) {
DumpPacket(opcode, packet);
}
if (packet.Length() < sizeof(ServerLSStatus_Struct)) {
LogError(
"Received application packet from server that had opcode ServerOP_LSStatus, but was too small. Discarded to avoid buffer overrun"
@ -151,15 +141,13 @@ void WorldServer::ProcessLSStatus(uint16_t opcode, const EQ::Net::Packet &packet
auto *ls_status = (ServerLSStatus_Struct *) packet.Data();
if (server.options.IsWorldTraceOn()) {
LogDebug(
"World Server Status Update Received | Server [{0}] Status [{1}] Players [{2}] Zones [{3}]",
GetServerLongName(),
ls_status->status,
ls_status->num_players,
ls_status->num_zones
);
}
LogDebug(
"World Server Status Update Received | Server [{0}] Status [{1}] Players [{2}] Zones [{3}]",
GetServerLongName(),
ls_status->status,
ls_status->num_players,
ls_status->num_zones
);
Handle_LSStatus(ls_status);
}
@ -170,17 +158,12 @@ void WorldServer::ProcessLSStatus(uint16_t opcode, const EQ::Net::Packet &packet
*/
void WorldServer::ProcessUserToWorldResponseLegacy(uint16_t opcode, const EQ::Net::Packet &packet)
{
if (server.options.IsWorldTraceOn()) {
LogDebug(
"Application packet received from server: [{0}], (size {1})",
opcode,
packet.Length()
);
}
if (server.options.IsDumpInPacketsOn()) {
DumpPacket(opcode, packet);
}
LogNetcode(
"[ProcessUserToWorldResponseLegacy] Application packet received from server [{:#04x}] [Size: {}]\n{}",
opcode,
packet.Length(),
packet.ToString()
);
if (packet.Length() < sizeof(UsertoWorldResponseLegacy_Struct)) {
LogError(
@ -191,19 +174,11 @@ void WorldServer::ProcessUserToWorldResponseLegacy(uint16_t opcode, const EQ::Ne
return;
}
//I don't use world trace for this and here is why:
//Because this is a part of the client login procedure it makes tracking client errors
//While keeping world server spam with multiple servers connected almost impossible.
if (server.options.IsTraceOn()) {
LogDebug("User-To-World Response received");
}
auto *r = (UsertoWorldResponseLegacy_Struct *) packet.Data();
LogDebug("Trying to find client with user id of [{0}]", r->lsaccountid);
Client *client = server.client_manager->GetClient(r->lsaccountid, "eqemu");
if (client) {
LogDebug(
"Found client with user id of [{0}] and account name of [{1}]",
r->lsaccountid,
@ -254,21 +229,13 @@ void WorldServer::ProcessUserToWorldResponseLegacy(uint16_t opcode, const EQ::Ne
break;
}
if (server.options.IsWorldTraceOn()) {
LogDebug(
"Sending play response: allowed [{0}] sequence [{1}] server number [{2}] message [{3}]",
per->base_reply.success,
per->base_header.sequence,
per->server_number,
per->base_reply.error_str_id
);
LogDebug("[Size: [{0}]] {1}", outapp->size, DumpPacketToString(outapp));
}
if (server.options.IsDumpOutPacketsOn()) {
DumpPacket(outapp);
}
LogDebug(
"Sending play response: allowed [{0}] sequence [{1}] server number [{2}] message [{3}]",
per->base_reply.success,
per->base_header.sequence,
per->server_number,
per->base_reply.error_str_id
);
client->SendPlayResponse(outapp);
delete outapp;
@ -287,17 +254,12 @@ void WorldServer::ProcessUserToWorldResponseLegacy(uint16_t opcode, const EQ::Ne
*/
void WorldServer::ProcessUserToWorldResponse(uint16_t opcode, const EQ::Net::Packet &packet)
{
if (server.options.IsWorldTraceOn()) {
LogDebug(
"Application packet received from server: 0x%.4X, (size %u)",
opcode,
packet.Length()
);
}
if (server.options.IsDumpInPacketsOn()) {
DumpPacket(opcode, packet);
}
LogNetcode(
"[ProcessUserToWorldResponse] Application packet received from server [{:#04x}] [Size: {}]\n{}",
opcode,
packet.Length(),
packet.ToString()
);
if (packet.Length() < sizeof(UsertoWorldResponse_Struct)) {
LogError(
@ -308,25 +270,18 @@ void WorldServer::ProcessUserToWorldResponse(uint16_t opcode, const EQ::Net::Pac
return;
}
//I don't use world trace for this and here is why:
//Because this is a part of the client login procedure it makes tracking client errors
//While keeping world server spam with multiple servers connected almost impossible.
if (server.options.IsTraceOn()) {
LogDebug("User-To-World Response received");
}
auto user_to_world_response = (UsertoWorldResponse_Struct *) packet.Data();
LogDebug("Trying to find client with user id of [{0}]", user_to_world_response->lsaccountid);
Client *client = server.client_manager->GetClient(
Client *c = server.client_manager->GetClient(
user_to_world_response->lsaccountid,
user_to_world_response->login
);
if (client) {
if (c) {
LogDebug("Found client with user id of [{0}] and account name of {1}",
user_to_world_response->lsaccountid,
client->GetAccountName().c_str()
c->GetAccountName().c_str()
);
auto *outapp = new EQApplicationPacket(
@ -334,69 +289,62 @@ void WorldServer::ProcessUserToWorldResponse(uint16_t opcode, const EQ::Net::Pac
sizeof(PlayEverquestResponse_Struct)
);
auto *per = (PlayEverquestResponse_Struct *) outapp->pBuffer;
per->base_header.sequence = client->GetPlaySequence();
per->server_number = client->GetPlayServerID();
auto *r = (PlayEverquestResponse_Struct *) outapp->pBuffer;
r->base_header.sequence = c->GetPlaySequence();
r->server_number = c->GetPlayServerID();
LogDebug(
"Found sequence and play of [{0}] [{1}]",
client->GetPlaySequence(),
client->GetPlayServerID()
c->GetPlaySequence(),
c->GetPlayServerID()
);
LogDebug("[Size: [{0}]] {1}", outapp->size, DumpPacketToString(outapp));
if (user_to_world_response->response > 0) {
per->base_reply.success = true;
r->base_reply.success = true;
SendClientAuth(
client->GetConnection()->GetRemoteAddr(),
client->GetAccountName(),
client->GetKey(),
client->GetAccountID(),
client->GetLoginServerName()
c->GetConnection()->GetRemoteAddr(),
c->GetAccountName(),
c->GetKey(),
c->GetAccountID(),
c->GetLoginServerName()
);
}
switch (user_to_world_response->response) {
case UserToWorldStatusSuccess:
per->base_reply.error_str_id = LS::ErrStr::ERROR_NONE;
r->base_reply.error_str_id = LS::ErrStr::ERROR_NONE;
break;
case UserToWorldStatusWorldUnavail:
per->base_reply.error_str_id = LS::ErrStr::ERROR_SERVER_UNAVAILABLE;
r->base_reply.error_str_id = LS::ErrStr::ERROR_SERVER_UNAVAILABLE;
break;
case UserToWorldStatusSuspended:
per->base_reply.error_str_id = LS::ErrStr::ERROR_ACCOUNT_SUSPENDED;
r->base_reply.error_str_id = LS::ErrStr::ERROR_ACCOUNT_SUSPENDED;
break;
case UserToWorldStatusBanned:
per->base_reply.error_str_id = LS::ErrStr::ERROR_ACCOUNT_BANNED;
r->base_reply.error_str_id = LS::ErrStr::ERROR_ACCOUNT_BANNED;
break;
case UserToWorldStatusWorldAtCapacity:
per->base_reply.error_str_id = LS::ErrStr::ERROR_WORLD_MAX_CAPACITY;
r->base_reply.error_str_id = LS::ErrStr::ERROR_WORLD_MAX_CAPACITY;
break;
case UserToWorldStatusAlreadyOnline:
per->base_reply.error_str_id = LS::ErrStr::ERROR_ACTIVE_CHARACTER;
r->base_reply.error_str_id = LS::ErrStr::ERROR_ACTIVE_CHARACTER;
break;
default:
per->base_reply.error_str_id = LS::ErrStr::ERROR_UNKNOWN;
r->base_reply.error_str_id = LS::ErrStr::ERROR_UNKNOWN;
break;
}
if (server.options.IsTraceOn()) {
LogDebug(
"Sending play response with following data, allowed [{0}], sequence {1}, server number {2}, message {3}",
per->base_reply.success,
per->base_header.sequence,
per->server_number,
per->base_reply.error_str_id
);
LogDebug("[Size: [{0}]] {1}", outapp->size, DumpPacketToString(outapp));
}
LogDebug(
"Sending play response with following data, allowed [{0}], sequence {1}, server number {2}, message {3}",
r->base_reply.success,
r->base_header.sequence,
r->server_number,
r->base_reply.error_str_id
);
if (server.options.IsDumpOutPacketsOn()) {
DumpPacket(outapp);
}
client->SendPlayResponse(outapp);
c->SendPlayResponse(outapp);
delete outapp;
}
else {
@ -413,17 +361,12 @@ void WorldServer::ProcessUserToWorldResponse(uint16_t opcode, const EQ::Net::Pac
*/
void WorldServer::ProcessLSAccountUpdate(uint16_t opcode, const EQ::Net::Packet &packet)
{
if (server.options.IsWorldTraceOn()) {
LogDebug(
"Application packet received from server: [{0}], (size {1})",
opcode,
packet.Length()
);
}
if (server.options.IsDumpInPacketsOn()) {
DumpPacket(opcode, packet);
}
LogNetcode(
"[ProcessLSAccountUpdate] Application packet received from server [{:#04x}] [Size: {}]\n{}",
opcode,
packet.Length(),
packet.ToString()
);
if (packet.Length() < sizeof(ServerLSAccountUpdate_Struct)) {
LogError(
@ -434,9 +377,7 @@ void WorldServer::ProcessLSAccountUpdate(uint16_t opcode, const EQ::Net::Packet
return;
}
if (server.options.IsWorldTraceOn()) {
LogDebug("ServerOP_LSAccountUpdate packet received from [{0}]", m_short_name);
}
LogDebug("ServerOP_LSAccountUpdate packet received from [{0}]", m_short_name);
auto *loginserver_update = (ServerLSAccountUpdate_Struct *) packet.Data();
if (IsServerTrusted()) {
@ -607,34 +548,34 @@ void WorldServer::SendClientAuth(
)
{
EQ::Net::DynamicPacket outapp;
ClientAuth_Struct client_auth{};
ClientAuth_Struct a{};
client_auth.loginserver_account_id = account_id;
a.loginserver_account_id = account_id;
strncpy(client_auth.account_name, account.c_str(), 30);
strncpy(client_auth.key, key.c_str(), 30);
strncpy(a.account_name, account.c_str(), 30);
strncpy(a.key, key.c_str(), 30);
client_auth.lsadmin = 0;
client_auth.is_world_admin = 0;
client_auth.ip = inet_addr(ip.c_str());
strncpy(client_auth.loginserver_name, &loginserver_name[0], 64);
a.lsadmin = 0;
a.is_world_admin = 0;
a.ip = inet_addr(ip.c_str());
strncpy(a.loginserver_name, &loginserver_name[0], 64);
const std::string &client_address(ip);
std::string world_address(m_connection->Handle()->RemoteIP());
if (client_address == world_address) {
client_auth.is_client_from_local_network = 1;
a.is_client_from_local_network = 1;
}
else if (IpUtil::IsIpInPrivateRfc1918(client_address)) {
LogInfo("Client is authenticating from a local address [{0}]", client_address);
client_auth.is_client_from_local_network = 1;
a.is_client_from_local_network = 1;
}
else {
client_auth.is_client_from_local_network = 0;
a.is_client_from_local_network = 0;
}
struct in_addr ip_addr{};
ip_addr.s_addr = client_auth.ip;
ip_addr.s_addr = a.ip;
LogInfo(
"Client authentication response: world_address [{0}] client_address [{1}]",
@ -645,22 +586,25 @@ void WorldServer::SendClientAuth(
LogInfo(
"Sending Client Authentication Response ls_account_id [{0}] ls_name [{1}] name [{2}] key [{3}] ls_admin [{4}] "
"world_admin [{5}] ip [{6}] local [{7}]",
client_auth.loginserver_account_id,
client_auth.loginserver_name,
client_auth.account_name,
client_auth.key,
client_auth.lsadmin,
client_auth.is_world_admin,
a.loginserver_account_id,
a.loginserver_name,
a.account_name,
a.key,
a.lsadmin,
a.is_world_admin,
inet_ntoa(ip_addr),
client_auth.is_client_from_local_network
a.is_client_from_local_network
);
outapp.PutSerialize(0, client_auth);
outapp.PutSerialize(0, a);
m_connection->Send(ServerOP_LSClientAuth, outapp);
if (server.options.IsDumpInPacketsOn()) {
DumpPacket(ServerOP_LSClientAuth, outapp);
}
LogNetcode(
"[ServerOP_LSClientAuth] Sending [{:#04x}] [Size: {}]\n{}",
ServerOP_LSClientAuth,
outapp.Length(),
outapp.ToString()
);
}
constexpr static int MAX_ACCOUNT_NAME_LENGTH = 30;

View File

@ -615,6 +615,14 @@ void Clientlist::Process()
while (KeyValid && !(*it)->GetForceDisconnect() && (app = (*it)->ClientStream->PopPacket())) {
EmuOpcode opcode = app->GetOpcode();
LogPacketClientServer(
"[{}] [{:#06x}] Size [{}] {}",
OpcodeManager::EmuToName(app->GetOpcode()),
(*it)->ClientStream->GetOpcodeManager()->EmuToEQ(app->GetOpcode()),
app->Size(),
(LogSys.IsLogEnabled(Logs::Detail, Logs::PacketClientServer) ? DumpPacketToString(app) : "")
);
switch (opcode) {
case OP_MailLogin: {
char *PacketBuffer = (char *)app->pBuffer + 1;

View File

@ -0,0 +1,53 @@
#!/usr/bin/perl
use strict;
use warnings FATAL => 'all';
my $filename = './common/eqemu_logsys.h';
open(my $fh, '<:encoding(UTF-8)', $filename)
or die "Could not open file '$filename' $!";
my $contents = "";
while (my $row = <$fh>) {
chomp $row;
$contents .= $row . "\n";
}
my @enum = split('enum LogCategory \{', $contents);
if (scalar(@enum) > 0) {
# print $enum[1];
my @second_split = split('};', $enum[1]);
if (scalar(@second_split) > 0) {
my $categories = $second_split[0];
$categories =~ s/^\s+//;
$categories =~ s/\s+$//;
$categories =~ s/ //g;
$categories =~ s/ //g;
$categories =~ s/\n//g;
$categories =~ s/None=0,//g;
$categories =~ s/,MaxCategoryID//g;
$categories =~ s/\/\*//g;
$categories =~ s/\*\///g;
$categories =~ s/Don'tRemovethis//g;
my @cats = split(',', $categories);
foreach my $cat (@cats) {
print "#define Log" . $cat . "(message, ...) do {\\
if (LogSys.IsLogEnabled(Logs::General, Logs::" . $cat . "))\\
OutF(LogSys, Logs::General, Logs::" . $cat . ", __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\\
} while (0)
#define Log" . $cat . "Detail(message, ...) do {\\
if (LogSys.IsLogEnabled(Logs::Detail, Logs::" . $cat . "))\\
OutF(LogSys, Logs::Detail, Logs::" . $cat . ", __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\\
} while (0)
";
# print "$cat\n";
}
}
}
close $fh;

View File

@ -1,241 +0,0 @@
#!/usr/bin/perl
# Author: Akkadius
# @file: lua-doc-parser.pl
# @description: Script meant to parse the source code to build the LUA API list
use File::Find;
use Data::Dumper;
sub usage() {
print "Usage:\n";
print " --client - Prints methods for just client class methods\n";
print " --mob - Prints methods for just mob class methods\n";
print " --npc - Prints methods for just npc class methods\n";
print " --entity - Prints methods for just entity class methods\n";
print " --entity_list - Prints methods for just entity_list class methods\n";
print " --door - Prints methods for just door class methods\n";
print " --object - Prints methods for just object class methods\n";
print " --group - Prints methods for just group class methods\n";
print " --raid - Prints methods for just raid class methods\n";
print " --item - Prints methods for just item class methods\n";
print " --iteminst - Prints methods for just iteminst class methods\n";
print " --inventory - Prints methods for just inventory class methods\n";
print " --corpse - Prints methods for just corpse class methods\n";
print " --hate_entry - Prints methods for just hate_entry class methods\n";
print " --quest - Prints methods for just quest class methods\n";
print " --spell - Prints methods for just spell class methods\n";
print " --spawn - Prints methods for just spawn class methods\n";
print " --packet - Prints methods for just packet class methods\n";
print " --stat_bonuses - Prints methods for just stat_bonuses class methods\n";
print " --all - Prints methods for all classes\n";
exit(1);
}
if($#ARGV < 0) {
usage();
}
#::: Open File
my $filename = 'lua-api.md';
open(my $fh, '>', $filename) or die "Could not open file '$filename' $!";
my $export = $ARGV[0];
$export=~s/--//g;
my $export_file_search = $export;
if ($export eq "quest") {
$export_file_search = "lua_general";
}
my @files;
my $start_dir = "zone/";
find(
sub { push @files, $File::Find::name unless -d; },
$start_dir
);
for my $file (@files) {
#::: Skip non lua.cpp files
if($file!~/lua_/i || $file!~/cpp/i){
next;
}
#::: If we are specifying a specific class type, skip everything else
if ($export ne "all" && $export ne "") {
if ($file!~/$export_file_search\.cpp/i) {
next;
}
}
@methods = ();
$split_key = "";
$object_prefix = "";
#::: Client Export
if ($export=~/all|client/i && $file=~/_client/i) {
$split_key = "Client::";
$object_prefix = "client:";
}
#::: Mob Export
if ($export=~/all|mob/i && $file=~/_mob/i) {
$split_key = "Mob::";
$object_prefix = "mob:";
}
#::: NPC Export
if ($export=~/all|npc/i && $file=~/_npc/i) {
$split_key = "NPC::";
$object_prefix = "npc:";
}
#::: Object Export
if ($export=~/all|object/i && $file=~/_object/i) {
$split_key = "Object::";
$object_prefix = "object:";
}
#::: Door Export
if ($export=~/all|door/i && $file=~/_door/i) {
$split_key = "Door::";
$object_prefix = "door:";
}
#::: Entity Export
if ($export=~/all|entity/i && $file=~/_entity/i) {
$split_key = "Entity::";
$object_prefix = "entity:";
}
#::: Entity List Export
if ($export=~/all|entity_list/i && $file=~/_entity_list/i) {
$split_key = "EntityList::";
$object_prefix = "entity_list:";
}
#::: Group
if ($export=~/all|group/i && $file=~/_group/i) {
$split_key = "Group::";
$object_prefix = "group:";
}
#::: Raid
if ($export=~/all|raid/i && $file=~/_raid/i) {
$split_key = "Raid::";
$object_prefix = "raid:";
}
#::: Corpse
if ($export=~/all|corpse/i && $file=~/_corpse/i) {
$split_key = "Corpse::";
$object_prefix = "corpse:";
}
#::: Hateentry
if ($export=~/all|hate_entry/i && $file=~/_hate_entry/i) {
$split_key = "HateEntry::";
$object_prefix = "hate_entry:";
}
#::: Spell
if ($export=~/all|spell/i && $file=~/_spell/i) {
$split_key = "Spell::";
$object_prefix = "spell:";
}
#::: Spawn
if ($export=~/all|spawn/i && $file=~/_spawn/i) {
$split_key = "Spawn::";
$object_prefix = "spawn:";
}
#::: StatBonuses
if ($export=~/all|stat_bonuses/i && $file=~/stat_bonuses/i) {
$split_key = "StatBonuses::";
$object_prefix = "statbonuses:";
}
#::: Item
if ($export=~/all|item/i && $file=~/_item/i) {
$split_key = "Item::";
$object_prefix = "item:";
}
#::: ItemInst
if ($export=~/all|iteminst/i && $file=~/_iteminst/i) {
$split_key = "ItemInst::";
$object_prefix = "iteminst:";
}
#::: Inventory
if ($export=~/all|inventory/i && $file=~/_inventory/i) {
$split_key = "Inventory::";
$object_prefix = "inventory:";
}
#::: Packet
if ($export=~/all|packet/i && $file=~/_packet/i) {
$split_key = "Packet::";
$object_prefix = "packet:";
}
#::: Quest
if ($export=~/all|quest/i && $file=~/lua_general/i) {
$split_key = " lua_";
$object_prefix = "eq.";
}
#::: Open File
print "\nOpening '" . $file . "'\n";
if ($split_key eq "") {
next;
}
open (FILE, $file);
while (<FILE>) {
chomp;
$line = $_;
@data = split(" ", $line);
if ((lc(substr($data[1], 0, 4)) eq "lua_") && $line!~/luabind/i && $line!~/return |#ifdef|struct /i) {
#::: Get return type
$return_type = trim($data[0]);
@method_split = split($split_key, $line);
@method_end = split("{", $method_split[1]);
$method = $object_prefix . trim($method_end[0]) . "; -- " . $return_type . "\n";
push @methods, $method;
}
}
#::: Header
$header = $split_key;
$header =~s/:://g;
print $fh "# " . $header . "\n";
print $fh "```lua\n";
@methods = sort @methods;
foreach $method (@methods) {
print $fh $method;
print $method;
}
print $fh "```\n\n";
}
close $fh;
#::: Trim Whitespaces
sub trim {
my $string = $_[0];
$string =~ s/^\s+//;
$string =~ s/\s+$//;
return $string;
}

View File

@ -1,179 +0,0 @@
#!/usr/bin/perl
# Author: Akkadius
# @file: perl-doc-parser.pl
# @description: Script meant to parse the source code to build the Perl API list
use File::Find;
use Data::Dumper;
sub usage() {
print "Usage:\n";
print " --client - Prints methods for just client class methods\n";
print " --mob - Prints methods for just mob class methods\n";
print " --npc - Prints methods for just npc class methods\n";
print " --entity - Prints methods for just entity class methods\n";
print " --door - Prints methods for just door class methods\n";
print " --object - Prints methods for just object class methods\n";
print " --group - Prints methods for just group class methods\n";
print " --raid - Prints methods for just raid class methods\n";
print " --questitem - Prints methods for just questitem class methods\n";
print " --corpse - Prints methods for just corpse class methods\n";
print " --hateentry - Prints methods for just hateentry class methods\n";
print " --quest - Prints methods for just quest class methods\n";
print " --all - Prints methods for all classes\n";
exit(1);
}
if($#ARGV < 0) {
usage();
}
my $export = $ARGV[0];
$export=~s/--//g;
my $export_file_search = $export;
if ($export eq "quest") {
$export_file_search = "embparser_api";
}
my @files;
my $start_dir = "zone/";
find(
sub { push @files, $File::Find::name unless -d; },
$start_dir
);
for my $file (@files) {
#::: Skip non Perl files
if($file!~/perl_|embparser_api/i){
next;
}
#::: If we are specifying a specific class type, skip everything else
if ($export ne "all" && $export ne "") {
if ($file!~/$export_file_search/i) {
next;
}
}
@methods = ();
$split_key = "";
$object_prefix = "";
#::: Open File
print "\nOpening '" . $file . "'\n";
open (FILE, $file);
while (<FILE>) {
chomp;
$line = $_;
if ($line=~/Perl_croak/i && $line=~/Usa/i && $line=~/::/i && $line!~/::new/i) {
#::: Client export
if ($export=~/all|client/i && $line=~/Client::/i) {
$split_key = "Client::";
$object_prefix = "\$client->";
}
#::: Mob export
if ($export=~/all|mob/i && $line=~/Mob::/i) {
$split_key = "Mob::";
$object_prefix = "\$mob->";
}
#::: NPC export
if ($export=~/all|npc/i && $line=~/NPC::/i) {
$split_key = "NPC::";
$object_prefix = "\$npc->";
}
#::: Corpse export
if ($export=~/all|corpse/i && $line=~/Corpse::/i) {
$split_key = "Corpse::";
$object_prefix = "\$corpse->";
}
#::: Entity export
if ($export=~/all|entity/i && $line=~/EntityList::/i) {
$split_key = "EntityList::";
$object_prefix = "\$entity_list->";
}
#::: Doors export
if ($export=~/all|door/i && $line=~/Doors::/i) {
$split_key = "Doors::";
$object_prefix = "\$door->";
}
#::: Object export
if ($export=~/all|object/i && $line=~/Object::/i) {
$split_key = "Object::";
$object_prefix = "\$object->";
}
#::: Group export
if ($export=~/all|group/i && $line=~/Group::/i) {
$split_key = "Group::";
$object_prefix = "\$group->";
}
#::: Raid export
if ($export=~/all|raid/i && $line=~/Raid::/i) {
$split_key = "Raid::";
$object_prefix = "\$raid->";
}
#::: Hateentry export
if ($export=~/all|hateentry/i && $line=~/HateEntry::/i) {
$split_key = "HateEntry::";
$object_prefix = "\$hate_entry->";
}
#::: Questitem export
if ($export=~/all|questitem/i && $line=~/QuestItem::/i) {
$split_key = "QuestItem::";
$object_prefix = "\$quest_item->";
}
#::: Quest:: exports
if ($export=~/all|quest/i && $line=~/quest::/i) {
$split_key = "quest::";
$object_prefix = "\quest::";
}
#::: Split on croak usage
@data = split($split_key, $line);
$usage = trim($data[1]);
#::: Split out param borders and get method name
@params_begin = split('\(', $usage);
$method_name = trim($params_begin[0]);
#::: Get params string built
@params_end = split('\)', $params_begin[1]);
$params_string = trim($params_end[0]);
$params_string =~s/THIS\,//g;
$params_string =~s/THIS//g;
$params_string = trim($params_string);
$method = $object_prefix . $method_name . "(" . lc($params_string) . ")\n";
push @methods, $method;
}
}
@methods = sort @methods;
foreach $method (@methods) {
print $method;
}
}
#::: Trim Whitespaces
sub trim {
my $string = $_[0];
$string =~ s/^\s+//;
$string =~ s/\s+$//;
return $string;
}

View File

@ -35,6 +35,7 @@
#include "../common/emu_versions.h"
#include "../common/random.h"
#include "../common/shareddb.h"
#include "../common/opcodemgr.h"
#include "client.h"
#include "worlddb.h"
@ -1009,7 +1010,13 @@ bool Client::HandlePacket(const EQApplicationPacket *app) {
EmuOpcode opcode = app->GetOpcode();
LogNetcode("Received EQApplicationPacket [{:#04x}]", opcode);
LogPacketClientServer(
"[{}] [{:#06x}] Size [{}] {}",
OpcodeManager::EmuToName(app->GetOpcode()),
eqs->GetOpcodeManager()->EmuToEQ(app->GetOpcode()),
app->Size(),
(LogSys.IsLogEnabled(Logs::Detail, Logs::PacketClientServer) ? DumpPacketToString(app) : "")
);
if (!eqs->CheckState(ESTABLISHED)) {
LogInfo("Client disconnected (net inactive on send)");

View File

@ -31,6 +31,11 @@ extern WorldConfig Config;
void WorldBoot::GMSayHookCallBackProcessWorld(uint16 log_category, std::string message)
{
// we don't want to loop up with chat messages
if (message.find("OP_SpecialMesg") != std::string::npos) {
return;
}
// Cut messages down to 4000 max to prevent client crash
if (!message.empty()) {
message = message.substr(0, 4000);

View File

@ -788,7 +788,6 @@ bool Client::SendAllPackets() {
if(eqs)
eqs->FastQueuePacket((EQApplicationPacket **)&cp->app, cp->ack_req);
clientpackets.pop_front();
Log(Logs::Moderate, Logs::PacketClientServer, "Transmitting a packet");
}
return true;
}

View File

@ -447,17 +447,13 @@ void ClearMappedOpcode(EmuOpcode op)
// client methods
int Client::HandlePacket(const EQApplicationPacket *app)
{
if (LogSys.log_settings[Logs::LogCategory::Netcode].is_category_enabled == 1) {
char buffer[64];
app->build_header_dump(buffer);
Log(Logs::Detail, Logs::PacketClientServer, "Dispatch opcode: %s", buffer);
}
if (LogSys.log_settings[Logs::PacketClientServer].is_category_enabled == 1)
Log(Logs::General, Logs::PacketClientServer, "[%s - 0x%04x] [Size: %u]", OpcodeManager::EmuToName(app->GetOpcode()), app->GetOpcode(), app->Size());
if (LogSys.log_settings[Logs::PacketClientServerWithDump].is_category_enabled == 1)
Log(Logs::General, Logs::PacketClientServerWithDump, "[%s - 0x%04x] [Size: %u] %s", OpcodeManager::EmuToName(app->GetOpcode()), app->GetOpcode(), app->Size(), DumpPacketToString(app).c_str());
LogPacketClientServer(
"[{}] [{:#06x}] Size [{}] {}",
OpcodeManager::EmuToName(app->GetOpcode()),
eqs->GetOpcodeManager()->EmuToEQ(app->GetOpcode()),
app->Size(),
(LogSys.IsLogEnabled(Logs::Detail, Logs::PacketClientServer) ? DumpPacketToString(app) : "")
);
EmuOpcode opcode = app->GetOpcode();
if (opcode == OP_AckPacket) {
@ -500,11 +496,6 @@ int Client::HandlePacket(const EQApplicationPacket *app)
args.push_back(const_cast<EQApplicationPacket*>(app));
parse->EventPlayer(EVENT_UNHANDLED_OPCODE, this, "", 0, &args);
if (LogSys.log_settings[Logs::PacketClientServerUnhandled].is_category_enabled == 1) {
char buffer[64];
app->build_header_dump(buffer);
Log(Logs::General, Logs::PacketClientServerUnhandled, "%s %s", buffer, DumpPacketToString(app).c_str());
}
break;
}

View File

@ -71,6 +71,11 @@ void command_logs(Client *c, const Seperator *sep)
break;
}
bool is_deprecated_category = Strings::Contains(fmt::format("{}", Logs::LogCategoryName[index]), "Deprecated");
if (is_deprecated_category) {
continue;
}
std::vector<std::string> gmsay;
for (int i = 0; i <= 3; i++) {
if (i == 2) {

View File

@ -322,6 +322,11 @@ public:
*/
static void GMSayHookCallBackProcess(uint16 log_category, std::string message)
{
// we don't want to loop up with chat messages
if (message.find("OP_SpecialMesg") != std::string::npos) {
return;
}
/**
* Cut messages down to 4000 max to prevent client crash
*/