mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-23 04:52:29 +00:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ca704c7f88 | |||
| ef6dfe0469 | |||
| d7e010a3ec | |||
| 85c3255568 | |||
| c6ddf300a4 | |||
| 42d6004467 | |||
| cabe06ea92 | |||
| 4abd9c1b40 | |||
| f72bbab0e9 | |||
| 9647a5b82c | |||
| 84a90cef23 | |||
| a8db057440 | |||
| 6d6cc8ca95 | |||
| 6694281f22 | |||
| 5dc093fe5e | |||
| 758774b0bf | |||
| 1958a12bc7 | |||
| 348094b881 | |||
| ba2ca5eada | |||
| 491b1edd12 |
@@ -20,3 +20,4 @@
|
||||
*.css text
|
||||
*.js text
|
||||
*.types text
|
||||
*.pdf binary
|
||||
|
||||
@@ -3,8 +3,8 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
linux:
|
||||
name: Linux
|
||||
@@ -25,6 +25,17 @@ jobs:
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y build-essential ninja-build ccache uuid-dev
|
||||
|
||||
- name: Restore vcpkg Cache
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: |
|
||||
build/vcpkg_installed
|
||||
submodules/vcpkg/downloads
|
||||
key: ${{ runner.os }}-vcpkg-${{ hashFiles('vcpkg.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-vcpkg-${{ hashFiles('vcpkg.json') }}-
|
||||
${{ runner.os }}-vcpkg-
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
cmake -S . -B build -G Ninja \
|
||||
@@ -47,6 +58,9 @@ jobs:
|
||||
windows:
|
||||
name: Windows
|
||||
runs-on: windows-latest
|
||||
env:
|
||||
VCPKG_DOWNLOADS: ${{ github.workspace }}\submodules\vcpkg\downloads
|
||||
VCPKG_BINARY_SOURCES: 'clear;files,${{ github.workspace }}\vcpkg_archives,readwrite'
|
||||
steps:
|
||||
- name: Checkout source
|
||||
uses: actions/checkout@v5
|
||||
@@ -55,12 +69,22 @@ jobs:
|
||||
|
||||
- name: Enable long paths
|
||||
run: git config --global core.longpaths true
|
||||
|
||||
|
||||
- name: Setup MSVC environment
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
uses: TheMrMilchmann/setup-msvc-dev@v4
|
||||
with:
|
||||
arch: x64
|
||||
|
||||
- name: Restore vcpkg Cache
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: |
|
||||
${{ env.VCPKG_DOWNLOADS }}
|
||||
${{ github.workspace }}/vcpkg_archives
|
||||
key: ${{ runner.os }}-vcpkg-${{ hashFiles('vcpkg.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-vcpkg-
|
||||
|
||||
- name: Configure
|
||||
shell: pwsh
|
||||
run: |
|
||||
|
||||
+3
-3
@@ -20,7 +20,7 @@ endif()
|
||||
|
||||
project(EQEmu
|
||||
VERSION 24.10.3
|
||||
LANGUAGES CXX
|
||||
LANGUAGES CXX
|
||||
)
|
||||
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
@@ -42,10 +42,10 @@ option(EQEMU_BUILD_PCH "Build with precompiled headers (Windows)" ON)
|
||||
|
||||
if(MSVC)
|
||||
add_compile_options(/bigobj)
|
||||
add_compile_definitions(_CRT_SECURE_NO_WARNINGS NOMINMAX CRASH_LOGGING _HAS_AUTO_PTR_ETC)
|
||||
add_compile_definitions(_CRT_SECURE_NO_WARNINGS NOMINMAX WIN32_LEAN_AND_MEAN CRASH_LOGGING)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
|
||||
|
||||
option(EQEMU_DISABLE_MSVC_WARNINGS "Disable MSVC compile warnings." ON)
|
||||
option(EQEMU_DISABLE_MSVC_WARNINGS "Disable MSVC compile warnings." OFF)
|
||||
if(EQEMU_DISABLE_MSVC_WARNINGS)
|
||||
add_compile_options(/W0 /wd4005 /wd4996 /nologo /Os)
|
||||
endif()
|
||||
|
||||
+66
-80
@@ -6,21 +6,22 @@ set(common_sources
|
||||
bodytypes.cpp
|
||||
classes.cpp
|
||||
cli/eqemu_command_handler.cpp
|
||||
compiler_macros.h
|
||||
compression.cpp
|
||||
condition.cpp
|
||||
content/world_content_service.cpp
|
||||
crash.cpp
|
||||
crc16.cpp
|
||||
crc32.cpp
|
||||
data_bucket.cpp
|
||||
data_bucket.cpp
|
||||
database_instances.cpp
|
||||
database.cpp
|
||||
database/database_dump_service.cpp
|
||||
database/database_update.cpp
|
||||
database_instances.cpp
|
||||
dbcore.cpp
|
||||
deity.cpp
|
||||
discord/discord.cpp
|
||||
discord/discord_manager.cpp
|
||||
discord/discord.cpp
|
||||
dynamic_zone_base.cpp
|
||||
dynamic_zone_lockout.cpp
|
||||
emu_constants.cpp
|
||||
@@ -31,13 +32,16 @@ set(common_sources
|
||||
eq_packet.cpp
|
||||
eq_stream_ident.cpp
|
||||
eq_stream_proxy.cpp
|
||||
eqdb.cpp
|
||||
eqdb_res.cpp
|
||||
eqdb.cpp
|
||||
eqemu_config.cpp
|
||||
eqemu_exception.cpp
|
||||
eqemu_logsys.cpp
|
||||
eqtime.cpp
|
||||
event_sub.cpp
|
||||
event/event_loop.cpp
|
||||
event/task_scheduler.cpp
|
||||
event/timer.cpp
|
||||
events/player_event_discord_formatter.cpp
|
||||
events/player_event_logs.cpp
|
||||
evolving_items.cpp
|
||||
@@ -51,62 +55,56 @@ set(common_sources
|
||||
ipc_mutex.cpp
|
||||
item_data.cpp
|
||||
item_instance.cpp
|
||||
json/json.hpp
|
||||
json/jsoncpp.cpp
|
||||
json_config.cpp
|
||||
json/jsoncpp.cpp
|
||||
light_source.cpp
|
||||
md5.cpp
|
||||
memory/ksm.hpp
|
||||
memory_buffer.cpp
|
||||
memory_mapped_file.cpp
|
||||
misc.cpp
|
||||
memory/ksm.cpp
|
||||
misc_functions.cpp
|
||||
mutex.cpp
|
||||
misc.cpp
|
||||
mysql_request_result.cpp
|
||||
mysql_request_row.cpp
|
||||
mysql_stmt.cpp
|
||||
net/console_server.cpp
|
||||
net/console_server_connection.cpp
|
||||
net/console_server.cpp
|
||||
net/crc32.cpp
|
||||
net/dns.cpp
|
||||
net/eqstream.cpp
|
||||
net/packet.cpp
|
||||
net/reliable_stream_connection.cpp
|
||||
net/servertalk_client_connection.cpp
|
||||
net/servertalk_legacy_client_connection.cpp
|
||||
net/servertalk_server.cpp
|
||||
net/servertalk_server_connection.cpp
|
||||
net/servertalk_server.cpp
|
||||
net/tcp_connection.cpp
|
||||
net/tcp_server.cpp
|
||||
net/websocket_server.cpp
|
||||
net/websocket_server_connection.cpp
|
||||
net/websocket_server.cpp
|
||||
opcode_map.cpp
|
||||
opcodemgr.cpp
|
||||
packet_dump.cpp
|
||||
packet_dump_file.cpp
|
||||
packet_dump.cpp
|
||||
packet_functions.cpp
|
||||
patches/patches.cpp
|
||||
patches/rof.cpp
|
||||
patches/rof2.cpp
|
||||
patches/rof2_limits.cpp
|
||||
patches/rof_limits.cpp
|
||||
patches/sod.cpp
|
||||
patches/rof.cpp
|
||||
patches/rof2_limits.cpp
|
||||
patches/rof2.cpp
|
||||
patches/sod_limits.cpp
|
||||
patches/sof.cpp
|
||||
patches/sod.cpp
|
||||
patches/sof_limits.cpp
|
||||
patches/titanium.cpp
|
||||
patches/sof.cpp
|
||||
patches/titanium_limits.cpp
|
||||
patches/uf.cpp
|
||||
patches/titanium.cpp
|
||||
patches/uf_limits.cpp
|
||||
patches/uf.cpp
|
||||
path_manager.cpp
|
||||
path_manager.cpp
|
||||
perl_eqdb.cpp
|
||||
perl_eqdb_res.cpp
|
||||
perl_eqdb.cpp
|
||||
platform.cpp
|
||||
platform/inet.h
|
||||
platform/platform.h
|
||||
platform/posix/include_inet.h
|
||||
platform/posix/include_pthreads.h
|
||||
platform/win/include_windows.h
|
||||
platform/win/include_winsock2.h
|
||||
proc_launcher.cpp
|
||||
process.cpp
|
||||
process/process.cpp
|
||||
@@ -123,12 +121,12 @@ set(common_sources
|
||||
shareddb.cpp
|
||||
skill_caps.cpp
|
||||
skills.cpp
|
||||
spdat.cpp
|
||||
spdat_bot.cpp
|
||||
spdat.cpp
|
||||
StackWalker/StackWalker.cpp
|
||||
strings.cpp
|
||||
strings_legacy.cpp
|
||||
strings_misc.cpp
|
||||
strings.cpp
|
||||
struct_strategy.cpp
|
||||
textures.cpp
|
||||
timer.cpp
|
||||
@@ -538,35 +536,32 @@ set(repositories
|
||||
)
|
||||
|
||||
set(common_headers
|
||||
StackWalker/StackWalker.h
|
||||
additive_lagged_fibonacci_engine.h
|
||||
base_packet.h
|
||||
bazaar.h
|
||||
bodytypes.h
|
||||
classes.h
|
||||
cli/argh.h
|
||||
cli/eqemu_command_handler.h
|
||||
cli/terminal_color.hpp
|
||||
classes.h
|
||||
compression.h
|
||||
condition.h
|
||||
content/world_content_service.h
|
||||
crash.h
|
||||
crc16.h
|
||||
crc32.h
|
||||
cron/croncpp.h
|
||||
data_bucket.cpp
|
||||
data_verification.h
|
||||
database_schema.h
|
||||
database.h
|
||||
database/database_dump_service.h
|
||||
database/database_update.h
|
||||
database/database_update_manifest.h
|
||||
database/database_update_manifest_bots.h
|
||||
database/database_update_manifest_custom.h
|
||||
database_schema.h
|
||||
database/database_update_manifest.h
|
||||
database/database_update.h
|
||||
dbcore.h
|
||||
deity.h
|
||||
discord/discord.h
|
||||
discord/discord_manager.h
|
||||
discord/discord.h
|
||||
dynamic_zone_base.h
|
||||
dynamic_zone_lockout.h
|
||||
emu_constants.h
|
||||
@@ -576,24 +571,24 @@ set(common_headers
|
||||
emu_versions.h
|
||||
eq_constants.h
|
||||
eq_limits.h
|
||||
eq_packet.h
|
||||
eq_packet_structs.h
|
||||
eq_packet.h
|
||||
eq_stream_ident.h
|
||||
eq_stream_intf.h
|
||||
eq_stream_locator.h
|
||||
eq_stream_proxy.h
|
||||
eqdb.h
|
||||
eqdb_res.h
|
||||
eqemu_config.h
|
||||
eqdb.h
|
||||
eqemu_config_elements.h
|
||||
eqemu_config.h
|
||||
eqemu_exception.h
|
||||
eqemu_logsys.h
|
||||
eqemu_logsys_log_aliases.h
|
||||
eqemu_logsys.h
|
||||
eqtime.h
|
||||
event_sub.h
|
||||
event/event_loop.h
|
||||
event/task.h
|
||||
event/timer.h
|
||||
event_sub.h
|
||||
events/player_event_discord_formatter.h
|
||||
events/player_event_logs.h
|
||||
events/player_events.h
|
||||
@@ -614,10 +609,11 @@ set(common_headers
|
||||
ipc_mutex.h
|
||||
item_data.h
|
||||
item_instance.h
|
||||
json_config.h
|
||||
json/json_archive_single_line.h
|
||||
json/json-forwards.h
|
||||
json/json.h
|
||||
json/json_archive_single_line.h
|
||||
json_config.h
|
||||
json/json.hpp
|
||||
light_source.h
|
||||
linked_list.h
|
||||
loot.h
|
||||
@@ -625,14 +621,14 @@ set(common_headers
|
||||
md5.h
|
||||
memory_buffer.h
|
||||
memory_mapped_file.h
|
||||
misc.h
|
||||
memory/ksm.h
|
||||
misc_functions.h
|
||||
mutex.h
|
||||
misc.h
|
||||
mysql_request_result.h
|
||||
mysql_request_row.h
|
||||
mysql_stmt.h
|
||||
net/console_server.h
|
||||
net/console_server_connection.h
|
||||
net/console_server.h
|
||||
net/crc32.h
|
||||
net/dns.h
|
||||
net/endian.h
|
||||
@@ -644,49 +640,54 @@ set(common_headers
|
||||
net/servertalk_client_connection.h
|
||||
net/servertalk_common.h
|
||||
net/servertalk_legacy_client_connection.h
|
||||
net/servertalk_server.h
|
||||
net/servertalk_server_connection.h
|
||||
net/tcp_connection.h
|
||||
net/servertalk_server.h
|
||||
net/tcp_connection_pooling.h
|
||||
net/tcp_connection.h
|
||||
net/tcp_server.h
|
||||
net/websocket_server.h
|
||||
net/websocket_server_connection.h
|
||||
net/websocket_server.h
|
||||
op_codes.h
|
||||
opcode_dispatch.h
|
||||
opcodemgr.h
|
||||
packet_dump.h
|
||||
packet_dump_file.h
|
||||
packet_dump.h
|
||||
packet_functions.h
|
||||
patches/patches.h
|
||||
patches/rof.h
|
||||
patches/rof2.h
|
||||
patches/rof2_limits.h
|
||||
patches/rof2_ops.h
|
||||
patches/rof2_structs.h
|
||||
patches/rof_limits.h
|
||||
patches/rof_ops.h
|
||||
patches/rof_structs.h
|
||||
patches/sod.h
|
||||
patches/rof.h
|
||||
patches/rof2_limits.h
|
||||
patches/rof2_ops.h
|
||||
patches/rof2_structs.h
|
||||
patches/rof2.h
|
||||
patches/sod_limits.h
|
||||
patches/sod_ops.h
|
||||
patches/sod_structs.h
|
||||
patches/sof.h
|
||||
patches/sod.h
|
||||
patches/sof_limits.h
|
||||
patches/sof_ops.h
|
||||
patches/sof_structs.h
|
||||
patches/sof.h
|
||||
patches/ss_declare.h
|
||||
patches/ss_define.h
|
||||
patches/ss_register.h
|
||||
patches/titanium.h
|
||||
patches/titanium_limits.h
|
||||
patches/titanium_ops.h
|
||||
patches/titanium_structs.h
|
||||
patches/uf.h
|
||||
patches/titanium.h
|
||||
patches/uf_limits.h
|
||||
patches/uf_ops.h
|
||||
patches/uf_structs.h
|
||||
path_manager.cpp
|
||||
patches/uf.h
|
||||
platform.h
|
||||
platform/inet.h
|
||||
platform/platform.h
|
||||
platform/posix/include_inet.h
|
||||
platform/posix/include_pthreads.h
|
||||
platform/win/include_windows.h
|
||||
platform/win/include_winsock2.h
|
||||
proc_launcher.h
|
||||
process.h
|
||||
process/process.h
|
||||
@@ -713,6 +714,7 @@ set(common_headers
|
||||
skills.h
|
||||
spdat.h
|
||||
stacktrace/backward.hpp
|
||||
StackWalker/StackWalker.h
|
||||
strings.h
|
||||
struct_strategy.h
|
||||
tasks.h
|
||||
@@ -729,25 +731,9 @@ set(common_headers
|
||||
zone_store.h
|
||||
)
|
||||
|
||||
# Source Groups (Regex based for automatic subdirectory handling)
|
||||
source_group("CLI" REGULAR_EXPRESSION "^cli/")
|
||||
source_group("Content" REGULAR_EXPRESSION "^content/")
|
||||
source_group("Cron" REGULAR_EXPRESSION "^cron/")
|
||||
source_group("Database" REGULAR_EXPRESSION "^database/")
|
||||
source_group("Discord" REGULAR_EXPRESSION "^discord/")
|
||||
source_group("Event" REGULAR_EXPRESSION "^event/")
|
||||
source_group("Events" REGULAR_EXPRESSION "^events/")
|
||||
source_group("Http" REGULAR_EXPRESSION "^http/")
|
||||
source_group("Json" REGULAR_EXPRESSION "^json/")
|
||||
source_group("Memory" REGULAR_EXPRESSION "^memory/")
|
||||
source_group("Net" REGULAR_EXPRESSION "^net/")
|
||||
source_group("Patches" REGULAR_EXPRESSION "^patches/")
|
||||
source_group("Process" REGULAR_EXPRESSION "^process/")
|
||||
source_group("Repositories" REGULAR_EXPRESSION "^repositories/")
|
||||
source_group("StackWalker" REGULAR_EXPRESSION "^StackWalker/")
|
||||
source_group("Stacktrace" REGULAR_EXPRESSION "^stacktrace/")
|
||||
source_group("Termcolor" REGULAR_EXPRESSION "^termcolor/")
|
||||
source_group("Util" REGULAR_EXPRESSION "^util/")
|
||||
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" PREFIX "Source Files" FILES ${common_sources})
|
||||
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" PREFIX "Header Files" FILES ${common_headers})
|
||||
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}/repositories" PREFIX "Repositories" FILES ${repositories})
|
||||
|
||||
option(EQEMU_ADD_PROFILER "Link with Google perftools profiler" OFF)
|
||||
#PRNG options
|
||||
|
||||
@@ -359,7 +359,7 @@ public:
|
||||
BOOL Publics; // contains public symbols
|
||||
};
|
||||
*/
|
||||
typedef struct IMAGEHLP_MODULE64_V2 {
|
||||
struct IMAGEHLP_MODULE64_V2 {
|
||||
DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64)
|
||||
DWORD64 BaseOfImage; // base load address of module
|
||||
DWORD ImageSize; // virtual size of the loaded module
|
||||
|
||||
@@ -134,7 +134,7 @@ protected:
|
||||
CHAR loadedImageName[STACKWALK_MAX_NAMELEN];
|
||||
} CallstackEntry;
|
||||
|
||||
typedef enum CallstackEntryType {firstEntry, nextEntry, lastEntry};
|
||||
enum CallstackEntryType {firstEntry, nextEntry, lastEntry};
|
||||
|
||||
virtual void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName);
|
||||
virtual void OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion);
|
||||
|
||||
+14
-24
@@ -19,44 +19,34 @@
|
||||
#include "common/misc.h"
|
||||
#include "common/packet_dump.h"
|
||||
|
||||
BasePacket::BasePacket(const unsigned char *buf, uint32 len)
|
||||
BasePacket::BasePacket(const unsigned char* buf, size_t len)
|
||||
{
|
||||
pBuffer=nullptr;
|
||||
size=0;
|
||||
_wpos = 0;
|
||||
_rpos = 0;
|
||||
timestamp.tv_sec = 0;
|
||||
if (len>0) {
|
||||
size=len;
|
||||
pBuffer= new unsigned char[len];
|
||||
if (len > 0) {
|
||||
size = static_cast<uint32>(len);
|
||||
pBuffer = new unsigned char[len];
|
||||
if (buf) {
|
||||
memcpy(pBuffer,buf,len);
|
||||
} else {
|
||||
memset(pBuffer,0,len);
|
||||
memcpy(pBuffer, buf, len);
|
||||
}
|
||||
else {
|
||||
memset(pBuffer, 0, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BasePacket::BasePacket(SerializeBuffer &buf)
|
||||
BasePacket::BasePacket(SerializeBuffer&& buf)
|
||||
: pBuffer(std::exchange(buf.m_buffer, nullptr))
|
||||
{
|
||||
pBuffer = buf.m_buffer;
|
||||
buf.m_buffer = nullptr;
|
||||
size = buf.m_pos;
|
||||
buf.m_pos = 0;
|
||||
// We are essentially taking ownership of this serialize buffer.
|
||||
size = static_cast<uint32>(std::exchange(buf.m_pos, 0));
|
||||
buf.m_capacity = 0;
|
||||
_wpos = 0;
|
||||
_rpos = 0;
|
||||
timestamp.tv_sec = 0;
|
||||
}
|
||||
|
||||
BasePacket::~BasePacket()
|
||||
{
|
||||
if (pBuffer)
|
||||
delete[] pBuffer;
|
||||
pBuffer=nullptr;
|
||||
delete[] pBuffer;
|
||||
pBuffer = nullptr;
|
||||
}
|
||||
|
||||
|
||||
void BasePacket::build_raw_header_dump(char *buffer, uint16 seq) const
|
||||
{
|
||||
if (timestamp.tv_sec) {
|
||||
|
||||
+21
-15
@@ -23,14 +23,26 @@
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
class BasePacket {
|
||||
class BasePacket
|
||||
{
|
||||
protected:
|
||||
BasePacket() = default;
|
||||
BasePacket(const unsigned char* buf, size_t len);
|
||||
BasePacket(SerializeBuffer&& buf);
|
||||
|
||||
virtual ~BasePacket();
|
||||
|
||||
public:
|
||||
unsigned char *pBuffer;
|
||||
uint32 size, _wpos, _rpos;
|
||||
uint32 src_ip,dst_ip;
|
||||
uint16 src_port,dst_port;
|
||||
uint32 priority;
|
||||
timeval timestamp;
|
||||
unsigned char* pBuffer = nullptr;
|
||||
uint32 size = 0;
|
||||
uint32 _wpos = 0;
|
||||
uint32 _rpos = 0;
|
||||
uint32 src_ip = 0;
|
||||
uint32 dst_ip = 0;
|
||||
uint16 src_port = 0;
|
||||
uint16 dst_port = 0;
|
||||
uint32 priority = 0;
|
||||
timeval timestamp{};
|
||||
|
||||
virtual void build_raw_header_dump(char *buffer, uint16 seq=0xffff) const;
|
||||
virtual void build_header_dump(char *buffer) const;
|
||||
@@ -40,11 +52,11 @@ public:
|
||||
|
||||
void setSrcInfo(uint32 sip, uint16 sport) { src_ip=sip; src_port=sport; }
|
||||
void setDstInfo(uint32 dip, uint16 dport) { dst_ip=dip; dst_port=dport; }
|
||||
void setTimeInfo(uint32 ts_sec, uint32 ts_usec) { timestamp.tv_sec=ts_sec; timestamp.tv_usec=ts_usec; }
|
||||
void setTimeInfo(uint32 ts_sec, uint32 ts_usec) { timestamp.tv_sec = ts_sec; timestamp.tv_usec = ts_usec; }
|
||||
void copyInfo(const BasePacket *p) { src_ip=p->src_ip; src_port=p->src_port; dst_ip=p->dst_ip; dst_port=p->dst_port; timestamp.tv_sec=p->timestamp.tv_sec; timestamp.tv_usec=p->timestamp.tv_usec; }
|
||||
|
||||
inline bool operator<(const BasePacket &rhs) {
|
||||
return (timestamp.tv_sec < rhs.timestamp.tv_sec || (timestamp.tv_sec==rhs.timestamp.tv_sec && timestamp.tv_usec < rhs.timestamp.tv_usec));
|
||||
return (timestamp.tv_sec < rhs.timestamp.tv_sec || (timestamp.tv_sec == rhs.timestamp.tv_sec && timestamp.tv_usec < rhs.timestamp.tv_usec));
|
||||
}
|
||||
|
||||
void WriteUInt8(uint8 value) { *(uint8 *)(pBuffer + _wpos) = value; _wpos += sizeof(uint8); }
|
||||
@@ -73,12 +85,6 @@ public:
|
||||
uint32 GetReadPosition() { return _rpos; }
|
||||
void SetWritePosition(uint32 Newwpos) { _wpos = Newwpos; }
|
||||
void SetReadPosition(uint32 Newrpos) { _rpos = Newrpos; }
|
||||
|
||||
protected:
|
||||
virtual ~BasePacket();
|
||||
BasePacket() { pBuffer=nullptr; size=0; _wpos = 0; _rpos = 0; }
|
||||
BasePacket(const unsigned char *buf, const uint32 len);
|
||||
BasePacket(SerializeBuffer &buf);
|
||||
};
|
||||
|
||||
extern void DumpPacketHex(const BasePacket* app);
|
||||
|
||||
@@ -23,12 +23,9 @@
|
||||
|
||||
namespace EQEmuCommand {
|
||||
|
||||
std::map<std::string, void (*)(
|
||||
int argc,
|
||||
char **argv,
|
||||
argh::parser &cmd,
|
||||
std::string &description
|
||||
)> function_map;
|
||||
using CommandFunction = void(*)(int argc, char** argv, argh::parser& cmd, std::string& description);
|
||||
|
||||
std::map<std::string, CommandFunction> function_map;
|
||||
|
||||
/**
|
||||
* @param cmd
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
# include <unistd.h>
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
# include <io.h>
|
||||
# include <windows.h>
|
||||
# include "common/platform/win/include_windows.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define PUSH_DISABLE_DEPRECATED_WARNINGS() __pragma(warning(push)) \
|
||||
__pragma(warning(disable:4996))
|
||||
#define POP_DISABLE_DEPRECATED_WARNINGS() __pragma(warning(pop))
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
#define PUSH_DISABLE_DEPRECATED_WARNINGS() _Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
|
||||
#define POP_DISABLE_DEPRECATED_WARNINGS() _Pragma("GCC diagnostic pop")
|
||||
#else
|
||||
#define PUSH_DISABLE_DEPRECATED_WARNINGS()
|
||||
#define POP_DISABLE_DEPRECATED_WARNINGS()
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#define UNREACHABLE() __assume(0)
|
||||
#else
|
||||
#define UNREACHABLE() __builtin_unreachable()
|
||||
#endif
|
||||
@@ -1,146 +0,0 @@
|
||||
/* EQEmu: EQEmulator
|
||||
|
||||
Copyright (C) 2001-2026 EQEmu Development Team
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "condition.h"
|
||||
|
||||
#ifdef _WINDOWS
|
||||
|
||||
Condition::Condition()
|
||||
{
|
||||
m_events[SignalEvent] = CreateEvent (nullptr, // security
|
||||
FALSE, // is auto-reset event?
|
||||
FALSE, // is signaled initially?
|
||||
nullptr); // name
|
||||
m_events[BroadcastEvent] = CreateEvent (nullptr, // security
|
||||
TRUE, // is auto-reset event?
|
||||
FALSE, // is signaled initially?
|
||||
nullptr); // name
|
||||
m_waiters = 0;
|
||||
InitializeCriticalSection(&CSMutex);
|
||||
}
|
||||
|
||||
Condition::~Condition()
|
||||
{
|
||||
DeleteCriticalSection(&CSMutex);
|
||||
CloseHandle(m_events[SignalEvent]);
|
||||
CloseHandle(m_events[BroadcastEvent]);
|
||||
}
|
||||
|
||||
void Condition::Signal()
|
||||
{
|
||||
EnterCriticalSection(&CSMutex);
|
||||
if(m_waiters > 0)
|
||||
SetEvent(m_events[SignalEvent]);
|
||||
LeaveCriticalSection(&CSMutex);
|
||||
}
|
||||
|
||||
void Condition::SignalAll()
|
||||
{
|
||||
EnterCriticalSection(&CSMutex);
|
||||
if(m_waiters > 0)
|
||||
SetEvent(m_events[BroadcastEvent]);
|
||||
LeaveCriticalSection(&CSMutex);
|
||||
}
|
||||
|
||||
void Condition::Wait()
|
||||
{
|
||||
EnterCriticalSection(&CSMutex);
|
||||
|
||||
m_waiters++;
|
||||
|
||||
|
||||
LeaveCriticalSection(&CSMutex);
|
||||
int result = WaitForMultipleObjects (_eventCount, m_events, FALSE, INFINITE);
|
||||
EnterCriticalSection(&CSMutex);
|
||||
|
||||
m_waiters--;
|
||||
|
||||
//see if we are the last person waiting on the condition, and there was a broadcast
|
||||
//if so, we need to reset the broadcast event.
|
||||
if(m_waiters == 0 && result == (WAIT_OBJECT_0+BroadcastEvent))
|
||||
ResetEvent(m_events[BroadcastEvent]);
|
||||
|
||||
LeaveCriticalSection(&CSMutex);
|
||||
}
|
||||
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#include <sys/time.h>
|
||||
#include <errno.h>
|
||||
|
||||
Condition::Condition()
|
||||
{
|
||||
pthread_cond_init(&cond,nullptr);
|
||||
pthread_mutex_init(&mutex,nullptr);
|
||||
}
|
||||
|
||||
void Condition::Signal()
|
||||
{
|
||||
pthread_mutex_lock(&mutex);
|
||||
pthread_cond_signal(&cond);
|
||||
pthread_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
void Condition::SignalAll()
|
||||
{
|
||||
pthread_mutex_lock(&mutex);
|
||||
pthread_cond_broadcast(&cond);
|
||||
pthread_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
void Condition::Wait()
|
||||
{
|
||||
pthread_mutex_lock(&mutex);
|
||||
pthread_cond_wait(&cond,&mutex);
|
||||
pthread_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
I commented this specifically because I think it might be very
|
||||
difficult to write a windows counterpart to it, so I would like
|
||||
to discourage its use until we can confirm that it can be reasonably
|
||||
implemented on windows.
|
||||
|
||||
bool Condition::TimedWait(unsigned long usec)
|
||||
{
|
||||
struct timeval now;
|
||||
struct timespec timeout;
|
||||
int retcode=0;
|
||||
pthread_mutex_lock(&mutex);
|
||||
gettimeofday(&now,nullptr);
|
||||
now.tv_usec+=usec;
|
||||
timeout.tv_sec = now.tv_sec + (now.tv_usec/1000000);
|
||||
timeout.tv_nsec = (now.tv_usec%1000000) *1000;
|
||||
//cout << "now=" << now.tv_sec << "."<<now.tv_usec << endl;
|
||||
//cout << "timeout=" << timeout.tv_sec << "."<<timeout.tv_nsec << endl;
|
||||
retcode=pthread_cond_timedwait(&cond,&mutex,&timeout);
|
||||
pthread_mutex_unlock(&mutex);
|
||||
|
||||
return retcode!=ETIMEDOUT;
|
||||
}
|
||||
*/
|
||||
|
||||
Condition::~Condition()
|
||||
{
|
||||
pthread_mutex_lock(&mutex);
|
||||
pthread_cond_destroy(&cond);
|
||||
pthread_mutex_unlock(&mutex);
|
||||
pthread_mutex_destroy(&mutex);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
/* EQEmu: EQEmulator
|
||||
|
||||
Copyright (C) 2001-2026 EQEmu Development Team
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "common/mutex.h"
|
||||
#include "common/platform/posix/include_pthreads.h"
|
||||
#include "common/platform/win/include_windows.h"
|
||||
|
||||
//Sombody, someday needs to figure out how to implement a condition
|
||||
//system on windows...
|
||||
|
||||
|
||||
class Condition {
|
||||
private:
|
||||
#ifdef WIN32
|
||||
enum {
|
||||
SignalEvent = 0,
|
||||
BroadcastEvent,
|
||||
_eventCount
|
||||
};
|
||||
|
||||
HANDLE m_events[_eventCount];
|
||||
uint32 m_waiters;
|
||||
CRITICAL_SECTION CSMutex;
|
||||
#else
|
||||
pthread_cond_t cond;
|
||||
pthread_mutex_t mutex;
|
||||
#endif
|
||||
public:
|
||||
Condition();
|
||||
void Signal();
|
||||
void SignalAll();
|
||||
void Wait();
|
||||
// bool TimedWait(unsigned long usec);
|
||||
~Condition();
|
||||
};
|
||||
@@ -132,7 +132,7 @@ void WorldContentService::SetContentFlags(const std::vector<ContentFlagsReposito
|
||||
bool WorldContentService::IsContentFlagEnabled(const std::string &content_flag)
|
||||
{
|
||||
for (auto &f: GetContentFlags()) {
|
||||
if (f.flag_name == content_flag && f.enabled == true) {
|
||||
if (f.flag_name == content_flag && f.enabled == 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -147,7 +147,7 @@ bool WorldContentService::IsContentFlagEnabled(const std::string &content_flag)
|
||||
bool WorldContentService::IsContentFlagDisabled(const std::string &content_flag)
|
||||
{
|
||||
for (auto &f: GetContentFlags()) {
|
||||
if (f.flag_name == content_flag && f.enabled == false) {
|
||||
if (f.flag_name == content_flag && f.enabled == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -125,6 +125,6 @@ uint32 CRC32::Update(const uint8* buf, uint32 bufsize, uint32 crc32var) {
|
||||
return crc32var;
|
||||
}
|
||||
|
||||
inline void CRC32::Calc(const uint8 byte, uint32& crc32var) {
|
||||
void CRC32::Calc(const uint8 byte, uint32& crc32var) {
|
||||
crc32var = ((crc32var) >> 8) ^ CRC32Table[(byte) ^ ((crc32var) & 0x000000FF)];
|
||||
}
|
||||
|
||||
+2
-2
@@ -728,7 +728,7 @@ bool Database::LoadVariables()
|
||||
return true;
|
||||
}
|
||||
|
||||
LockMutex lock(&Mvarcache);
|
||||
std::scoped_lock lock(Mvarcache);
|
||||
|
||||
for (const auto& e : l) {
|
||||
varcache.last_update = std::time(nullptr);
|
||||
@@ -747,7 +747,7 @@ bool Database::LoadVariables()
|
||||
|
||||
bool Database::GetVariable(const std::string& name, std::string& value)
|
||||
{
|
||||
LockMutex lock(&Mvarcache);
|
||||
std::scoped_lock lock(Mvarcache);
|
||||
|
||||
if (name.empty()) {
|
||||
return false;
|
||||
|
||||
+3
-4
@@ -20,13 +20,12 @@
|
||||
#include "common/dbcore.h"
|
||||
#include "common/eq_packet_structs.h"
|
||||
#include "common/eqemu_logsys.h"
|
||||
#include "common/linked_list.h"
|
||||
#include "common/types.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#define AUTHENTICATION_TIMEOUT 60
|
||||
#define INVALID_ID 0xFFFFFFFF
|
||||
@@ -265,7 +264,7 @@ public:
|
||||
uint64_t GetNextTableId(const std::string& table_name);
|
||||
|
||||
private:
|
||||
Mutex Mvarcache;
|
||||
std::mutex Mvarcache;
|
||||
VarCache_Struct varcache;
|
||||
|
||||
/* Groups, utility methods. */
|
||||
|
||||
+23
-40
@@ -33,17 +33,9 @@
|
||||
#endif
|
||||
|
||||
DBcore::DBcore()
|
||||
: mysql(mysql_init(nullptr))
|
||||
, m_mutex(std::make_shared<Mutex>())
|
||||
{
|
||||
mysql = mysql_init(nullptr);
|
||||
mysqlOwner = true;
|
||||
pHost = nullptr;
|
||||
pUser = nullptr;
|
||||
pPassword = nullptr;
|
||||
pDatabase = nullptr;
|
||||
pCompress = false;
|
||||
pSSL = false;
|
||||
pStatus = Closed;
|
||||
m_mutex = new Mutex;
|
||||
}
|
||||
|
||||
DBcore::~DBcore()
|
||||
@@ -56,20 +48,17 @@ DBcore::~DBcore()
|
||||
if (mysqlOwner) {
|
||||
mysql_close(mysql);
|
||||
}
|
||||
|
||||
safe_delete_array(pHost);
|
||||
safe_delete_array(pUser);
|
||||
safe_delete_array(pPassword);
|
||||
safe_delete_array(pDatabase);
|
||||
}
|
||||
|
||||
// Sends the MySQL server a keepalive
|
||||
void DBcore::ping()
|
||||
{
|
||||
if (!m_mutex->trylock()) {
|
||||
if (!m_mutex->try_lock())
|
||||
{
|
||||
// well, if's it's locked, someone's using it. If someone's using it, it doesnt need a keepalive
|
||||
return;
|
||||
}
|
||||
|
||||
mysql_ping(mysql);
|
||||
m_mutex->unlock();
|
||||
}
|
||||
@@ -92,7 +81,7 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo
|
||||
BenchTimer timer;
|
||||
timer.reset();
|
||||
|
||||
LockMutex lock(m_mutex);
|
||||
std::scoped_lock lock(*m_mutex);
|
||||
|
||||
// Reconnect if we are not connected before hand.
|
||||
if (pStatus != Connected) {
|
||||
@@ -217,15 +206,12 @@ bool DBcore::Open(
|
||||
bool iSSL
|
||||
)
|
||||
{
|
||||
LockMutex lock(m_mutex);
|
||||
safe_delete_array(pHost);
|
||||
safe_delete_array(pUser);
|
||||
safe_delete_array(pPassword);
|
||||
safe_delete_array(pDatabase);
|
||||
pHost = strcpy(new char[strlen(iHost) + 1], iHost);
|
||||
pUser = strcpy(new char[strlen(iUser) + 1], iUser);
|
||||
pPassword = strcpy(new char[strlen(iPassword) + 1], iPassword);
|
||||
pDatabase = strcpy(new char[strlen(iDatabase) + 1], iDatabase);
|
||||
std::scoped_lock lock(*m_mutex);
|
||||
|
||||
m_host = iHost;
|
||||
m_user = iUser;
|
||||
m_password = iPassword;
|
||||
m_database = iDatabase;
|
||||
pCompress = iCompress;
|
||||
pPort = iPort;
|
||||
pSSL = iSSL;
|
||||
@@ -234,10 +220,12 @@ bool DBcore::Open(
|
||||
|
||||
bool DBcore::Open(uint32 *errnum, char *errbuf)
|
||||
{
|
||||
// Expects m_mutex to already be locked.
|
||||
|
||||
if (errbuf) {
|
||||
errbuf[0] = 0;
|
||||
}
|
||||
LockMutex lock(m_mutex);
|
||||
|
||||
if (GetStatus() == Connected) {
|
||||
return true;
|
||||
}
|
||||
@@ -245,7 +233,7 @@ bool DBcore::Open(uint32 *errnum, char *errbuf)
|
||||
mysql_close(mysql);
|
||||
mysql_init(mysql); // Initialize structure again
|
||||
}
|
||||
if (!pHost) {
|
||||
if (m_host.empty()) {
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
@@ -268,11 +256,10 @@ bool DBcore::Open(uint32 *errnum, char *errbuf)
|
||||
mysql_options(mysql, MYSQL_OPT_SSL_ENFORCE, &off);
|
||||
mysql_options(mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, &off);
|
||||
}
|
||||
if (mysql_real_connect(mysql, pHost, pUser, pPassword, pDatabase, pPort, 0, flags)) {
|
||||
if (mysql_real_connect(mysql, m_host.c_str(), m_user.c_str(), m_password.c_str(), m_database.c_str(), pPort, nullptr, flags)) {
|
||||
pStatus = Connected;
|
||||
|
||||
std::string connected_origin_host = pHost;
|
||||
SetOriginHost(connected_origin_host);
|
||||
SetOriginHost(m_host);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -293,9 +280,9 @@ const std::string &DBcore::GetOriginHost() const
|
||||
return origin_host;
|
||||
}
|
||||
|
||||
void DBcore::SetOriginHost(const std::string &origin_host)
|
||||
void DBcore::SetOriginHost(const std::string& originHost)
|
||||
{
|
||||
DBcore::origin_host = origin_host;
|
||||
DBcore::origin_host = originHost;
|
||||
}
|
||||
|
||||
std::string DBcore::Escape(const std::string& s)
|
||||
@@ -307,12 +294,8 @@ std::string DBcore::Escape(const std::string& s)
|
||||
return temp.data();
|
||||
}
|
||||
|
||||
void DBcore::SetMutex(Mutex *mutex)
|
||||
void DBcore::SetMutex(const std::shared_ptr<Mutex>& mutex)
|
||||
{
|
||||
if (m_mutex && m_mutex != mutex) {
|
||||
safe_delete(m_mutex);
|
||||
}
|
||||
|
||||
DBcore::m_mutex = mutex;
|
||||
}
|
||||
|
||||
@@ -326,7 +309,7 @@ MySQLRequestResult DBcore::QueryDatabaseMulti(const std::string &query)
|
||||
BenchTimer timer;
|
||||
timer.reset();
|
||||
|
||||
LockMutex lock(m_mutex);
|
||||
std::scoped_lock lock(*m_mutex);
|
||||
|
||||
// Reconnect if we are not connected before hand.
|
||||
if (pStatus != Connected) {
|
||||
@@ -449,5 +432,5 @@ MySQLRequestResult DBcore::QueryDatabaseMulti(const std::string &query)
|
||||
|
||||
mysql::PreparedStmt DBcore::Prepare(std::string query)
|
||||
{
|
||||
return mysql::PreparedStmt(*mysql, std::move(query), m_mutex);
|
||||
return mysql::PreparedStmt(*mysql, std::move(query), *m_mutex);
|
||||
}
|
||||
|
||||
+20
-18
@@ -17,11 +17,11 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "common/mutex.h"
|
||||
#include "common/mysql_request_result.h"
|
||||
#include "common/types.h"
|
||||
|
||||
#include "mysql.h"
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
#define CR_SERVER_GONE_ERROR 2006
|
||||
@@ -29,12 +29,15 @@
|
||||
|
||||
namespace mysql { class PreparedStmt; }
|
||||
|
||||
class DBcore {
|
||||
class DBcore
|
||||
{
|
||||
public:
|
||||
enum eStatus {
|
||||
Closed, Connected, Error
|
||||
};
|
||||
|
||||
using Mutex = std::recursive_mutex;
|
||||
|
||||
DBcore();
|
||||
~DBcore();
|
||||
eStatus GetStatus() { return pStatus; }
|
||||
@@ -48,17 +51,17 @@ public:
|
||||
uint32 DoEscapeString(char *tobuf, const char *frombuf, uint32 fromlen);
|
||||
void ping();
|
||||
|
||||
const std::string &GetOriginHost() const;
|
||||
void SetOriginHost(const std::string &origin_host);
|
||||
const std::string& GetOriginHost() const;
|
||||
void SetOriginHost(const std::string& origin_host);
|
||||
|
||||
bool DoesTableExist(const std::string& table_name);
|
||||
|
||||
void SetMySQL(const DBcore &o)
|
||||
void SetMySQL(const DBcore& o)
|
||||
{
|
||||
mysql = o.mysql;
|
||||
mysqlOwner = false;
|
||||
}
|
||||
void SetMutex(Mutex *mutex);
|
||||
void SetMutex(const std::shared_ptr<Mutex>& mutex);
|
||||
|
||||
// only safe on connections shared with other threads if results buffered
|
||||
// unsafe to use off main thread due to internal server logging
|
||||
@@ -81,22 +84,21 @@ protected:
|
||||
private:
|
||||
bool Open(uint32 *errnum = nullptr, char *errbuf = nullptr);
|
||||
|
||||
MYSQL* mysql;
|
||||
bool mysqlOwner;
|
||||
Mutex *m_mutex;
|
||||
eStatus pStatus;
|
||||
MYSQL* mysql = nullptr;
|
||||
bool mysqlOwner = true;
|
||||
eStatus pStatus = Closed;
|
||||
|
||||
std::mutex m_query_lock{};
|
||||
std::shared_ptr<Mutex> m_mutex;
|
||||
|
||||
std::string origin_host;
|
||||
|
||||
char *pHost;
|
||||
char *pUser;
|
||||
char *pPassword;
|
||||
char *pDatabase;
|
||||
bool pCompress;
|
||||
uint32 pPort;
|
||||
bool pSSL;
|
||||
std::string m_host;
|
||||
std::string m_user;
|
||||
std::string m_password;
|
||||
std::string m_database;
|
||||
bool pCompress = false;
|
||||
uint32 pPort = 0;
|
||||
bool pSSL = false;
|
||||
|
||||
// allows multiple queries to be executed within the same query
|
||||
// do not use this under normal operation
|
||||
|
||||
@@ -376,6 +376,7 @@ N(OP_MercenaryDismiss),
|
||||
N(OP_MercenaryHire),
|
||||
N(OP_MercenarySuspendRequest),
|
||||
N(OP_MercenarySuspendResponse),
|
||||
N(OP_MercenarySwitch),
|
||||
N(OP_MercenaryTimer),
|
||||
N(OP_MercenaryTimerRequest),
|
||||
N(OP_MercenaryUnknown1),
|
||||
|
||||
+20
-11
@@ -31,9 +31,19 @@
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
||||
EQPacket::EQPacket(EmuOpcode op, const unsigned char *buf, uint32 len)
|
||||
: BasePacket(buf, len),
|
||||
emu_opcode(op)
|
||||
EQPacket::EQPacket()
|
||||
{
|
||||
}
|
||||
|
||||
EQPacket::EQPacket(EmuOpcode op, const unsigned char *buf, size_t len)
|
||||
: BasePacket(buf, len)
|
||||
, emu_opcode(op)
|
||||
{
|
||||
}
|
||||
|
||||
EQPacket::EQPacket(EmuOpcode opcode, SerializeBuffer&& buf)
|
||||
: BasePacket(std::move(buf))
|
||||
, emu_opcode(opcode)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -360,17 +370,16 @@ EQRawApplicationPacket::EQRawApplicationPacket(const unsigned char *buf, const u
|
||||
}
|
||||
}
|
||||
|
||||
void DumpPacket(const EQApplicationPacket* app, bool iShowInfo) {
|
||||
void DumpPacket(const EQApplicationPacket* app, bool iShowInfo)
|
||||
{
|
||||
if (iShowInfo) {
|
||||
std::cout << "Dumping Applayer: 0x" << std::hex << std::setfill('0') << std::setw(4) << app->GetOpcode() << std::dec;
|
||||
std::cout << " size:" << app->size << std::endl;
|
||||
printf("Dumping Applayer: 0x%04x size: %u", app->GetOpcode(), app->size);
|
||||
}
|
||||
|
||||
DumpPacketHex(app->pBuffer, app->size);
|
||||
// DumpPacketAscii(app->pBuffer, app->size);
|
||||
}
|
||||
|
||||
std::string DumpPacketToString(const EQApplicationPacket* app){
|
||||
std::ostringstream out;
|
||||
out << DumpPacketHexToString(app->pBuffer, app->size);
|
||||
return out.str();
|
||||
std::string DumpPacketToString(const EQApplicationPacket* app)
|
||||
{
|
||||
return DumpPacketHexToString(app->pBuffer, app->size);
|
||||
}
|
||||
|
||||
+49
-29
@@ -28,8 +28,15 @@
|
||||
#include "common/emu_opcodes.h"
|
||||
#endif
|
||||
|
||||
class EQPacket : public BasePacket {
|
||||
class EQPacket : public BasePacket
|
||||
{
|
||||
friend class EQStream;
|
||||
|
||||
protected:
|
||||
EQPacket();
|
||||
EQPacket(EmuOpcode opcode, const unsigned char* buf, size_t len);
|
||||
EQPacket(EmuOpcode opcode, SerializeBuffer&& buf);
|
||||
|
||||
public:
|
||||
virtual ~EQPacket() {}
|
||||
|
||||
@@ -41,19 +48,12 @@ public:
|
||||
virtual void DumpRawHeaderNoTime(uint16 seq=0xffff, FILE *to = stdout) const;
|
||||
|
||||
void SetOpcode(EmuOpcode op) { emu_opcode = op; }
|
||||
const EmuOpcode GetOpcode() const { return(emu_opcode); }
|
||||
// const char *GetOpcodeName() const;
|
||||
EmuOpcode GetOpcode() const { return(emu_opcode); }
|
||||
|
||||
protected:
|
||||
//this is just a cache so we dont look it up several times on Get()
|
||||
//and it is mutable so we can store the cached copy even on a const object
|
||||
EmuOpcode emu_opcode;
|
||||
|
||||
EQPacket(EmuOpcode opcode, const unsigned char *buf, const uint32 len);
|
||||
EQPacket(EmuOpcode opcode, SerializeBuffer &buf) : BasePacket(buf), emu_opcode(opcode) { };
|
||||
// EQPacket(const EQPacket &p) { }
|
||||
EQPacket() { emu_opcode=OP_Unknown; pBuffer=nullptr; size=0; }
|
||||
|
||||
EmuOpcode emu_opcode = OP_Unknown;
|
||||
};
|
||||
|
||||
class EQRawApplicationPacket;
|
||||
@@ -90,19 +90,43 @@ protected:
|
||||
uint16 opcode;
|
||||
};
|
||||
|
||||
class EQApplicationPacket : public EQPacket {
|
||||
class EQApplicationPacket : public EQPacket
|
||||
{
|
||||
friend class EQStream;
|
||||
|
||||
public:
|
||||
EQApplicationPacket()
|
||||
{
|
||||
}
|
||||
|
||||
EQApplicationPacket(EmuOpcode op)
|
||||
: EQPacket(op, nullptr, 0)
|
||||
{
|
||||
}
|
||||
|
||||
EQApplicationPacket(EmuOpcode op, size_t len)
|
||||
: EQPacket(op, nullptr, len)
|
||||
{
|
||||
}
|
||||
EQApplicationPacket(EmuOpcode op, const unsigned char* buf, size_t len)
|
||||
: EQPacket(op, buf, len)
|
||||
{
|
||||
}
|
||||
|
||||
EQApplicationPacket(EmuOpcode op, SerializeBuffer&& buf)
|
||||
: EQPacket(op, std::move(buf))
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
EQApplicationPacket(const EQApplicationPacket& p)
|
||||
: EQPacket(p.emu_opcode, p.pBuffer, p.size)
|
||||
, app_opcode_size(p.app_opcode_size)
|
||||
, opcode_bypass(p.opcode_bypass)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
EQApplicationPacket() : EQPacket(OP_Unknown, nullptr, 0), opcode_bypass(0)
|
||||
{ app_opcode_size = GetExecutablePlatform() == ExePlatformUCS ? 1 : 2; }
|
||||
EQApplicationPacket(const EmuOpcode op) : EQPacket(op, nullptr, 0), opcode_bypass(0)
|
||||
{ app_opcode_size = GetExecutablePlatform() == ExePlatformUCS ? 1 : 2; }
|
||||
EQApplicationPacket(const EmuOpcode op, const uint32 len) : EQPacket(op, nullptr, len), opcode_bypass(0)
|
||||
{ app_opcode_size = GetExecutablePlatform() == ExePlatformUCS ? 1 : 2; }
|
||||
EQApplicationPacket(const EmuOpcode op, const unsigned char *buf, const uint32 len) : EQPacket(op, buf, len), opcode_bypass(0)
|
||||
{ app_opcode_size = GetExecutablePlatform() == ExePlatformUCS ? 1 : 2; }
|
||||
EQApplicationPacket(const EmuOpcode op, SerializeBuffer &buf) : EQPacket(op, buf), opcode_bypass(0)
|
||||
{ app_opcode_size = GetExecutablePlatform() == ExePlatformUCS ? 1 : 2; }
|
||||
bool combine(const EQApplicationPacket *rhs);
|
||||
uint32 serialize (uint16 opcode, unsigned char *dest) const;
|
||||
uint32 Size() const { return size+app_opcode_size; }
|
||||
@@ -119,15 +143,11 @@ public:
|
||||
|
||||
uint16 GetProtocolOpcode() const { return protocol_opcode; }
|
||||
void SetProtocolOpcode(uint16 v) { protocol_opcode = v; }
|
||||
|
||||
protected:
|
||||
|
||||
uint16 protocol_opcode;
|
||||
uint8 app_opcode_size;
|
||||
uint16 opcode_bypass;
|
||||
private:
|
||||
|
||||
EQApplicationPacket(const EQApplicationPacket &p) : EQPacket(p.emu_opcode, p.pBuffer, p.size), opcode_bypass(p.opcode_bypass) { app_opcode_size = p.app_opcode_size; }
|
||||
|
||||
uint16 protocol_opcode = 0;
|
||||
uint8 app_opcode_size = GetExecutablePlatform() == ExePlatformUCS ? 1 : 2;
|
||||
uint16 opcode_bypass = 0;
|
||||
};
|
||||
|
||||
class EQRawApplicationPacket : public EQApplicationPacket {
|
||||
|
||||
@@ -6236,6 +6236,12 @@ struct SuspendMercenary_Struct {
|
||||
/*0001*/
|
||||
};
|
||||
|
||||
// [OPCode: 0x1b37 (RoF2)] [Client->Server] [Size: 4]
|
||||
struct SwitchMercenary_Struct {
|
||||
/*0000*/ uint32 MercIndex; // 0-based UI index into owned merc list
|
||||
/*0004*/
|
||||
};
|
||||
|
||||
// [OPCode: 0x2528] On Live as of April 2 2012 [Server->Client] [Size: 4]
|
||||
// Response to suspend merc with timestamp
|
||||
struct SuspendMercenaryResponse_Struct {
|
||||
|
||||
@@ -26,13 +26,13 @@
|
||||
//this is the only part of an EQStream that is seen by the application.
|
||||
|
||||
|
||||
typedef enum {
|
||||
enum EQStreamState {
|
||||
ESTABLISHED,
|
||||
CLOSING, //waiting for pending data to flush.
|
||||
DISCONNECTING, //have sent disconnect, waiting for their disconnect reply.
|
||||
CLOSED, //received a disconnect from remote side.
|
||||
UNESTABLISHED
|
||||
} EQStreamState;
|
||||
};
|
||||
|
||||
class EQApplicationPacket;
|
||||
class OpcodeManager;
|
||||
|
||||
@@ -33,10 +33,8 @@
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#include <conio.h>
|
||||
#include "common/platform/platform.h"
|
||||
#include <direct.h>
|
||||
#include <process.h>
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <sys/stat.h>
|
||||
#include <thread>
|
||||
|
||||
@@ -15,36 +15,43 @@
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "common/types.h"
|
||||
#include "common/platform/posix/include_pthreads.h"
|
||||
#include "common/platform/win/include_windows.h"
|
||||
#include "common/event/event_loop.h"
|
||||
#include "uv.h"
|
||||
|
||||
class Mutex {
|
||||
public:
|
||||
Mutex();
|
||||
~Mutex();
|
||||
namespace EQ {
|
||||
|
||||
void lock();
|
||||
void unlock();
|
||||
bool trylock();
|
||||
protected:
|
||||
private:
|
||||
#if defined _WINDOWS
|
||||
CRITICAL_SECTION CSMutex;
|
||||
#else
|
||||
pthread_mutex_t CSMutex;
|
||||
#endif
|
||||
};
|
||||
EventLoop& EventLoop::Get()
|
||||
{
|
||||
thread_local EventLoop inst;
|
||||
return inst;
|
||||
}
|
||||
|
||||
class LockMutex {
|
||||
public:
|
||||
LockMutex(Mutex* in_mut, bool iLock = true);
|
||||
~LockMutex();
|
||||
void unlock();
|
||||
void lock();
|
||||
private:
|
||||
bool locked;
|
||||
Mutex* mut;
|
||||
};
|
||||
EventLoop::EventLoop()
|
||||
: m_loop(std::make_unique<uv_loop_t>())
|
||||
{
|
||||
memset(m_loop.get(), 0, sizeof(uv_loop_t));
|
||||
uv_loop_init(m_loop.get());
|
||||
}
|
||||
|
||||
EventLoop::~EventLoop()
|
||||
{
|
||||
uv_loop_close(m_loop.get());
|
||||
}
|
||||
|
||||
void EventLoop::Process()
|
||||
{
|
||||
uv_run(m_loop.get(), UV_RUN_NOWAIT);
|
||||
}
|
||||
|
||||
void EventLoop::Run()
|
||||
{
|
||||
uv_run(m_loop.get(), UV_RUN_DEFAULT);
|
||||
}
|
||||
|
||||
void EventLoop::Shutdown()
|
||||
{
|
||||
uv_stop(m_loop.get());
|
||||
}
|
||||
|
||||
} // namespace EQ
|
||||
+19
-36
@@ -17,48 +17,31 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "common/platform/win/include_windows.h" // uv.h is going to include it so let's do it first.
|
||||
#include "uv.h" // FIXME: hide this
|
||||
#include <memory>
|
||||
|
||||
#include <cstring>
|
||||
typedef struct uv_loop_s uv_loop_t;
|
||||
|
||||
namespace EQ
|
||||
namespace EQ {
|
||||
|
||||
class EventLoop
|
||||
{
|
||||
class EventLoop
|
||||
{
|
||||
public:
|
||||
static EventLoop &Get() {
|
||||
static thread_local EventLoop inst;
|
||||
return inst;
|
||||
}
|
||||
public:
|
||||
static EventLoop& Get();
|
||||
|
||||
~EventLoop() {
|
||||
uv_loop_close(&m_loop);
|
||||
}
|
||||
~EventLoop();
|
||||
EventLoop(const EventLoop&) = delete;
|
||||
EventLoop& operator=(const EventLoop&) = delete;
|
||||
|
||||
void Process() {
|
||||
uv_run(&m_loop, UV_RUN_NOWAIT);
|
||||
}
|
||||
void Process();
|
||||
void Run();
|
||||
void Shutdown();
|
||||
|
||||
void Run() {
|
||||
uv_run(&m_loop, UV_RUN_DEFAULT);
|
||||
}
|
||||
uv_loop_t* Handle() { return m_loop.get(); }
|
||||
|
||||
void Shutdown() {
|
||||
uv_stop(&m_loop);
|
||||
}
|
||||
private:
|
||||
EventLoop();
|
||||
|
||||
uv_loop_t* Handle() { return &m_loop; }
|
||||
std::unique_ptr<uv_loop_t> m_loop;
|
||||
};
|
||||
|
||||
private:
|
||||
EventLoop() {
|
||||
memset(&m_loop, 0, sizeof(uv_loop_t));
|
||||
uv_loop_init(&m_loop);
|
||||
}
|
||||
|
||||
EventLoop(const EventLoop&);
|
||||
EventLoop& operator=(const EventLoop&);
|
||||
|
||||
uv_loop_t m_loop;
|
||||
};
|
||||
}
|
||||
} // namespace EQ
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
/* EQEmu: EQEmulator
|
||||
|
||||
Copyright (C) 2001-2026 EQEmu Development Team
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "task_scheduler.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
namespace EQ::Event {
|
||||
|
||||
static constexpr int DefaultThreadCount = 4;
|
||||
|
||||
struct TaskScheduler::SchedulerData
|
||||
{
|
||||
std::atomic_bool running{ false };
|
||||
std::vector<std::thread> threads;
|
||||
std::mutex lock;
|
||||
std::condition_variable cv;
|
||||
std::queue<std::function<void()>> tasks;
|
||||
};
|
||||
|
||||
TaskScheduler::TaskScheduler()
|
||||
: m_data(std::make_unique<SchedulerData>())
|
||||
{
|
||||
Start(DefaultThreadCount);
|
||||
}
|
||||
|
||||
TaskScheduler::TaskScheduler(size_t threads)
|
||||
{
|
||||
Start(threads);
|
||||
}
|
||||
|
||||
TaskScheduler::~TaskScheduler()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
||||
void TaskScheduler::Start(size_t threads)
|
||||
{
|
||||
if (m_data->running.exchange(true))
|
||||
return;
|
||||
|
||||
m_data->threads.reserve(threads);
|
||||
|
||||
for (size_t i = 0; i < threads; ++i)
|
||||
{
|
||||
m_data->threads.emplace_back(
|
||||
[this]{ ProcessWork(); });
|
||||
}
|
||||
}
|
||||
|
||||
void TaskScheduler::Stop()
|
||||
{
|
||||
if (!m_data->running.exchange(false))
|
||||
return;
|
||||
|
||||
m_data->cv.notify_all();
|
||||
|
||||
for (auto& t : m_data->threads)
|
||||
{
|
||||
t.join();
|
||||
}
|
||||
|
||||
m_data->threads.clear();
|
||||
}
|
||||
|
||||
void TaskScheduler::ProcessWork()
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
std::function<void()> work;
|
||||
|
||||
{
|
||||
std::unique_lock lock(m_data->lock);
|
||||
|
||||
m_data->cv.wait(lock,
|
||||
[this]
|
||||
{
|
||||
return !m_data->running || !m_data->tasks.empty();
|
||||
});
|
||||
|
||||
if (!m_data->running)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
work = std::move(m_data->tasks.front());
|
||||
m_data->tasks.pop();
|
||||
}
|
||||
|
||||
work();
|
||||
}
|
||||
}
|
||||
|
||||
void TaskScheduler::AddTask(std::function<void()>&& task)
|
||||
{
|
||||
if (!m_data->running)
|
||||
{
|
||||
throw std::runtime_error("Enqueue on stopped scheduler.");
|
||||
}
|
||||
|
||||
{
|
||||
std::scoped_lock lock(m_data->lock);
|
||||
m_data->tasks.push(std::move(task));
|
||||
}
|
||||
m_data->cv.notify_one();
|
||||
}
|
||||
|
||||
} // namespace EQ::Event
|
||||
+33
-104
@@ -17,116 +17,45 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
#include <future>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
namespace EQ
|
||||
namespace EQ::Event {
|
||||
|
||||
class TaskScheduler
|
||||
{
|
||||
namespace Event
|
||||
public:
|
||||
TaskScheduler();
|
||||
TaskScheduler(size_t threads);
|
||||
|
||||
~TaskScheduler();
|
||||
|
||||
void Start(size_t threads);
|
||||
void Stop();
|
||||
|
||||
template <typename Fn, typename... Args>
|
||||
auto Enqueue(Fn&& fn, Args&&... args) -> std::future<typename std::invoke_result<Fn, Args...>::type>
|
||||
{
|
||||
class TaskScheduler
|
||||
{
|
||||
public:
|
||||
static const int DefaultThreadCount = 4;
|
||||
|
||||
TaskScheduler() : _running(false)
|
||||
using return_type = typename std::invoke_result<Fn, Args...>::type;
|
||||
|
||||
auto task = std::make_shared<std::packaged_task<return_type()>>(
|
||||
[fn = std::forward<Fn>(fn), ...args = std::forward<Args>(args)]() mutable
|
||||
{
|
||||
Start(DefaultThreadCount);
|
||||
}
|
||||
|
||||
TaskScheduler(size_t threads) : _running(false)
|
||||
{
|
||||
Start(threads);
|
||||
return fn(std::forward<Args>(args)...);
|
||||
}
|
||||
);
|
||||
|
||||
~TaskScheduler() {
|
||||
Stop();
|
||||
}
|
||||
|
||||
void Start(size_t threads) {
|
||||
if (true == _running) {
|
||||
return;
|
||||
}
|
||||
|
||||
_running = true;
|
||||
|
||||
for (size_t i = 0; i < threads; ++i) {
|
||||
_threads.emplace_back(std::thread(std::bind(&TaskScheduler::ProcessWork, this)));
|
||||
}
|
||||
}
|
||||
|
||||
void Stop() {
|
||||
if (false == _running) {
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_lock);
|
||||
_running = false;
|
||||
}
|
||||
|
||||
_cv.notify_all();
|
||||
|
||||
for (auto &t : _threads) {
|
||||
t.join();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Fn, typename... Args>
|
||||
auto Enqueue(Fn&& fn, Args&&... args) -> std::future<typename std::invoke_result<Fn, Args...>::type> {
|
||||
using return_type = typename std::invoke_result<Fn, Args...>::type;
|
||||
|
||||
auto task = std::make_shared<std::packaged_task<return_type()>>(
|
||||
std::bind(std::forward<Fn>(fn), std::forward<Args>(args)...)
|
||||
);
|
||||
|
||||
std::future<return_type> res = task->get_future();
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_lock);
|
||||
|
||||
if (false == _running) {
|
||||
throw std::runtime_error("Enqueue on stopped scheduler.");
|
||||
}
|
||||
|
||||
_tasks.emplace([task]() { (*task)(); });
|
||||
}
|
||||
|
||||
_cv.notify_one();
|
||||
return res;
|
||||
}
|
||||
|
||||
private:
|
||||
void ProcessWork() {
|
||||
for (;;) {
|
||||
std::function<void()> work;
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_lock);
|
||||
_cv.wait(lock, [this] { return !_running || !_tasks.empty(); });
|
||||
|
||||
if (false == _running) {
|
||||
return;
|
||||
}
|
||||
|
||||
work = std::move(_tasks.front());
|
||||
_tasks.pop();
|
||||
}
|
||||
|
||||
work();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool _running = true;
|
||||
std::vector<std::thread> _threads;
|
||||
std::mutex _lock;
|
||||
std::condition_variable _cv;
|
||||
std::queue<std::function<void()>> _tasks;
|
||||
};
|
||||
AddTask([task] { (*task)(); });
|
||||
return task->get_future();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void AddTask(std::function<void()>&& task);
|
||||
void ProcessWork();
|
||||
|
||||
struct SchedulerData;
|
||||
std::unique_ptr<SchedulerData> m_data;
|
||||
};
|
||||
|
||||
} // namespace EQ::Event
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/* EQEmu: EQEmulator
|
||||
|
||||
Copyright (C) 2001-2026 EQEmu Development Team
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "common/event/timer.h"
|
||||
#include "uv.h"
|
||||
|
||||
namespace EQ {
|
||||
|
||||
Timer::Timer(callback_t cb)
|
||||
: m_cb(std::move(cb))
|
||||
{
|
||||
}
|
||||
|
||||
Timer::Timer(uint64_t duration_ms, bool repeats, callback_t cb)
|
||||
: m_cb(std::move(cb))
|
||||
{
|
||||
Start(duration_ms, repeats);
|
||||
}
|
||||
|
||||
Timer::~Timer()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
||||
void Timer::Start(uint64_t duration_ms, bool repeats)
|
||||
{
|
||||
if (!m_timer)
|
||||
{
|
||||
uv_loop_t* loop = EventLoop::Get().Handle();
|
||||
|
||||
m_timer = std::make_unique<uv_timer_t>();
|
||||
memset(m_timer.get(), 0, sizeof(uv_timer_t));
|
||||
|
||||
uv_timer_init(loop, m_timer.get());
|
||||
m_timer->data = this;
|
||||
|
||||
if (repeats)
|
||||
{
|
||||
uv_timer_start(m_timer.get(), [](uv_timer_t* handle)
|
||||
{
|
||||
Timer* t = static_cast<Timer*>(handle->data);
|
||||
t->Execute();
|
||||
}, duration_ms, duration_ms);
|
||||
}
|
||||
else
|
||||
{
|
||||
uv_timer_start(m_timer.get(),
|
||||
[](uv_timer_t* handle)
|
||||
{
|
||||
Timer* t = static_cast<Timer*>(handle->data);
|
||||
t->Stop();
|
||||
t->Execute();
|
||||
}, duration_ms, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Timer::Stop()
|
||||
{
|
||||
if (m_timer)
|
||||
{
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(m_timer.release()),
|
||||
[](uv_handle_t* handle)
|
||||
{
|
||||
delete reinterpret_cast<uv_timer_t*>(handle);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void Timer::Execute()
|
||||
{
|
||||
m_cb(this);
|
||||
}
|
||||
|
||||
} // namespace EQ
|
||||
+20
-58
@@ -19,69 +19,31 @@
|
||||
|
||||
#include "event_loop.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
typedef struct uv_timer_s uv_timer_t;
|
||||
|
||||
namespace EQ {
|
||||
class Timer
|
||||
{
|
||||
public:
|
||||
Timer(std::function<void(Timer *)> cb)
|
||||
{
|
||||
m_timer = nullptr;
|
||||
m_cb = cb;
|
||||
}
|
||||
|
||||
Timer(uint64_t duration_ms, bool repeats, std::function<void(Timer *)> cb)
|
||||
{
|
||||
m_timer = nullptr;
|
||||
m_cb = cb;
|
||||
Start(duration_ms, repeats);
|
||||
}
|
||||
class Timer
|
||||
{
|
||||
public:
|
||||
using callback_t = std::function<void(Timer*)>;
|
||||
|
||||
Timer(callback_t cb);
|
||||
Timer(uint64_t duration_ms, bool repeats, callback_t cb);
|
||||
|
||||
~Timer()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
~Timer();
|
||||
|
||||
void Start(uint64_t duration_ms, bool repeats) {
|
||||
auto loop = EventLoop::Get().Handle();
|
||||
if (!m_timer) {
|
||||
m_timer = new uv_timer_t;
|
||||
memset(m_timer, 0, sizeof(uv_timer_t));
|
||||
uv_timer_init(loop, m_timer);
|
||||
m_timer->data = this;
|
||||
void Start(uint64_t duration_ms, bool repeats);
|
||||
void Stop();
|
||||
|
||||
if (repeats) {
|
||||
uv_timer_start(m_timer, [](uv_timer_t *handle) {
|
||||
Timer *t = (Timer*)handle->data;
|
||||
t->Execute();
|
||||
}, duration_ms, duration_ms);
|
||||
}
|
||||
else {
|
||||
uv_timer_start(m_timer, [](uv_timer_t *handle) {
|
||||
Timer *t = (Timer*)handle->data;
|
||||
t->Stop();
|
||||
t->Execute();
|
||||
}, duration_ms, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Stop() {
|
||||
if (m_timer) {
|
||||
uv_close((uv_handle_t*)m_timer, [](uv_handle_t* handle) {
|
||||
delete (uv_timer_t *)handle;
|
||||
});
|
||||
m_timer = nullptr;
|
||||
}
|
||||
}
|
||||
private:
|
||||
void Execute() {
|
||||
m_cb(this);
|
||||
}
|
||||
private:
|
||||
void Execute();
|
||||
|
||||
uv_timer_t *m_timer;
|
||||
std::function<void(Timer*)> m_cb;
|
||||
};
|
||||
}
|
||||
std::unique_ptr<uv_timer_t> m_timer;
|
||||
callback_t m_cb;
|
||||
};
|
||||
|
||||
} // namespace EQ
|
||||
|
||||
@@ -56,12 +56,12 @@ void PlayerEventLogs::Init()
|
||||
auto s = PlayerEventLogSettingsRepository::All(*m_database);
|
||||
std::vector<int> db{};
|
||||
db.reserve(s.size());
|
||||
for (auto &e: s) {
|
||||
for (auto& e: s) {
|
||||
if (e.id >= PlayerEvent::MAX) {
|
||||
continue;
|
||||
}
|
||||
m_settings[e.id] = e;
|
||||
db.emplace_back(e.id);
|
||||
db.emplace_back(static_cast<int>(e.id));
|
||||
}
|
||||
|
||||
std::vector<PlayerEventLogSettingsRepository::PlayerEventLogSettings> settings_to_insert{};
|
||||
|
||||
+2
-2
@@ -46,7 +46,7 @@
|
||||
#define GUILD_INITIATE 7
|
||||
#define GUILD_RECRUIT 8
|
||||
|
||||
typedef enum {
|
||||
enum GuildAction {
|
||||
GUILD_ACTION_BANNER_CHANGE = 1,
|
||||
GUILD_ACTION_BANNER_PLANT = 2,
|
||||
GUILD_ACTION_BANNER_REMOVE = 3,
|
||||
@@ -77,6 +77,6 @@ typedef enum {
|
||||
GUILD_ACTION_REAL_ESTATE_GUILD_PLOT_SELL = 28,
|
||||
GUILD_ACTION_REAL_ESTATE_MODIFY_TROPHIES = 29,
|
||||
GUILD_ACTION_MEMBERS_DEMOTE_SELF = 30,
|
||||
} GuildAction;
|
||||
};
|
||||
|
||||
constexpr int format_as(GuildAction action) { return static_cast<int>(action); }
|
||||
|
||||
@@ -349,7 +349,7 @@ bool EQ::InventoryProfile::SwapItem(
|
||||
fail_state = swapLevel;
|
||||
return false;
|
||||
}
|
||||
if (source_item_instance->IsEvolving() > 0) {
|
||||
if (source_item_instance->IsEvolving()) {
|
||||
source_item_instance->SetEvolveEquipped(true);
|
||||
}
|
||||
}
|
||||
|
||||
+34
-125
@@ -25,14 +25,24 @@
|
||||
#include "common/net/dns.h"
|
||||
|
||||
#include "fmt/format.h"
|
||||
#include <cstring>
|
||||
#include <csignal>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* @param ip
|
||||
* @return
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#pragma comment(lib, "Ws2_32.lib")
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
|
||||
uint32_t IpUtil::IPToUInt(const std::string &ip)
|
||||
{
|
||||
int a, b, c, d;
|
||||
@@ -49,12 +59,6 @@ uint32_t IpUtil::IPToUInt(const std::string &ip)
|
||||
return addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ip
|
||||
* @param network
|
||||
* @param mask
|
||||
* @return
|
||||
*/
|
||||
bool IpUtil::IsIpInRange(const std::string &ip, const std::string &network, const std::string &mask)
|
||||
{
|
||||
uint32_t ip_addr = IpUtil::IPToUInt(ip);
|
||||
@@ -67,10 +71,6 @@ bool IpUtil::IsIpInRange(const std::string &ip, const std::string &network, cons
|
||||
return ip_addr >= net_lower && ip_addr <= net_upper;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ip
|
||||
* @return
|
||||
*/
|
||||
bool IpUtil::IsIpInPrivateRfc1918(const std::string &ip)
|
||||
{
|
||||
return (
|
||||
@@ -80,30 +80,13 @@ bool IpUtil::IsIpInPrivateRfc1918(const std::string &ip)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#pragma comment(lib, "Ws2_32.lib")
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
|
||||
std::string IpUtil::GetLocalIPAddress()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
WSADATA wsaData;
|
||||
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
|
||||
return "";
|
||||
}
|
||||
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
|
||||
return "";
|
||||
}
|
||||
#endif
|
||||
|
||||
char my_ip_address[INET_ADDRSTRLEN];
|
||||
@@ -114,10 +97,10 @@ std::string IpUtil::GetLocalIPAddress()
|
||||
// Create a UDP socket
|
||||
#ifdef _WIN32
|
||||
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sockfd == INVALID_SOCKET) {
|
||||
WSACleanup();
|
||||
return "";
|
||||
}
|
||||
if (sockfd == INVALID_SOCKET) {
|
||||
WSACleanup();
|
||||
return "";
|
||||
}
|
||||
#else
|
||||
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sockfd < 0) {
|
||||
@@ -200,98 +183,24 @@ std::string IpUtil::GetPublicIPAddress()
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string IpUtil::DNSLookupSync(const std::string &addr, int port)
|
||||
{
|
||||
auto task_runner = new EQ::Event::TaskScheduler();
|
||||
auto res = task_runner->Enqueue(
|
||||
[&]() -> std::string {
|
||||
bool running = true;
|
||||
std::string ret;
|
||||
|
||||
EQ::Net::DNSLookup(
|
||||
addr, port, false, [&](const std::string &addr) {
|
||||
ret = addr;
|
||||
if (addr.empty()) {
|
||||
ret = "";
|
||||
running = false;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
);
|
||||
|
||||
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
|
||||
|
||||
auto &loop = EQ::EventLoop::Get();
|
||||
while (running) {
|
||||
if (!ret.empty()) {
|
||||
running = false;
|
||||
}
|
||||
|
||||
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
|
||||
if (std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count() > 1500) {
|
||||
LogInfo(
|
||||
"Deadline exceeded [{}]",
|
||||
1500
|
||||
);
|
||||
running = false;
|
||||
}
|
||||
|
||||
loop.Process();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
);
|
||||
|
||||
std::string result = res.get();
|
||||
safe_delete(task_runner);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool IpUtil::IsIPAddress(const std::string &ip_address)
|
||||
{
|
||||
struct sockaddr_in sa{};
|
||||
int result = inet_pton(AF_INET, ip_address.c_str(), &(sa.sin_addr));
|
||||
sockaddr_in sa{};
|
||||
int result = inet_pton(AF_INET, ip_address.c_str(), &(sa.sin_addr));
|
||||
return result != 0;
|
||||
}
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#pragma comment(lib, "ws2_32.lib") // Link against Winsock library
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h> // For inet_pton
|
||||
#pragma comment(lib, "ws2_32.lib") // Link against Winsock library
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h> // For inet_pton
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
bool IpUtil::IsPortInUse(const std::string& ip, int port) {
|
||||
bool IpUtil::IsPortInUse(const std::string& ip, int port)
|
||||
{
|
||||
bool in_use = false;
|
||||
|
||||
#ifdef _WIN32
|
||||
WSADATA wsaData;
|
||||
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
|
||||
std::cerr << "WSAStartup failed\n";
|
||||
return true; // Assume in use on failure
|
||||
}
|
||||
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
|
||||
std::cerr << "WSAStartup failed\n";
|
||||
return true; // Assume in use on failure
|
||||
}
|
||||
#endif
|
||||
|
||||
int sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
@@ -319,20 +228,20 @@ bool IpUtil::IsPortInUse(const std::string& ip, int port) {
|
||||
std::cerr << "Invalid IP address format: " << ip << std::endl;
|
||||
#ifdef _WIN32
|
||||
closesocket(sock);
|
||||
WSACleanup();
|
||||
WSACleanup();
|
||||
#else
|
||||
close(sock);
|
||||
#endif
|
||||
return true; // Assume in use on failure
|
||||
}
|
||||
|
||||
if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
|
||||
if (bind(sock, (sockaddr*)&addr, sizeof(addr)) < 0) {
|
||||
in_use = true; // Bind failed, port is in use
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
closesocket(sock);
|
||||
WSACleanup();
|
||||
WSACleanup();
|
||||
#else
|
||||
close(sock);
|
||||
#endif
|
||||
|
||||
+1
-4
@@ -29,10 +29,7 @@ public:
|
||||
static bool IsIpInPrivateRfc1918(const std::string &ip);
|
||||
static std::string GetLocalIPAddress();
|
||||
static std::string GetPublicIPAddress();
|
||||
static std::string DNSLookupSync(
|
||||
const std::string &addr,
|
||||
int port
|
||||
);
|
||||
|
||||
static bool IsIPAddress(const std::string &ip_address);
|
||||
static bool IsPortInUse(const std::string& ip, int port);
|
||||
|
||||
|
||||
@@ -320,6 +320,7 @@ bool EQ::ItemInstance::IsAugmentSlotAvailable(int32 augment_type, uint8 slot) co
|
||||
}
|
||||
|
||||
return (
|
||||
slot < invaug::SOCKET_COUNT &&
|
||||
(
|
||||
augment_type == -1 ||
|
||||
(
|
||||
|
||||
@@ -271,11 +271,7 @@ static size_t const stackLimit_g = JSONCPP_DEPRECATED_STACK_LIMIT; // see readVa
|
||||
|
||||
namespace Json {
|
||||
|
||||
#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
|
||||
typedef std::unique_ptr<CharReader> CharReaderPtr;
|
||||
#else
|
||||
typedef std::auto_ptr<CharReader> CharReaderPtr;
|
||||
#endif
|
||||
|
||||
// Implementation of class Features
|
||||
// ////////////////////////////////
|
||||
@@ -4153,11 +4149,7 @@ Value& Path::make(Value& root) const {
|
||||
|
||||
namespace Json {
|
||||
|
||||
#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
|
||||
typedef std::unique_ptr<StreamWriter> StreamWriterPtr;
|
||||
#else
|
||||
typedef std::auto_ptr<StreamWriter> StreamWriterPtr;
|
||||
#endif
|
||||
|
||||
static bool containsControlCharacter(const char* str) {
|
||||
while (*str) {
|
||||
|
||||
+1
-2
@@ -45,5 +45,4 @@ struct LootItem {
|
||||
uint32 lootdrop_id; // required for zone state referencing
|
||||
};
|
||||
|
||||
typedef std::list<LootItem*> LootItems;
|
||||
|
||||
using LootItems = std::list<LootItem*>;
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
/* EQEmu: EQEmulator
|
||||
|
||||
Copyright (C) 2001-2026 EQEmu Development Team
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "ksm.h"
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <sys/mman.h> // For madvise
|
||||
#include <unistd.h> // For sysconf, sbrk
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
// Windows-specific functionality
|
||||
|
||||
void* PageAlignedAllocatorBase::allocateInternal(size_t size, size_t alignment)
|
||||
{
|
||||
void* ptr = malloc(size);
|
||||
|
||||
if (!ptr)
|
||||
{
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
size_t PageAlignedAllocatorBase::getPageSize() const
|
||||
{
|
||||
SYSTEM_INFO sysInfo;
|
||||
GetSystemInfo(&sysInfo);
|
||||
return sysInfo.dwPageSize; // Page size in bytes
|
||||
}
|
||||
|
||||
namespace KSM {
|
||||
|
||||
// Windows-specific placeholder functions (no-op)
|
||||
void CheckPageAlignment(void* ptr)
|
||||
{
|
||||
}
|
||||
|
||||
void* AllocatePageAligned(size_t size)
|
||||
{
|
||||
return memset(malloc(size), 0, size);
|
||||
}
|
||||
|
||||
void MarkMemoryForKSM(void* start, size_t size)
|
||||
{
|
||||
}
|
||||
|
||||
void AlignHeapToPageBoundary()
|
||||
{
|
||||
}
|
||||
|
||||
void* MarkHeapStart()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t MeasureHeapUsage(void* start)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace KSM
|
||||
|
||||
#else
|
||||
|
||||
// Linux-specific functionality
|
||||
|
||||
void* PageAlignedAllocatorBase::allocateInternal(size_t size, size_t alignment)
|
||||
{
|
||||
void* ptr = nullptr;
|
||||
|
||||
if (posix_memalign(&ptr, alignment, size) != 0)
|
||||
{
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
size_t PageAlignedAllocatorBase::getPageSize() const
|
||||
{
|
||||
return static_cast<size_t>(sysconf(_SC_PAGESIZE));
|
||||
}
|
||||
|
||||
namespace KSM {
|
||||
|
||||
void CheckPageAlignment(void* ptr)
|
||||
{
|
||||
size_t page_size = sysconf(_SC_PAGESIZE);
|
||||
|
||||
if (reinterpret_cast<uintptr_t>(ptr) % page_size == 0)
|
||||
{
|
||||
LogKSMDetail("Memory is page-aligned [{}]", ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogKSMDetail("Memory is NOT page-aligned [{}]", ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void* AllocatePageAligned(size_t size)
|
||||
{
|
||||
size_t page_size = sysconf(_SC_PAGESIZE);
|
||||
void* aligned_ptr = nullptr;
|
||||
|
||||
if (posix_memalign(&aligned_ptr, page_size, size) != 0)
|
||||
{
|
||||
LogKSM("Failed to allocate page-aligned memory on Linux. page_size [{}] size [{}] bytes", page_size, size);
|
||||
}
|
||||
|
||||
std::memset(aligned_ptr, 0, size);
|
||||
return aligned_ptr;
|
||||
}
|
||||
|
||||
void MarkMemoryForKSM(void* start, size_t size)
|
||||
{
|
||||
if (madvise(start, size, MADV_MERGEABLE) == 0)
|
||||
{
|
||||
LogKSM("Marked memory for KSM | start [{}] size [{}] bytes", start, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
perror("madvise failed");
|
||||
}
|
||||
}
|
||||
|
||||
void AlignHeapToPageBoundary()
|
||||
{
|
||||
size_t page_size = sysconf(_SC_PAGESIZE);
|
||||
if (page_size == 0)
|
||||
{
|
||||
LogKSM("Failed to retrieve page size SC_PAGESIZE [{}]", page_size);
|
||||
return;
|
||||
}
|
||||
|
||||
void* current_break = sbrk(0);
|
||||
if (current_break == (void*)-1)
|
||||
{
|
||||
LogKSM("Failed to retrieve the current program break");
|
||||
return;
|
||||
}
|
||||
|
||||
uintptr_t current_address = reinterpret_cast<uintptr_t>(current_break);
|
||||
size_t misalignment = current_address % page_size;
|
||||
|
||||
if (misalignment != 0)
|
||||
{
|
||||
size_t adjustment = page_size - misalignment;
|
||||
if (sbrk(adjustment) == (void*)-1)
|
||||
{
|
||||
LogKSM("Failed to align heap to page boundary. adjustment [{}] bytes", adjustment);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
LogKSMDetail("Heap aligned to next page boundary. Current break [{}]", sbrk(0));
|
||||
}
|
||||
|
||||
void* MarkHeapStart()
|
||||
{
|
||||
void* current_pos = sbrk(0);
|
||||
AlignHeapToPageBoundary();
|
||||
return current_pos;
|
||||
}
|
||||
|
||||
size_t MeasureHeapUsage(void* start)
|
||||
{
|
||||
void* current_break = sbrk(0);
|
||||
return static_cast<char*>(current_break) - static_cast<char*>(start);
|
||||
}
|
||||
|
||||
} // namespace KSM
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,74 @@
|
||||
/* EQEmu: EQEmulator
|
||||
|
||||
Copyright (C) 2001-2026 EQEmu Development Team
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "common/eqemu_logsys.h"
|
||||
|
||||
class PageAlignedAllocatorBase
|
||||
{
|
||||
protected:
|
||||
void* allocateInternal(size_t amount, size_t alignment);
|
||||
size_t getPageSize() const;
|
||||
};
|
||||
|
||||
// Page-aligned allocator for std::vector
|
||||
template <typename T>
|
||||
class PageAlignedAllocator : public PageAlignedAllocatorBase
|
||||
{
|
||||
public:
|
||||
using value_type = T;
|
||||
|
||||
PageAlignedAllocator() noexcept = default;
|
||||
|
||||
template <typename U>
|
||||
PageAlignedAllocator(const PageAlignedAllocator<U>&) noexcept {}
|
||||
|
||||
T* allocate(std::size_t n)
|
||||
{
|
||||
size_t size = n * sizeof(T);
|
||||
|
||||
return static_cast<T*>(allocateInternal(size, getPageSize()));
|
||||
}
|
||||
|
||||
void deallocate(T* p, std::size_t) noexcept
|
||||
{
|
||||
free(p);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
bool operator==(const PageAlignedAllocator<T>&, const PageAlignedAllocator<U>&) noexcept {
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
bool operator!=(const PageAlignedAllocator<T>&, const PageAlignedAllocator<U>&) noexcept {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Kernel Samepage Merging (KSM) functionality
|
||||
namespace KSM {
|
||||
|
||||
void CheckPageAlignment(void* ptr);
|
||||
void* AllocatePageAligned(size_t size);
|
||||
void MarkMemoryForKSM(void* start, size_t size);
|
||||
void AlignHeapToPageBoundary();
|
||||
void* MarkHeapStart();
|
||||
size_t MeasureHeapUsage(void* start);
|
||||
|
||||
} // namespace KSM
|
||||
@@ -1,234 +0,0 @@
|
||||
/* EQEmu: EQEmulator
|
||||
|
||||
Copyright (C) 2001-2026 EQEmu Development Team
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "common/eqemu_logsys.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
#ifdef _WIN32
|
||||
#include <malloc.h> // For _aligned_malloc, _aligned_free
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <sys/mman.h> // For madvise
|
||||
#include <unistd.h> // For sysconf, sbrk
|
||||
#endif
|
||||
|
||||
|
||||
// Page-aligned allocator for std::vector
|
||||
template <typename T>
|
||||
class PageAlignedAllocator {
|
||||
public:
|
||||
using value_type = T;
|
||||
|
||||
PageAlignedAllocator() noexcept = default;
|
||||
template <typename U>
|
||||
PageAlignedAllocator(const PageAlignedAllocator<U>&) noexcept {}
|
||||
|
||||
T* allocate(std::size_t n) {
|
||||
void* ptr = nullptr;
|
||||
size_t size = n * sizeof(T);
|
||||
|
||||
#ifdef _WIN32
|
||||
// Simply allocate memory without alignment
|
||||
ptr = malloc(size);
|
||||
if (!ptr) throw std::bad_alloc();
|
||||
#else
|
||||
size_t alignment = getPageSize(); // Get the system's page size
|
||||
if (posix_memalign(&ptr, alignment, size) != 0) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
#endif
|
||||
return static_cast<T*>(ptr);
|
||||
}
|
||||
|
||||
void deallocate(T* p, std::size_t) noexcept {
|
||||
free(p);
|
||||
}
|
||||
|
||||
private:
|
||||
size_t getPageSize() const
|
||||
{
|
||||
#ifdef _WIN32
|
||||
SYSTEM_INFO sysInfo;
|
||||
GetSystemInfo(&sysInfo);
|
||||
return sysInfo.dwPageSize; // Page size in bytes
|
||||
#else
|
||||
return static_cast<size_t>(sysconf(_SC_PAGESIZE));
|
||||
#endif
|
||||
};
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
bool operator==(const PageAlignedAllocator<T>&, const PageAlignedAllocator<U>&) noexcept {
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
bool operator!=(const PageAlignedAllocator<T>&, const PageAlignedAllocator<U>&) noexcept {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Kernel Samepage Merging (KSM) functionality
|
||||
namespace KSM {
|
||||
|
||||
#ifdef _WIN32
|
||||
// Windows-specific placeholder functions (no-op)
|
||||
inline void CheckPageAlignment(void* ptr) {
|
||||
}
|
||||
|
||||
inline void* AllocatePageAligned(size_t size) {
|
||||
return memset(malloc(size), 0, size);
|
||||
}
|
||||
|
||||
inline void MarkMemoryForKSM(void* start, size_t size) {
|
||||
}
|
||||
|
||||
inline void AlignHeapToPageBoundary() {
|
||||
}
|
||||
|
||||
inline void* MarkHeapStart() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline size_t MeasureHeapUsage(void* start) {
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
// Linux-specific functionality
|
||||
inline void CheckPageAlignment(void* ptr) {
|
||||
size_t page_size = sysconf(_SC_PAGESIZE);
|
||||
if (reinterpret_cast<uintptr_t>(ptr) % page_size == 0) {
|
||||
LogKSMDetail("Memory is page-aligned [{}]", ptr);
|
||||
} else {
|
||||
LogKSMDetail("Memory is NOT page-aligned [{}]", ptr);
|
||||
}
|
||||
}
|
||||
|
||||
inline void* AllocatePageAligned(size_t size) {
|
||||
size_t page_size = sysconf(_SC_PAGESIZE);
|
||||
void* aligned_ptr = nullptr;
|
||||
if (posix_memalign(&aligned_ptr, page_size, size) != 0) {
|
||||
LogKSM("Failed to allocate page-aligned memory on Linux. page_size [{}] size [{}] bytes", page_size, size);
|
||||
}
|
||||
std::memset(aligned_ptr, 0, size);
|
||||
return aligned_ptr;
|
||||
}
|
||||
|
||||
inline void MarkMemoryForKSM(void* start, size_t size) {
|
||||
if (madvise(start, size, MADV_MERGEABLE) == 0) {
|
||||
LogKSM("Marked memory for KSM | start [{}] size [{}] bytes", start, size);
|
||||
} else {
|
||||
perror("madvise failed");
|
||||
}
|
||||
}
|
||||
|
||||
inline void AlignHeapToPageBoundary() {
|
||||
size_t page_size = sysconf(_SC_PAGESIZE);
|
||||
if (page_size == 0) {
|
||||
LogKSM("Failed to retrieve page size SC_PAGESIZE [{}]", page_size);
|
||||
return;
|
||||
}
|
||||
|
||||
void* current_break = sbrk(0);
|
||||
if (current_break == (void*)-1) {
|
||||
LogKSM("Failed to retrieve the current program break");
|
||||
return;
|
||||
}
|
||||
|
||||
uintptr_t current_address = reinterpret_cast<uintptr_t>(current_break);
|
||||
size_t misalignment = current_address % page_size;
|
||||
|
||||
if (misalignment != 0) {
|
||||
size_t adjustment = page_size - misalignment;
|
||||
if (sbrk(adjustment) == (void*)-1) {
|
||||
LogKSM("Failed to align heap to page boundary. adjustment [{}] bytes", adjustment);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
LogKSMDetail("Heap aligned to next page boundary. Current break [{}]", sbrk(0));
|
||||
}
|
||||
|
||||
inline void* MarkHeapStart() {
|
||||
void* current_pos = sbrk(0);
|
||||
AlignHeapToPageBoundary();
|
||||
return current_pos;
|
||||
}
|
||||
|
||||
inline size_t MeasureHeapUsage(void* start) {
|
||||
void* current_break = sbrk(0);
|
||||
return static_cast<char*>(current_break) - static_cast<char*>(start);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
inline size_t getPageSize()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
SYSTEM_INFO sysInfo;
|
||||
GetSystemInfo(&sysInfo);
|
||||
return sysInfo.dwPageSize; // Page size in bytes
|
||||
#else
|
||||
return static_cast<size_t>(sysconf(_SC_PAGESIZE)); // POSIX page size
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline void PageAlignVectorAligned(std::vector<T, PageAlignedAllocator<T>>& vec) {
|
||||
if (vec.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t page_size = getPageSize();
|
||||
void* start = vec.data();
|
||||
size_t size = vec.size() * sizeof(T);
|
||||
|
||||
// Check if the memory is page-aligned
|
||||
if (reinterpret_cast<std::uintptr_t>(start) % page_size != 0) {
|
||||
// Allocate a new aligned vector
|
||||
std::vector<T, PageAlignedAllocator<T>> aligned_vec(vec.get_allocator());
|
||||
aligned_vec.reserve(vec.capacity()); // Match capacity to avoid reallocation during copy
|
||||
|
||||
// Copy elements from the original vector
|
||||
aligned_vec.insert(aligned_vec.end(), vec.begin(), vec.end());
|
||||
|
||||
// Swap the aligned vector with the original vector
|
||||
vec.swap(aligned_vec);
|
||||
|
||||
// Clear the temporary aligned vector to free its memory
|
||||
aligned_vec.clear();
|
||||
|
||||
// Verify the new alignment
|
||||
start = vec.data();
|
||||
if (reinterpret_cast<std::uintptr_t>(start) % page_size != 0) {
|
||||
throw std::runtime_error("Failed to align vector memory to page boundaries.");
|
||||
}
|
||||
|
||||
LogKSMDetail("Vector reallocated to ensure page alignment. start [{}] size [{}] bytes", start, size);
|
||||
} else {
|
||||
LogKSMDetail("Vector is already page-aligned. start [{}] size [{}] bytes", start, size);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
// Mark memory for KSM (only on non-Windows systems)
|
||||
MarkMemoryForKSM(start, size);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
/* EQEmu: EQEmulator
|
||||
|
||||
Copyright (C) 2001-2026 EQEmu Development Team
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "mutex.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#define DEBUG_MUTEX_CLASS 0
|
||||
#if DEBUG_MUTEX_CLASS >= 1
|
||||
#endif
|
||||
|
||||
#ifdef _WINDOWS
|
||||
bool IsTryLockSupported();
|
||||
bool TrylockSupported = IsTryLockSupported();
|
||||
|
||||
bool IsTryLockSupported() {
|
||||
OSVERSIONINFOEX osvi;
|
||||
BOOL bOsVersionInfoEx;
|
||||
|
||||
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
|
||||
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
|
||||
|
||||
if( !(bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &osvi)) )
|
||||
{
|
||||
// If OSVERSIONINFOEX doesn't work, try OSVERSIONINFO.
|
||||
osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
|
||||
if (! GetVersionEx ( (OSVERSIONINFO *) &osvi) ) {
|
||||
#if DEBUG_MUTEX_CLASS >= 1
|
||||
std::cout << "Mutex::trylock() NOT supported" << std::endl;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Tests for Windows NT product family.
|
||||
if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT && osvi.dwMajorVersion >= 4) {
|
||||
#if DEBUG_MUTEX_CLASS >= 1
|
||||
std::cout << "Mutex::trylock() SUPPORTED" << std::endl;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
#if DEBUG_MUTEX_CLASS >= 1
|
||||
std::cout << "Mutex::trylock() NOT supported" << std::endl;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
Mutex::Mutex() {
|
||||
|
||||
#if DEBUG_MUTEX_CLASS >= 7
|
||||
std::cout << "Constructing Mutex" << std::endl;
|
||||
#endif
|
||||
#ifdef _WINDOWS
|
||||
InitializeCriticalSection(&CSMutex);
|
||||
#else
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
#if defined(__CYGWIN__) || defined(__APPLE__) || defined(FREEBSD)
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||
#else
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
|
||||
#endif
|
||||
pthread_mutex_init(&CSMutex, &attr);
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
#endif
|
||||
}
|
||||
|
||||
Mutex::~Mutex() {
|
||||
#ifdef _WINDOWS
|
||||
DeleteCriticalSection(&CSMutex);
|
||||
#else
|
||||
#endif
|
||||
}
|
||||
|
||||
void Mutex::lock() {
|
||||
#if DEBUG_MUTEX_CLASS >= 5
|
||||
if (!trylock()) {
|
||||
std::cout << "Locking Mutex: Having to wait" << std::endl;
|
||||
#ifdef _WINDOWS
|
||||
EnterCriticalSection(&CSMutex);
|
||||
#else
|
||||
pthread_mutex_lock(&CSMutex);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
#ifdef _WINDOWS
|
||||
EnterCriticalSection(&CSMutex);
|
||||
#else
|
||||
pthread_mutex_lock(&CSMutex);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Mutex::trylock() {
|
||||
#ifdef _WINDOWS
|
||||
#if(_WIN32_WINNT >= 0x0400)
|
||||
if (TrylockSupported)
|
||||
return TryEnterCriticalSection(&CSMutex);
|
||||
else {
|
||||
EnterCriticalSection(&CSMutex);
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
EnterCriticalSection(&CSMutex);
|
||||
return true;
|
||||
#endif
|
||||
#else
|
||||
return (pthread_mutex_trylock(&CSMutex) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Mutex::unlock() {
|
||||
#ifdef _WINDOWS
|
||||
LeaveCriticalSection(&CSMutex);
|
||||
#else
|
||||
pthread_mutex_unlock(&CSMutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
LockMutex::LockMutex(Mutex* in_mut, bool iLock) {
|
||||
mut = in_mut;
|
||||
locked = iLock;
|
||||
if (locked) {
|
||||
mut->lock();
|
||||
}
|
||||
}
|
||||
|
||||
LockMutex::~LockMutex() {
|
||||
if (locked) {
|
||||
mut->unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void LockMutex::unlock() {
|
||||
if (locked)
|
||||
mut->unlock();
|
||||
locked = false;
|
||||
}
|
||||
|
||||
void LockMutex::lock() {
|
||||
if (!locked)
|
||||
mut->lock();
|
||||
locked = true;
|
||||
}
|
||||
+10
-6
@@ -18,7 +18,6 @@
|
||||
#include "mysql_stmt.h"
|
||||
|
||||
#include "common/eqemu_logsys.h"
|
||||
#include "common/mutex.h"
|
||||
#include "common/timer.h"
|
||||
|
||||
#include <charconv>
|
||||
@@ -31,14 +30,19 @@ void PreparedStmt::StmtDeleter::operator()(MYSQL_STMT* stmt) noexcept
|
||||
// The connection must be locked when closing the stmt to avoid mysql errors
|
||||
// in case another thread tries to use it during the close. If the mutex is
|
||||
// changed to one that throws then exceptions need to be caught here.
|
||||
LockMutex lock(mutex);
|
||||
std::scoped_lock lock(mutex);
|
||||
|
||||
mysql_stmt_close(stmt);
|
||||
}
|
||||
|
||||
PreparedStmt::PreparedStmt(MYSQL& mysql, std::string query, Mutex* mutex, StmtOptions opts)
|
||||
: m_stmt(mysql_stmt_init(&mysql), { mutex }), m_query(std::move(query)), m_mutex(mutex), m_options(opts)
|
||||
PreparedStmt::PreparedStmt(MYSQL& mysql, std::string query, DBcore::Mutex& mutex, StmtOptions opts)
|
||||
: m_stmt(mysql_stmt_init(&mysql), { mutex })
|
||||
, m_query(std::move(query))
|
||||
, m_options(opts)
|
||||
, m_mutex(mutex)
|
||||
{
|
||||
LockMutex lock(m_mutex);
|
||||
std::scoped_lock lock(m_mutex);
|
||||
|
||||
if (mysql_stmt_prepare(m_stmt.get(), m_query.c_str(), static_cast<unsigned long>(m_query.size())) != 0)
|
||||
{
|
||||
ThrowError(fmt::format("Prepare error: {}", GetStmtError()));
|
||||
@@ -186,7 +190,7 @@ void PreparedStmt::CheckArgs(size_t argc)
|
||||
StmtResult PreparedStmt::DoExecute()
|
||||
{
|
||||
BenchTimer timer;
|
||||
LockMutex lock(m_mutex);
|
||||
std::scoped_lock lock(m_mutex);
|
||||
|
||||
if (m_need_bind && mysql_stmt_bind_param(m_stmt.get(), m_params.data()) != 0)
|
||||
{
|
||||
|
||||
+7
-4
@@ -17,10 +17,12 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "mysql.h"
|
||||
#include "common/dbcore.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <span>
|
||||
#include <string_view>
|
||||
@@ -183,7 +185,7 @@ public:
|
||||
int64_t, uint64_t, float, double, bool, std::string_view, std::nullptr_t>;
|
||||
|
||||
PreparedStmt() = delete;
|
||||
PreparedStmt(MYSQL& mysql, std::string query, Mutex* mutex, StmtOptions opts = {});
|
||||
PreparedStmt(MYSQL& mysql, std::string query, DBcore::Mutex& mutex, StmtOptions opts = {});
|
||||
|
||||
const std::string& GetQuery() const { return m_query; }
|
||||
StmtOptions GetOptions() const { return m_options; }
|
||||
@@ -219,7 +221,8 @@ private:
|
||||
|
||||
struct StmtDeleter
|
||||
{
|
||||
Mutex* mutex = nullptr;
|
||||
DBcore::Mutex& mutex;
|
||||
|
||||
void operator()(MYSQL_STMT* stmt) noexcept;
|
||||
};
|
||||
|
||||
@@ -232,7 +235,7 @@ private:
|
||||
std::string m_query;
|
||||
StmtOptions m_options = {};
|
||||
bool m_need_bind = true;
|
||||
Mutex* m_mutex = nullptr; // connection mutex
|
||||
DBcore::Mutex& m_mutex; // connection mutex
|
||||
};
|
||||
|
||||
} // namespace mysql
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
/* EQEmu: EQEmulator
|
||||
|
||||
Copyright (C) 2001-2026 EQEmu Development Team
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dns.h"
|
||||
|
||||
#include "common/eqemu_logsys.h"
|
||||
#include "common/event/event_loop.h"
|
||||
#include "common/event/task_scheduler.h"
|
||||
|
||||
#include "uv.h"
|
||||
|
||||
namespace EQ::Net {
|
||||
|
||||
struct DNSBaton
|
||||
{
|
||||
dns_callback_t cb;
|
||||
bool ipv6;
|
||||
};
|
||||
|
||||
void DNSLookup(const std::string& addr, int port, bool ipv6, dns_callback_t cb)
|
||||
{
|
||||
addrinfo hints = {};
|
||||
hints.ai_family = PF_INET;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
|
||||
uv_loop_t* loop = EQ::EventLoop::Get().Handle();
|
||||
|
||||
uv_getaddrinfo_t* resolver = new uv_getaddrinfo_t();
|
||||
memset(resolver, 0, sizeof(uv_getaddrinfo_t));
|
||||
std::string port_str = std::to_string(port);
|
||||
DNSBaton* baton = new DNSBaton();
|
||||
baton->cb = std::move(cb);
|
||||
baton->ipv6 = ipv6;
|
||||
resolver->data = baton;
|
||||
|
||||
uv_getaddrinfo(loop, resolver, [](uv_getaddrinfo_t* req, int status, addrinfo* result)
|
||||
{
|
||||
DNSBaton* baton = static_cast<DNSBaton*>(req->data);
|
||||
|
||||
dns_callback_t dns_callback = std::move(baton->cb);
|
||||
bool ipv6 = baton->ipv6;
|
||||
|
||||
delete baton;
|
||||
delete req;
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
dns_callback({});
|
||||
return;
|
||||
}
|
||||
|
||||
char addr[40] = {};
|
||||
|
||||
if (ipv6)
|
||||
{
|
||||
uv_ip6_name(reinterpret_cast<sockaddr_in6*>(result->ai_addr), addr, 40);
|
||||
}
|
||||
else
|
||||
{
|
||||
uv_ip4_name(reinterpret_cast<sockaddr_in*>(result->ai_addr), addr, 40);
|
||||
}
|
||||
|
||||
uv_freeaddrinfo(result);
|
||||
|
||||
dns_callback(addr);
|
||||
}, addr.c_str(), port_str.c_str(), &hints);
|
||||
}
|
||||
|
||||
std::string DNSLookupSync(const std::string& addr, int port, bool ipv6 /* = false */)
|
||||
{
|
||||
EQ::Event::TaskScheduler task_runner;
|
||||
|
||||
auto res = task_runner.Enqueue(
|
||||
[addr, port, ipv6]() -> std::string
|
||||
{
|
||||
bool running = true;
|
||||
std::string ret;
|
||||
|
||||
EQ::Net::DNSLookup(
|
||||
addr, port, ipv6, [&](const std::string& addr) {
|
||||
ret = addr;
|
||||
running = !addr.empty();
|
||||
|
||||
return ret;
|
||||
}
|
||||
);
|
||||
|
||||
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
|
||||
|
||||
auto& loop = EQ::EventLoop::Get();
|
||||
while (running) {
|
||||
if (!ret.empty()) {
|
||||
running = false;
|
||||
}
|
||||
|
||||
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
|
||||
if (std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count() > 1500) {
|
||||
LogInfo(
|
||||
"Deadline exceeded [{}]",
|
||||
1500
|
||||
);
|
||||
running = false;
|
||||
}
|
||||
|
||||
loop.Process();
|
||||
}
|
||||
|
||||
return ret;
|
||||
});
|
||||
|
||||
return res.get();
|
||||
}
|
||||
|
||||
|
||||
} // namespace EQ::Net
|
||||
+5
-53
@@ -17,63 +17,15 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "common/event/event_loop.h"
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
namespace Net
|
||||
{
|
||||
static void DNSLookup(const std::string &addr, int port, bool ipv6, std::function<void(const std::string&)> cb) {
|
||||
struct DNSBaton
|
||||
{
|
||||
std::function<void(const std::string&)> cb;
|
||||
bool ipv6;
|
||||
};
|
||||
namespace EQ::Net {
|
||||
|
||||
addrinfo hints;
|
||||
memset(&hints, 0, sizeof(addrinfo));
|
||||
hints.ai_family = PF_INET;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
using dns_callback_t = std::function<void(const std::string&)>;
|
||||
|
||||
auto loop = EQ::EventLoop::Get().Handle();
|
||||
uv_getaddrinfo_t *resolver = new uv_getaddrinfo_t();
|
||||
memset(resolver, 0, sizeof(uv_getaddrinfo_t));
|
||||
auto port_str = std::to_string(port);
|
||||
DNSBaton *baton = new DNSBaton();
|
||||
baton->cb = cb;
|
||||
baton->ipv6 = ipv6;
|
||||
resolver->data = baton;
|
||||
void DNSLookup(const std::string& addr, int port, bool ipv6, dns_callback_t cb);
|
||||
|
||||
uv_getaddrinfo(loop, resolver, [](uv_getaddrinfo_t* req, int status, addrinfo* res) {
|
||||
DNSBaton *baton = (DNSBaton*)req->data;
|
||||
if (status < 0) {
|
||||
auto cb = baton->cb;
|
||||
delete baton;
|
||||
delete req;
|
||||
cb("");
|
||||
return;
|
||||
}
|
||||
std::string DNSLookupSync(const std::string& addr, int port, bool ipv6 = false);
|
||||
|
||||
char addr[40] = { 0 };
|
||||
|
||||
if (baton->ipv6) {
|
||||
uv_ip6_name((struct sockaddr_in6*)res->ai_addr, addr, 40);
|
||||
}
|
||||
else {
|
||||
uv_ip4_name((struct sockaddr_in*)res->ai_addr, addr, 40);
|
||||
}
|
||||
|
||||
auto cb = baton->cb;
|
||||
delete baton;
|
||||
delete req;
|
||||
uv_freeaddrinfo(res);
|
||||
|
||||
cb(addr);
|
||||
}, addr.c_str(), port_str.c_str(), &hints);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace EQ::Net
|
||||
|
||||
@@ -19,7 +19,9 @@
|
||||
|
||||
#include "common/net/tcp_connection_pooling.h"
|
||||
|
||||
#include "common/platform/platform.h"
|
||||
#include "uv.h"
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
@@ -49,9 +49,9 @@ namespace EQ
|
||||
WebsocketException(const std::string &msg)
|
||||
: _msg(msg.empty() ? "Unknown Error" : msg) { }
|
||||
|
||||
~WebsocketException() throw() {}
|
||||
~WebsocketException() noexcept {}
|
||||
|
||||
virtual char const *what() const throw() {
|
||||
virtual char const *what() const noexcept override {
|
||||
return _msg.c_str();
|
||||
}
|
||||
private:
|
||||
|
||||
+13
-14
@@ -17,17 +17,16 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
||||
static const char OP_SessionRequest = 0x01;
|
||||
static const char OP_SessionResponse = 0x02;
|
||||
static const char OP_Combined = 0x03;
|
||||
static const char OP_SessionDisconnect = 0x05;
|
||||
static const char OP_KeepAlive = 0x06;
|
||||
static const char OP_SessionStatRequest = 0x07;
|
||||
static const char OP_SessionStatResponse= 0x08;
|
||||
static const char OP_Packet = 0x09;
|
||||
static const char OP_Fragment = 0x0d;
|
||||
static const char OP_OutOfOrderAck = 0x11;
|
||||
static const char OP_Ack = 0x15;
|
||||
static const char OP_AppCombined = 0x19;
|
||||
static const char OP_OutOfSession = 0x1d;
|
||||
static constexpr char OP_SessionRequest = 0x01;
|
||||
static constexpr char OP_SessionResponse = 0x02;
|
||||
static constexpr char OP_Combined = 0x03;
|
||||
static constexpr char OP_SessionDisconnect = 0x05;
|
||||
static constexpr char OP_KeepAlive = 0x06;
|
||||
static constexpr char OP_SessionStatRequest = 0x07;
|
||||
static constexpr char OP_SessionStatResponse = 0x08;
|
||||
static constexpr char OP_Packet = 0x09;
|
||||
static constexpr char OP_Fragment = 0x0d;
|
||||
static constexpr char OP_OutOfOrderAck = 0x11;
|
||||
static constexpr char OP_Ack = 0x15;
|
||||
static constexpr char OP_AppCombined = 0x19;
|
||||
static constexpr char OP_OutOfSession = 0x1d;
|
||||
|
||||
+26
-23
@@ -142,10 +142,12 @@ RegularOpcodeManager::~RegularOpcodeManager() {
|
||||
safe_delete_array(eq_to_emu);
|
||||
}
|
||||
|
||||
bool RegularOpcodeManager::LoadOpcodes(const char *filename, bool report_errors) {
|
||||
bool RegularOpcodeManager::LoadOpcodes(const char *filename, bool report_errors)
|
||||
{
|
||||
std::scoped_lock lock(MOpcodes);
|
||||
|
||||
NormalMemStrategy s;
|
||||
s.it = this;
|
||||
MOpcodes.lock();
|
||||
|
||||
loaded = true;
|
||||
eq_to_emu = new EmuOpcode[MAX_EQ_OPCODE];
|
||||
@@ -158,32 +160,30 @@ bool RegularOpcodeManager::LoadOpcodes(const char *filename, bool report_errors)
|
||||
memset(emu_to_eq, 0, sizeof(uint16)*_maxEmuOpcode);
|
||||
|
||||
bool ret = LoadOpcodesFile(filename, &s, report_errors);
|
||||
MOpcodes.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool RegularOpcodeManager::ReloadOpcodes(const char *filename, bool report_errors) {
|
||||
if(!loaded)
|
||||
return(LoadOpcodes(filename));
|
||||
bool RegularOpcodeManager::ReloadOpcodes(const char* filename, bool report_errors)
|
||||
{
|
||||
if (!loaded)
|
||||
return LoadOpcodes(filename);
|
||||
|
||||
std::scoped_lock lock(MOpcodes);
|
||||
|
||||
NormalMemStrategy s;
|
||||
s.it = this;
|
||||
MOpcodes.lock();
|
||||
|
||||
memset(eq_to_emu, 0, sizeof(uint16)*MAX_EQ_OPCODE);
|
||||
|
||||
bool ret = LoadOpcodesFile(filename, &s, report_errors);
|
||||
|
||||
MOpcodes.unlock();
|
||||
return(ret);
|
||||
memset(eq_to_emu, 0, sizeof(uint16) * MAX_EQ_OPCODE);
|
||||
return LoadOpcodesFile(filename, &s, report_errors);
|
||||
}
|
||||
|
||||
uint16 RegularOpcodeManager::EmuToEQ(const EmuOpcode emu_op) {
|
||||
//opcode is checked for validity in GetEQOpcode
|
||||
uint16 res;
|
||||
MOpcodes.lock();
|
||||
res = emu_to_eq[emu_op];
|
||||
MOpcodes.unlock();
|
||||
{
|
||||
std::scoped_lock lock(MOpcodes);
|
||||
res = emu_to_eq[emu_op];
|
||||
}
|
||||
|
||||
LogNetcodeDetail("[Opcode Manager] Translate emu [{}] ({:#06x}) eq [{:#06x}]", OpcodeNames[emu_op], emu_op, res);
|
||||
|
||||
@@ -193,15 +193,18 @@ uint16 RegularOpcodeManager::EmuToEQ(const EmuOpcode emu_op) {
|
||||
return(res);
|
||||
}
|
||||
|
||||
EmuOpcode RegularOpcodeManager::EQToEmu(const uint16 eq_op) {
|
||||
EmuOpcode RegularOpcodeManager::EQToEmu(const uint16 eq_op)
|
||||
{
|
||||
//opcode is checked for validity in GetEmuOpcode
|
||||
//Disabled since current live EQ uses the entire uint16 bitspace for opcodes
|
||||
// if(eq_op > MAX_EQ_OPCODE)
|
||||
// return(OP_Unknown);
|
||||
//Disabled since current live EQ uses the entire uint16 bitspace for opcodes
|
||||
// if(eq_op > MAX_EQ_OPCODE)
|
||||
// return(OP_Unknown);
|
||||
EmuOpcode res;
|
||||
MOpcodes.lock();
|
||||
res = eq_to_emu[eq_op];
|
||||
MOpcodes.unlock();
|
||||
{
|
||||
std::scoped_lock lock(MOpcodes);
|
||||
res = eq_to_emu[eq_op];
|
||||
}
|
||||
|
||||
#ifdef DEBUG_TRANSLATE
|
||||
fprintf(stderr, "M Translate EQ 0x%.4x to Emu %s (%d)\n", eq_op, OpcodeNames[res], res);
|
||||
#endif
|
||||
|
||||
+20
-16
@@ -18,10 +18,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/emu_opcodes.h"
|
||||
#include "common/mutex.h"
|
||||
#include "common/types.h"
|
||||
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
|
||||
//enable the use of shared mem opcodes for world and zone only
|
||||
#ifdef ZONE
|
||||
@@ -31,7 +31,8 @@
|
||||
#define SHARED_OPCODES
|
||||
#endif
|
||||
|
||||
class OpcodeManager {
|
||||
class OpcodeManager
|
||||
{
|
||||
public:
|
||||
OpcodeManager();
|
||||
virtual ~OpcodeManager() {}
|
||||
@@ -48,24 +49,27 @@ public:
|
||||
EmuOpcode NameSearch(const char *name);
|
||||
|
||||
//This has to be public for stupid visual studio
|
||||
class OpcodeSetStrategy {
|
||||
class OpcodeSetStrategy
|
||||
{
|
||||
public:
|
||||
virtual ~OpcodeSetStrategy() {} //shut up compiler!
|
||||
virtual ~OpcodeSetStrategy() = default;
|
||||
virtual void Set(EmuOpcode emu_op, uint16 eq_op) = 0;
|
||||
};
|
||||
|
||||
protected:
|
||||
bool loaded; //true if all opcodes loaded
|
||||
Mutex MOpcodes; //this only protects the local machine
|
||||
std::mutex MOpcodes; //this only protects the local machine
|
||||
//in a shared manager, this dosent protect others
|
||||
|
||||
static bool LoadOpcodesFile(const char *filename, OpcodeSetStrategy *s, bool report_errors);
|
||||
};
|
||||
|
||||
class MutableOpcodeManager : public OpcodeManager {
|
||||
class MutableOpcodeManager : public OpcodeManager
|
||||
{
|
||||
public:
|
||||
MutableOpcodeManager() : OpcodeManager() {}
|
||||
virtual bool Mutable() { return(true); }
|
||||
MutableOpcodeManager() = default;
|
||||
|
||||
virtual bool Mutable() override { return true; }
|
||||
virtual void SetOpcode(EmuOpcode emu_op, uint16 eq_op) = 0;
|
||||
};
|
||||
|
||||
@@ -108,16 +112,16 @@ public:
|
||||
virtual void SetOpcode(EmuOpcode emu_op, uint16 eq_op);
|
||||
|
||||
protected:
|
||||
class NormalMemStrategy : public OpcodeManager::OpcodeSetStrategy {
|
||||
class NormalMemStrategy : public OpcodeManager::OpcodeSetStrategy
|
||||
{
|
||||
public:
|
||||
virtual ~NormalMemStrategy() {} //shut up compiler!
|
||||
RegularOpcodeManager *it;
|
||||
void Set(EmuOpcode emu_op, uint16 eq_op);
|
||||
};
|
||||
friend class NormalMemStrategy;
|
||||
RegularOpcodeManager* it;
|
||||
|
||||
uint16 *emu_to_eq;
|
||||
EmuOpcode *eq_to_emu;
|
||||
virtual void Set(EmuOpcode emu_op, uint16 eq_op) override;
|
||||
};
|
||||
|
||||
uint16* emu_to_eq;
|
||||
EmuOpcode* eq_to_emu;
|
||||
uint32 EQOpcodeCount;
|
||||
uint32 EmuOpcodeCount;
|
||||
};
|
||||
|
||||
@@ -3221,7 +3221,7 @@ namespace RoF
|
||||
|
||||
buf.WriteString(new_message);
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_SpecialMesg, buf);
|
||||
auto outapp = new EQApplicationPacket(OP_SpecialMesg, std::move(buf));
|
||||
|
||||
dest->FastQueuePacket(&outapp, ack_req);
|
||||
delete in;
|
||||
|
||||
+15
-12
@@ -689,7 +689,7 @@ namespace RoF2
|
||||
EQApplicationPacket *outapp = nullptr;
|
||||
if (eq->bufffade == 1)
|
||||
{
|
||||
outapp = new EQApplicationPacket(OP_BuffCreate, 29);
|
||||
outapp = new EQApplicationPacket(OP_BuffCreate, 29u);
|
||||
outapp->WriteUInt32(emu->entityid);
|
||||
outapp->WriteUInt32(0); // tic timer
|
||||
outapp->WriteUInt8(0); // Type of OP_BuffCreate packet ?
|
||||
@@ -753,7 +753,7 @@ namespace RoF2
|
||||
ar(bl);
|
||||
|
||||
//packet size
|
||||
auto packet_size = bl.item_name.length() + 1 + 34;
|
||||
size_t packet_size = bl.item_name.length() + 1 + 34;
|
||||
for (auto const &b: bl.trade_items) {
|
||||
packet_size += b.item_name.length() + 1;
|
||||
packet_size += 12;
|
||||
@@ -1622,7 +1622,7 @@ namespace RoF2
|
||||
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Yourname is %s", gu2->yourname);
|
||||
|
||||
int MemberCount = 1;
|
||||
int PacketLength = 8 + strlen(gu2->leadersname) + 1 + 22 + strlen(gu2->yourname) + 1;
|
||||
uint32 PacketLength = 8 + strlen(gu2->leadersname) + 1 + 22 + strlen(gu2->yourname) + 1;
|
||||
|
||||
for (int i = 0; i < 5; ++i)
|
||||
{
|
||||
@@ -2207,7 +2207,7 @@ namespace RoF2
|
||||
|
||||
char *Buffer = (char *)in->pBuffer;
|
||||
|
||||
int PacketSize = sizeof(structs::MercenaryMerchantList_Struct) - 4 + emu->MercTypeCount * 4;
|
||||
uint32 PacketSize = sizeof(structs::MercenaryMerchantList_Struct) - 4 + emu->MercTypeCount * 4;
|
||||
PacketSize += (sizeof(structs::MercenaryListEntry_Struct) - sizeof(structs::MercenaryStance_Struct)) * emu->MercCount;
|
||||
|
||||
uint32 r;
|
||||
@@ -2278,15 +2278,19 @@ namespace RoF2
|
||||
// There are 2 different sized versions of this packet depending if a merc is hired or not
|
||||
if (emu->MercStatus >= 0)
|
||||
{
|
||||
PacketSize += sizeof(structs::MercenaryDataUpdate_Struct) + (sizeof(structs::MercenaryData_Struct) - sizeof(structs::MercenaryStance_Struct)) * emu->MercCount;
|
||||
|
||||
// Per-merc size: base struct minus Stances[1] and MercUnk05,
|
||||
// then add back actual stances and name length per merc.
|
||||
// MercUnk05 is a single trailing field after all mercs.
|
||||
PacketSize += sizeof(structs::MercenaryDataUpdate_Struct);
|
||||
uint32 r;
|
||||
uint32 k;
|
||||
for (r = 0; r < emu->MercCount; r++)
|
||||
{
|
||||
PacketSize += sizeof(structs::MercenaryData_Struct) - sizeof(structs::MercenaryStance_Struct) - sizeof(uint32); // subtract Stances[1] and MercUnk05
|
||||
PacketSize += sizeof(structs::MercenaryStance_Struct) * emu->MercData[r].StanceCount;
|
||||
PacketSize += strlen(emu->MercData[r].MercName); // Null Terminator size already accounted for in the struct
|
||||
}
|
||||
PacketSize += sizeof(uint32); // MercUnk05 - trailing field after all mercs
|
||||
|
||||
outapp = new EQApplicationPacket(OP_MercenaryDataUpdate, PacketSize);
|
||||
Buffer = (char *)outapp->pBuffer;
|
||||
@@ -2312,15 +2316,14 @@ namespace RoF2
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->MercData[r].StanceCount);
|
||||
VARSTRUCT_ENCODE_TYPE(int32, Buffer, emu->MercData[r].MercUnk03);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->MercData[r].MercUnk04);
|
||||
//VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // MercName
|
||||
VARSTRUCT_ENCODE_STRING(Buffer, emu->MercData[r].MercName);
|
||||
for (k = 0; k < emu->MercData[r].StanceCount; k++)
|
||||
{
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->MercData[r].Stances[k].StanceIndex);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->MercData[r].Stances[k].Stance);
|
||||
}
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 1); // MercUnk05
|
||||
}
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->MercData[0].MercUnk05); // MercUnk05 - trailing field (unlocked slot count)
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3820,7 +3823,7 @@ namespace RoF2
|
||||
|
||||
buf.WriteString(new_message);
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_SpecialMesg, buf);
|
||||
auto outapp = new EQApplicationPacket(OP_SpecialMesg, std::move(buf));
|
||||
|
||||
dest->FastQueuePacket(&outapp, ack_req);
|
||||
delete in;
|
||||
@@ -4120,8 +4123,8 @@ namespace RoF2
|
||||
std::begin(emu->items),
|
||||
std::end(emu->items),
|
||||
std::begin(eq->items),
|
||||
[&](const uint32 x) {
|
||||
return x;
|
||||
[&](uint64 x) {
|
||||
return static_cast<uint32>(x);
|
||||
}
|
||||
);
|
||||
std::copy_n(
|
||||
@@ -4599,7 +4602,7 @@ namespace RoF2
|
||||
int k;
|
||||
for (r = 0; r < entrycount; r++, emu++) {
|
||||
|
||||
int PacketSize = 206;
|
||||
uint32 PacketSize = 206;
|
||||
|
||||
PacketSize += strlen(emu->name);
|
||||
PacketSize += strlen(emu->lastName);
|
||||
|
||||
@@ -2128,7 +2128,7 @@ namespace SoD
|
||||
|
||||
buf.WriteString(new_message);
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_SpecialMesg, buf);
|
||||
auto outapp = new EQApplicationPacket(OP_SpecialMesg, std::move(buf));
|
||||
|
||||
dest->FastQueuePacket(&outapp, ack_req);
|
||||
delete in;
|
||||
|
||||
@@ -1785,7 +1785,7 @@ namespace SoF
|
||||
|
||||
buf.WriteString(new_message);
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_SpecialMesg, buf);
|
||||
auto outapp = new EQApplicationPacket(OP_SpecialMesg, std::move(buf));
|
||||
|
||||
dest->FastQueuePacket(&outapp, ack_req);
|
||||
delete in;
|
||||
|
||||
@@ -1991,7 +1991,7 @@ namespace Titanium
|
||||
|
||||
buf.WriteString(new_message);
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_SpecialMesg, buf);
|
||||
auto outapp = new EQApplicationPacket(OP_SpecialMesg, std::move(buf));
|
||||
|
||||
dest->FastQueuePacket(&outapp, ack_req);
|
||||
delete in;
|
||||
|
||||
@@ -2711,7 +2711,7 @@ namespace UF
|
||||
|
||||
buf.WriteString(new_message);
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_SpecialMesg, buf);
|
||||
auto outapp = new EQApplicationPacket(OP_SpecialMesg, std::move(buf));
|
||||
|
||||
dest->FastQueuePacket(&outapp, ack_req);
|
||||
delete in;
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#ifdef _WINDOWS
|
||||
|
||||
#include "common/platform/win/include_windows.h"
|
||||
#include <WinSock2.h>
|
||||
|
||||
#endif // _WINDOWS
|
||||
|
||||
+3
-1
@@ -23,11 +23,13 @@
|
||||
|
||||
inline std::string random_string(size_t length)
|
||||
{
|
||||
auto randchar = []() -> char {
|
||||
auto randchar = []() -> char
|
||||
{
|
||||
const char charset[] = "0123456789" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz";
|
||||
const size_t max_index = (sizeof(charset) - 1);
|
||||
return charset[static_cast<size_t>(std::rand()) % max_index];
|
||||
};
|
||||
|
||||
std::string str(length, 0);
|
||||
std::generate_n(str.begin(), length, randchar);
|
||||
return str;
|
||||
|
||||
@@ -255,6 +255,7 @@ RULE_BOOL(Mercs, AllowMercSuspendInCombat, true, "Allow merc suspend in combat")
|
||||
RULE_BOOL(Mercs, MercsIgnoreLevelBasedHasteCaps, false, "Ignores hard coded level based haste caps.")
|
||||
RULE_INT(Mercs, MercsHasteCap, 100, "Haste cap for non-v3(over haste) haste")
|
||||
RULE_INT(Mercs, MercsHastev3Cap, 25, "Haste cap for v3(over haste) haste")
|
||||
RULE_INT(Mercs, MaxMercSlots, 6, "Maximum number of mercenary slots per character (max = MAXMERCS)")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Guild)
|
||||
|
||||
+24
-20
@@ -27,7 +27,7 @@
|
||||
class SerializeBuffer
|
||||
{
|
||||
public:
|
||||
SerializeBuffer() : m_buffer(nullptr), m_capacity(0), m_pos(0) {}
|
||||
SerializeBuffer() = default;
|
||||
|
||||
explicit SerializeBuffer(size_t size) : m_capacity(size), m_pos(0)
|
||||
{
|
||||
@@ -35,8 +35,10 @@ public:
|
||||
memset(m_buffer, 0, size);
|
||||
}
|
||||
|
||||
SerializeBuffer(const SerializeBuffer &rhs)
|
||||
: m_buffer(new unsigned char[rhs.m_capacity]), m_capacity(rhs.m_capacity), m_pos(rhs.m_pos)
|
||||
SerializeBuffer(const SerializeBuffer& rhs)
|
||||
: m_buffer(new unsigned char[rhs.m_capacity])
|
||||
, m_capacity(rhs.m_capacity)
|
||||
, m_pos(rhs.m_pos)
|
||||
{
|
||||
memcpy(m_buffer, rhs.m_buffer, rhs.m_capacity);
|
||||
}
|
||||
@@ -53,30 +55,31 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
SerializeBuffer(SerializeBuffer &&rhs) : m_buffer(rhs.m_buffer), m_capacity(rhs.m_capacity), m_pos(rhs.m_pos)
|
||||
SerializeBuffer(SerializeBuffer&& rhs)
|
||||
: m_buffer(std::exchange(rhs.m_buffer, nullptr))
|
||||
, m_capacity(std::exchange(rhs.m_capacity, 0))
|
||||
, m_pos(std::exchange(rhs.m_pos, 0))
|
||||
{
|
||||
rhs.m_buffer = nullptr;
|
||||
rhs.m_capacity = 0;
|
||||
rhs.m_pos = 0;
|
||||
}
|
||||
|
||||
SerializeBuffer &operator=(SerializeBuffer &&rhs)
|
||||
SerializeBuffer& operator=(SerializeBuffer&& rhs)
|
||||
{
|
||||
if (this != &rhs) {
|
||||
if (this != &rhs)
|
||||
{
|
||||
delete[] m_buffer;
|
||||
|
||||
m_buffer = rhs.m_buffer;
|
||||
m_capacity = rhs.m_capacity;
|
||||
m_pos = rhs.m_pos;
|
||||
|
||||
rhs.m_buffer = nullptr;
|
||||
rhs.m_capacity = 0;
|
||||
rhs.m_pos = 0;
|
||||
m_buffer = std::exchange(rhs.m_buffer, nullptr);
|
||||
m_capacity = std::exchange(rhs.m_capacity, 0);
|
||||
m_pos = std::exchange(rhs.m_pos, 0);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
~SerializeBuffer() { delete[] m_buffer; }
|
||||
~SerializeBuffer()
|
||||
{
|
||||
delete[] m_buffer;
|
||||
}
|
||||
|
||||
void WriteUInt8(uint8_t v)
|
||||
{
|
||||
@@ -209,7 +212,8 @@ public:
|
||||
private:
|
||||
void Grow(size_t new_size);
|
||||
void Reset();
|
||||
unsigned char *m_buffer;
|
||||
size_t m_capacity;
|
||||
size_t m_pos;
|
||||
|
||||
unsigned char* m_buffer = nullptr;
|
||||
size_t m_capacity = 0;
|
||||
size_t m_pos = 0;
|
||||
};
|
||||
|
||||
+28
-31
@@ -389,35 +389,31 @@ enum {
|
||||
class ServerPacket
|
||||
{
|
||||
public:
|
||||
~ServerPacket() { safe_delete_array(pBuffer); }
|
||||
ServerPacket(uint16 in_opcode = 0, uint32 in_size = 0) {
|
||||
this->compressed = false;
|
||||
size = in_size;
|
||||
opcode = in_opcode;
|
||||
if (size == 0) {
|
||||
pBuffer = 0;
|
||||
}
|
||||
else {
|
||||
~ServerPacket()
|
||||
{
|
||||
safe_delete_array(pBuffer);
|
||||
}
|
||||
|
||||
ServerPacket(uint16 in_opcode = 0, size_t in_size = 0)
|
||||
: size(static_cast<uint32>(in_size))
|
||||
, opcode(in_opcode)
|
||||
{
|
||||
if (size != 0)
|
||||
{
|
||||
pBuffer = new uchar[size];
|
||||
memset(pBuffer, 0, size);
|
||||
}
|
||||
_wpos = 0;
|
||||
_rpos = 0;
|
||||
}
|
||||
|
||||
ServerPacket(uint16 in_opcode, const EQ::Net::Packet &p) {
|
||||
this->compressed = false;
|
||||
size = (uint32)p.Length();
|
||||
opcode = in_opcode;
|
||||
if (size == 0) {
|
||||
pBuffer = 0;
|
||||
}
|
||||
else {
|
||||
ServerPacket(uint16 in_opcode, const EQ::Net::Packet& p)
|
||||
: size(static_cast<uint32>(p.Length()))
|
||||
, opcode(in_opcode)
|
||||
{
|
||||
if (size != 0)
|
||||
{
|
||||
pBuffer = new uchar[size];
|
||||
memcpy(pBuffer, p.Data(), size);
|
||||
}
|
||||
_wpos = 0;
|
||||
_rpos = 0;
|
||||
}
|
||||
|
||||
ServerPacket* Copy() {
|
||||
@@ -447,14 +443,14 @@ public:
|
||||
void ReadSkipBytes(uint32 count) { _rpos += count; }
|
||||
void SetReadPosition(uint32 Newrpos) { _rpos = Newrpos; }
|
||||
|
||||
uint32 size;
|
||||
uint16 opcode;
|
||||
uchar* pBuffer;
|
||||
uint32 _wpos;
|
||||
uint32 _rpos;
|
||||
bool compressed;
|
||||
uint32 InflatedSize;
|
||||
uint32 destination;
|
||||
uint32 size = 0;
|
||||
uint16 opcode = 0;
|
||||
uchar* pBuffer = nullptr;
|
||||
uint32 _wpos = 0;
|
||||
uint32 _rpos = 0;
|
||||
bool compressed = false;
|
||||
uint32 InflatedSize = 0;
|
||||
uint32 destination = 0;
|
||||
};
|
||||
|
||||
#pragma pack(push)
|
||||
@@ -989,11 +985,12 @@ struct LauncherConnectInfo {
|
||||
char name[64];
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
enum ZoneRequestCommands {
|
||||
ZR_Start,
|
||||
ZR_Restart,
|
||||
ZR_Stop
|
||||
} ZoneRequestCommands;
|
||||
};
|
||||
|
||||
struct LauncherZoneRequest {
|
||||
uint8 command;
|
||||
char short_name[33];
|
||||
|
||||
+1
-1
@@ -999,7 +999,7 @@ uint8 GetSpellLevel(uint16 spell_id, uint8 class_id)
|
||||
return UINT8_MAX;
|
||||
}
|
||||
|
||||
if (class_id >= Class::PLAYER_CLASS_COUNT) {
|
||||
if (class_id < Class::Warrior || class_id > Class::PLAYER_CLASS_COUNT) {
|
||||
return UINT8_MAX;
|
||||
}
|
||||
|
||||
|
||||
+50
-109
@@ -380,118 +380,59 @@ std::string Strings::NumberToWords(unsigned long long int n)
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string Strings::Money(uint64 platinum, uint64 gold, uint64 silver, uint64 copper)
|
||||
{
|
||||
std::string money_string = "Unknown";
|
||||
if (copper && silver && gold && platinum) { // CSGP
|
||||
money_string = fmt::format(
|
||||
"{} platinum, {} gold, {} silver, and {} copper",
|
||||
Strings::Commify(std::to_string(platinum)),
|
||||
Strings::Commify(std::to_string(gold)),
|
||||
Strings::Commify(std::to_string(silver)),
|
||||
Strings::Commify(std::to_string(copper))
|
||||
);
|
||||
std::string Strings::Money(uint64 platinum, uint64 gold, uint64 silver, uint64 copper, bool commify) {
|
||||
uint64 values[] = { platinum, gold, silver, copper };
|
||||
const char* names[] = { " platinum", " gold", " silver", " copper" };
|
||||
|
||||
std::vector<std::string> parts;
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (values[i] > 0) {
|
||||
std::string s = std::to_string(values[i]);
|
||||
parts.push_back((commify ? Strings::Commify(s) : s) + names[i]);
|
||||
}
|
||||
}
|
||||
else if (copper && silver && !gold && platinum) { // CSP
|
||||
money_string = fmt::format(
|
||||
"{} platinum, {} silver, and {} copper",
|
||||
Strings::Commify(std::to_string(platinum)),
|
||||
Strings::Commify(std::to_string(silver)),
|
||||
Strings::Commify(std::to_string(copper))
|
||||
);
|
||||
|
||||
if (parts.empty()) return "0 copper";
|
||||
if (parts.size() == 1) return parts[0];
|
||||
|
||||
std::string result;
|
||||
for (size_t i = 0; i < parts.size(); ++i) {
|
||||
result += parts[i];
|
||||
if (i < parts.size() - 2) {
|
||||
result += ", ";
|
||||
}
|
||||
else if (i == parts.size() - 2) {
|
||||
// Oxford comma logic: ", and " for 3+ items, " and " for 2
|
||||
result += (parts.size() > 2) ? ", and " : " and ";
|
||||
}
|
||||
}
|
||||
else if (copper && silver && gold && !platinum) { // CSG
|
||||
money_string = fmt::format(
|
||||
"{} gold, {} silver, and {} copper",
|
||||
Strings::Commify(std::to_string(gold)),
|
||||
Strings::Commify(std::to_string(silver)),
|
||||
Strings::Commify(std::to_string(copper))
|
||||
);
|
||||
}
|
||||
else if (copper && !silver && !gold && platinum) { // CP
|
||||
money_string = fmt::format(
|
||||
"{} platinum and {} copper",
|
||||
Strings::Commify(std::to_string(platinum)),
|
||||
Strings::Commify(std::to_string(copper))
|
||||
);
|
||||
}
|
||||
else if (copper && silver && !gold && !platinum) { // CS
|
||||
money_string = fmt::format(
|
||||
"{} silver and {} copper",
|
||||
Strings::Commify(std::to_string(silver)),
|
||||
Strings::Commify(std::to_string(copper))
|
||||
);
|
||||
}
|
||||
else if (!copper && silver && gold && platinum) { // SGP
|
||||
money_string = fmt::format(
|
||||
"{} platinum, {} gold, and {} silver",
|
||||
Strings::Commify(std::to_string(platinum)),
|
||||
Strings::Commify(std::to_string(gold)),
|
||||
Strings::Commify(std::to_string(silver))
|
||||
);
|
||||
}
|
||||
else if (!copper && silver && !gold && platinum) { // SP
|
||||
money_string = fmt::format(
|
||||
"{} platinum and {} silver",
|
||||
Strings::Commify(std::to_string(platinum)),
|
||||
Strings::Commify(std::to_string(silver))
|
||||
);
|
||||
}
|
||||
else if (!copper && silver && gold && !platinum) { // SG
|
||||
money_string = fmt::format(
|
||||
"{} gold and {} silver",
|
||||
Strings::Commify(std::to_string(gold)),
|
||||
Strings::Commify(std::to_string(silver))
|
||||
);
|
||||
}
|
||||
else if (copper && !silver && gold && platinum) { // CGP
|
||||
money_string = fmt::format(
|
||||
"{} platinum, {} gold, and {} copper",
|
||||
Strings::Commify(std::to_string(platinum)),
|
||||
Strings::Commify(std::to_string(gold)),
|
||||
Strings::Commify(std::to_string(copper))
|
||||
);
|
||||
}
|
||||
else if (copper && !silver && gold && !platinum) { // CG
|
||||
money_string = fmt::format(
|
||||
"{} gold and {} copper",
|
||||
Strings::Commify(std::to_string(gold)),
|
||||
Strings::Commify(std::to_string(copper))
|
||||
);
|
||||
}
|
||||
else if (!copper && !silver && gold && platinum) { // GP
|
||||
money_string = fmt::format(
|
||||
"{} platinum and {} gold",
|
||||
Strings::Commify(std::to_string(platinum)),
|
||||
Strings::Commify(std::to_string(gold))
|
||||
);
|
||||
}
|
||||
else if (!copper && !silver && !gold && platinum) { // P
|
||||
money_string = fmt::format(
|
||||
"{} platinum",
|
||||
Strings::Commify(std::to_string(platinum))
|
||||
);
|
||||
}
|
||||
else if (!copper && !silver && gold && !platinum) { // G
|
||||
money_string = fmt::format(
|
||||
"{} gold",
|
||||
Strings::Commify(std::to_string(gold))
|
||||
);
|
||||
}
|
||||
else if (!copper && silver && !gold && !platinum) { // S
|
||||
money_string = fmt::format(
|
||||
"{} silver",
|
||||
Strings::Commify(std::to_string(silver))
|
||||
);
|
||||
}
|
||||
else if (copper && !silver && !gold && !platinum) { // C
|
||||
money_string = fmt::format(
|
||||
"{} copper",
|
||||
Strings::Commify(std::to_string(copper))
|
||||
);
|
||||
}
|
||||
return money_string;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string Strings::MoneyShort(uint64 copper, bool commify) {
|
||||
// Matches merchant format
|
||||
uint64 values[] = {
|
||||
copper / 1000,
|
||||
(copper / 100) % 10,
|
||||
(copper / 10) % 10,
|
||||
copper % 10
|
||||
};
|
||||
const char* names[] = { " platinum", " gold", " silver", " copper" };
|
||||
|
||||
std::string result;
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (values[i] > 0) {
|
||||
if (!result.empty()) result += " ";
|
||||
|
||||
std::string s = std::to_string(values[i]);
|
||||
result += (commify ? Strings::Commify(s) : s) + names[i];
|
||||
}
|
||||
}
|
||||
|
||||
return result.empty() ? "0 copper" : result;
|
||||
}
|
||||
|
||||
std::string Strings::SecondsToTime(int duration, bool is_milliseconds)
|
||||
{
|
||||
if (duration <= 0) {
|
||||
|
||||
+2
-1
@@ -62,7 +62,8 @@ public:
|
||||
static std::string Join(const std::vector<std::string> &ar, const std::string &delim);
|
||||
static std::string Join(const std::vector<uint32_t> &ar, const std::string &delim);
|
||||
static std::string MillisecondsToTime(int duration);
|
||||
static std::string Money(uint64 platinum, uint64 gold = 0, uint64 silver = 0, uint64 copper = 0);
|
||||
static std::string Money(uint64 platinum, uint64 gold = 0, uint64 silver = 0, uint64 copper = 0, bool commify = true);
|
||||
static std::string MoneyShort(uint64 copper = 0, bool commify = true); // Matches merchant format when commify is false
|
||||
static std::string NumberToWords(unsigned long long int n);
|
||||
static std::string Repeat(std::string s, int n);
|
||||
static std::string Replace(std::string subject, const std::string &search, const std::string &replace);
|
||||
|
||||
+2
-2
@@ -38,10 +38,10 @@
|
||||
#define RELOADTASKS 0
|
||||
#define RELOADTASKSETS 2
|
||||
|
||||
typedef enum {
|
||||
enum TaskMethodType {
|
||||
METHODSINGLEID = 0,
|
||||
METHODQUEST = 2
|
||||
} TaskMethodType;
|
||||
};
|
||||
|
||||
enum class TaskActivityType : int32_t // task element/objective
|
||||
{
|
||||
|
||||
@@ -103,7 +103,7 @@ namespace luabind { namespace detail
|
||||
if (luabind::move_back_reference(L, ptr))
|
||||
return;
|
||||
|
||||
make_instance(L, std::auto_ptr<T>(ptr));
|
||||
make_instance(L, std::unique_ptr<T>(ptr));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -335,7 +335,7 @@ namespace luabind
|
||||
template <class T>
|
||||
struct default_pointer<null_type, T>
|
||||
{
|
||||
typedef std::auto_ptr<T> type;
|
||||
typedef std::unique_ptr<T> type;
|
||||
};
|
||||
|
||||
template <class Class, class Pointer, class Signature, class Policies>
|
||||
|
||||
@@ -46,7 +46,7 @@ struct construct_aux<0, T, Pointer, Signature>
|
||||
object_rep* self = touserdata<object_rep>(self_);
|
||||
class_rep* cls = self->crep();
|
||||
|
||||
std::auto_ptr<T> instance(new T);
|
||||
std::unique_ptr<T> instance(new T);
|
||||
inject_backref(self_.interpreter(), instance.get(), instance.get());
|
||||
|
||||
void* naked_ptr = instance.get();
|
||||
@@ -55,7 +55,7 @@ struct construct_aux<0, T, Pointer, Signature>
|
||||
void* storage = self->allocate(sizeof(holder_type));
|
||||
|
||||
self->set_instance(new (storage) holder_type(
|
||||
ptr, registered_class<T>::id, naked_ptr, cls));
|
||||
std::move(ptr), registered_class<T>::id, naked_ptr, cls));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -92,7 +92,7 @@ struct construct_aux<N, T, Pointer, Signature>
|
||||
object_rep* self = touserdata<object_rep>(self_);
|
||||
class_rep* cls = self->crep();
|
||||
|
||||
std::auto_ptr<T> instance(new T(BOOST_PP_ENUM_PARAMS(N,_)));
|
||||
std::unique_ptr<T> instance(new T(BOOST_PP_ENUM_PARAMS(N,_)));
|
||||
inject_backref(self_.interpreter(), instance.get(), instance.get());
|
||||
|
||||
void* naked_ptr = instance.get();
|
||||
@@ -101,7 +101,7 @@ struct construct_aux<N, T, Pointer, Signature>
|
||||
void* storage = self->allocate(sizeof(holder_type));
|
||||
|
||||
self->set_instance(new (storage) holder_type(
|
||||
ptr, registered_class<T>::id, naked_ptr, cls));
|
||||
std::move(ptr), registered_class<T>::id, naked_ptr, cls));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace has_get_pointer_
|
||||
T* get_pointer(T const volatile*);
|
||||
|
||||
template<class T>
|
||||
T* get_pointer(std::auto_ptr<T> const&);
|
||||
T* get_pointer(std::unique_ptr<T> const&);
|
||||
|
||||
# endif
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ inline mpl::true_ check_const_pointer(void const*)
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void release_ownership(std::auto_ptr<T>& p)
|
||||
void release_ownership(std::unique_ptr<T>& p)
|
||||
{
|
||||
p.release();
|
||||
}
|
||||
@@ -83,7 +83,7 @@ public:
|
||||
P p, class_id dynamic_id, void* dynamic_ptr, class_rep* cls
|
||||
)
|
||||
: instance_holder(cls, check_const_pointer(false ? get_pointer(p) : 0))
|
||||
, p(p)
|
||||
, p(std::move(p))
|
||||
, weak(0)
|
||||
, dynamic_id(dynamic_id)
|
||||
, dynamic_ptr(dynamic_ptr)
|
||||
|
||||
@@ -88,7 +88,7 @@ void make_instance(lua_State* L, P p)
|
||||
|
||||
try
|
||||
{
|
||||
new (storage) holder_type(p, dynamic.first, dynamic.second, cls);
|
||||
new (storage) holder_type(std::move(p), dynamic.first, dynamic.second, cls);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
||||
@@ -169,7 +169,7 @@ namespace luabind { namespace detail
|
||||
{
|
||||
if (get_pointer(x))
|
||||
{
|
||||
make_instance(L, x);
|
||||
make_instance(L, std::move(x));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -180,8 +180,8 @@ namespace luabind { namespace detail
|
||||
template <class T>
|
||||
void make_pointee_instance(lua_State* L, T& x, mpl::false_, mpl::true_)
|
||||
{
|
||||
std::auto_ptr<T> ptr(new T(x));
|
||||
make_instance(L, ptr);
|
||||
std::unique_ptr<T> ptr(new T(x));
|
||||
make_instance(L, std::move(ptr));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace detail
|
||||
template <class F, class Policies>
|
||||
scope def(char const* name, F f, Policies const& policies)
|
||||
{
|
||||
return scope(std::auto_ptr<detail::registration>(
|
||||
return scope(std::unique_ptr<detail::registration>(
|
||||
new detail::function_registration<F, Policies>(name, f, policies)));
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace luabind {
|
||||
struct LUABIND_API scope
|
||||
{
|
||||
scope();
|
||||
explicit scope(std::auto_ptr<detail::registration> reg);
|
||||
explicit scope(std::unique_ptr<detail::registration> reg);
|
||||
scope(scope const& other_);
|
||||
~scope();
|
||||
|
||||
|
||||
@@ -235,7 +235,7 @@ namespace luabind { namespace detail {
|
||||
// -- interface ---------------------------------------------------------
|
||||
|
||||
class_base::class_base(char const* name)
|
||||
: scope(std::auto_ptr<registration>(
|
||||
: scope(std::unique_ptr<registration>(
|
||||
m_registration = new class_registration(name))
|
||||
)
|
||||
{
|
||||
@@ -258,14 +258,14 @@ namespace luabind { namespace detail {
|
||||
|
||||
void class_base::add_member(registration* member)
|
||||
{
|
||||
std::auto_ptr<registration> ptr(member);
|
||||
m_registration->m_members.operator,(scope(ptr));
|
||||
std::unique_ptr<registration> ptr(member);
|
||||
m_registration->m_members.operator,(scope(std::move(ptr)));
|
||||
}
|
||||
|
||||
void class_base::add_default_member(registration* member)
|
||||
{
|
||||
std::auto_ptr<registration> ptr(member);
|
||||
m_registration->m_default_members.operator,(scope(ptr));
|
||||
std::unique_ptr<registration> ptr(member);
|
||||
m_registration->m_default_members.operator,(scope(std::move(ptr)));
|
||||
}
|
||||
|
||||
const char* class_base::name() const
|
||||
|
||||
@@ -94,7 +94,7 @@ namespace
|
||||
{
|
||||
m_cache.insert(std::make_pair(
|
||||
key_type(src, target, dynamic_id, object_offset)
|
||||
, cache_entry(offset, distance)
|
||||
, cache_entry(offset, static_cast<int>(distance))
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,8 @@ namespace luabind { namespace detail {
|
||||
{
|
||||
}
|
||||
|
||||
scope::scope(std::auto_ptr<detail::registration> reg)
|
||||
|
||||
scope::scope(std::unique_ptr<detail::registration> reg)
|
||||
: m_chain(reg.release())
|
||||
{
|
||||
}
|
||||
@@ -193,7 +194,7 @@ namespace luabind {
|
||||
};
|
||||
|
||||
namespace_::namespace_(char const* name)
|
||||
: scope(std::auto_ptr<detail::registration>(
|
||||
: scope(std::unique_ptr<detail::registration>(
|
||||
m_registration = new registration_(name)))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -37,3 +37,13 @@ target_include_directories(loginserver PRIVATE ..)
|
||||
|
||||
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
|
||||
set_property(TARGET loginserver PROPERTY FOLDER executables/servers)
|
||||
|
||||
# vcpkg doesn't copy legacy.dll automatically because it is loaded at runtime, not via the import table.
|
||||
if(WIN32 AND DEFINED VCPKG_INSTALLED_DIR AND DEFINED VCPKG_TARGET_TRIPLET)
|
||||
add_custom_command(TARGET loginserver POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"$<IF:$<CONFIG:Debug>,${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/debug/bin/legacy.dll,${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/bin/legacy.dll>"
|
||||
"$<TARGET_FILE_DIR:loginserver>/legacy.dll"
|
||||
VERBATIM
|
||||
)
|
||||
endif()
|
||||
|
||||
+53
-126
@@ -88,9 +88,6 @@ bool Client::Process()
|
||||
SendPlayToWorld((const char *) app->pBuffer);
|
||||
break;
|
||||
}
|
||||
case OP_SystemFingerprint: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
delete app;
|
||||
@@ -107,19 +104,16 @@ void Client::HandleSessionReady(const char *data, unsigned int size)
|
||||
return;
|
||||
}
|
||||
|
||||
if (size < sizeof(int32)) {
|
||||
if (size < sizeof(unsigned int)) {
|
||||
LogError("Session ready was too small");
|
||||
return;
|
||||
}
|
||||
|
||||
//existing sequence id
|
||||
int32 sequence_in = *(int32*)data;
|
||||
|
||||
m_client_status = cs_waiting_for_login;
|
||||
|
||||
auto *outapp = new EQApplicationPacket(OP_ChatMessage, sizeof(LoginHandShakeReply));
|
||||
auto buf = reinterpret_cast<LoginHandShakeReply *>(outapp->pBuffer);
|
||||
buf->base_header.sequence = sequence_in;
|
||||
buf->base_header.sequence = 0x02;
|
||||
buf->base_reply.success = true;
|
||||
buf->base_reply.error_str_id = 0x65; // 101 "No Error"
|
||||
|
||||
@@ -362,55 +356,28 @@ void Client::SendFailedLogin()
|
||||
m_stored_username.clear();
|
||||
m_stored_password.clear();
|
||||
|
||||
if (m_client_version == cv_steam_latest) {
|
||||
// unencrypted
|
||||
LoginBaseMessage h{};
|
||||
h.sequence = m_login_base_message.sequence; // login (3)
|
||||
h.encrypt_type = m_login_base_message.encrypt_type;
|
||||
// unencrypted
|
||||
LoginBaseMessage h{};
|
||||
h.sequence = m_login_base_message.sequence; // login (3)
|
||||
h.encrypt_type = m_login_base_message.encrypt_type;
|
||||
|
||||
// encrypted
|
||||
PlayerLoginReplySteamLatest r{};
|
||||
r.base_reply.success = false;
|
||||
r.base_reply.error_str_id = 105; // Error - The username and/or password were not valid
|
||||
// encrypted
|
||||
PlayerLoginReply r{};
|
||||
r.base_reply.success = false;
|
||||
r.base_reply.error_str_id = 105; // Error - The username and/or password were not valid
|
||||
|
||||
char encrypted_buffer[80] = { 0 };
|
||||
auto rc = eqcrypt_block((const char*)&r, sizeof(r), encrypted_buffer, 1);
|
||||
if (rc == nullptr) {
|
||||
LogDebug("Failed to encrypt eqcrypt block for failed login");
|
||||
}
|
||||
|
||||
constexpr int outsize = sizeof(LoginBaseMessage) + sizeof(encrypted_buffer);
|
||||
EQApplicationPacket outapp(OP_LoginAccepted, outsize);
|
||||
outapp.WriteData(&h, sizeof(h));
|
||||
outapp.WriteData(&encrypted_buffer, sizeof(encrypted_buffer));
|
||||
|
||||
m_connection->QueuePacket(&outapp);
|
||||
char encrypted_buffer[80] = {0};
|
||||
auto rc = eqcrypt_block((const char *) &r, sizeof(r), encrypted_buffer, 1);
|
||||
if (rc == nullptr) {
|
||||
LogDebug("Failed to encrypt eqcrypt block for failed login");
|
||||
}
|
||||
else {
|
||||
// unencrypted
|
||||
LoginBaseMessage h{};
|
||||
h.sequence = m_login_base_message.sequence; // login (3)
|
||||
h.encrypt_type = m_login_base_message.encrypt_type;
|
||||
|
||||
// encrypted
|
||||
PlayerLoginReply r{};
|
||||
r.base_reply.success = false;
|
||||
r.base_reply.error_str_id = 105; // Error - The username and/or password were not valid
|
||||
constexpr int outsize = sizeof(LoginBaseMessage) + sizeof(encrypted_buffer);
|
||||
EQApplicationPacket outapp(OP_LoginAccepted, outsize);
|
||||
outapp.WriteData(&h, sizeof(h));
|
||||
outapp.WriteData(&encrypted_buffer, sizeof(encrypted_buffer));
|
||||
|
||||
char encrypted_buffer[80] = { 0 };
|
||||
auto rc = eqcrypt_block((const char*)&r, sizeof(r), encrypted_buffer, 1);
|
||||
if (rc == nullptr) {
|
||||
LogDebug("Failed to encrypt eqcrypt block for failed login");
|
||||
}
|
||||
|
||||
constexpr int outsize = sizeof(LoginBaseMessage) + sizeof(encrypted_buffer);
|
||||
EQApplicationPacket outapp(OP_LoginAccepted, outsize);
|
||||
outapp.WriteData(&h, sizeof(h));
|
||||
outapp.WriteData(&encrypted_buffer, sizeof(encrypted_buffer));
|
||||
|
||||
m_connection->QueuePacket(&outapp);
|
||||
}
|
||||
|
||||
m_connection->QueuePacket(&outapp);
|
||||
m_client_status = cs_failed_to_login;
|
||||
}
|
||||
|
||||
@@ -496,86 +463,46 @@ void Client::DoSuccessfulLogin(LoginAccountsRepository::LoginAccounts &a)
|
||||
m_account_name = a.account_name;
|
||||
m_loginserver_name = a.source_loginserver;
|
||||
|
||||
if (m_client_version == cv_steam_latest) {
|
||||
// unencrypted
|
||||
LoginBaseMessage h{};
|
||||
h.sequence = m_login_base_message.sequence;
|
||||
h.compressed = false;
|
||||
h.encrypt_type = m_login_base_message.encrypt_type;
|
||||
h.unk3 = m_login_base_message.unk3;
|
||||
// unencrypted
|
||||
LoginBaseMessage h{};
|
||||
h.sequence = m_login_base_message.sequence;
|
||||
h.compressed = false;
|
||||
h.encrypt_type = m_login_base_message.encrypt_type;
|
||||
h.unk3 = m_login_base_message.unk3;
|
||||
|
||||
// not serializing any of the variable length strings so just use struct directly
|
||||
PlayerLoginReplySteamLatest r{};
|
||||
r.base_reply.success = true;
|
||||
r.base_reply.error_str_id = 101; // No Error
|
||||
r.unk1 = 0;
|
||||
r.unk2 = 0;
|
||||
r.lsid = a.id;
|
||||
r.failed_attempts = 0;
|
||||
r.show_player_count = server.options.IsShowPlayerCountEnabled();
|
||||
r.unk3 = 0;
|
||||
r.unk4 = 0;
|
||||
memcpy(r.key, m_key.c_str(), m_key.size());
|
||||
// not serializing any of the variable length strings so just use struct directly
|
||||
PlayerLoginReply r{};
|
||||
r.base_reply.success = true;
|
||||
r.base_reply.error_str_id = 101; // No Error
|
||||
r.unk1 = 0;
|
||||
r.unk2 = 0;
|
||||
r.lsid = a.id;
|
||||
r.failed_attempts = 0;
|
||||
r.show_player_count = server.options.IsShowPlayerCountEnabled();
|
||||
r.offer_min_days = 99;
|
||||
r.offer_min_views = -1;
|
||||
r.offer_cooldown_minutes = 0;
|
||||
r.web_offer_number = 0;
|
||||
r.web_offer_min_days = 99;
|
||||
r.web_offer_min_views = -1;
|
||||
r.web_offer_cooldown_minutes = 0;
|
||||
memcpy(r.key, m_key.c_str(), m_key.size());
|
||||
|
||||
//todo: needs to be fixed
|
||||
//SendExpansionPacketData(r);
|
||||
SendExpansionPacketData(r);
|
||||
|
||||
char encrypted_buffer[80] = { 0 };
|
||||
char encrypted_buffer[80] = {0};
|
||||
|
||||
auto rc = eqcrypt_block((const char*)&r, sizeof(r), encrypted_buffer, 1);
|
||||
if (rc == nullptr) {
|
||||
LogDebug("Failed to encrypt eqcrypt block");
|
||||
}
|
||||
|
||||
constexpr int outsize = sizeof(LoginBaseMessage) + sizeof(encrypted_buffer);
|
||||
auto outapp = std::make_unique<EQApplicationPacket>(OP_LoginAccepted, outsize);
|
||||
outapp->WriteData(&h, sizeof(h));
|
||||
outapp->WriteData(&encrypted_buffer, sizeof(encrypted_buffer));
|
||||
|
||||
m_connection->QueuePacket(outapp.get());
|
||||
auto rc = eqcrypt_block((const char *) &r, sizeof(r), encrypted_buffer, 1);
|
||||
if (rc == nullptr) {
|
||||
LogDebug("Failed to encrypt eqcrypt block");
|
||||
}
|
||||
else {
|
||||
// unencrypted
|
||||
LoginBaseMessage h{};
|
||||
h.sequence = m_login_base_message.sequence;
|
||||
h.compressed = false;
|
||||
h.encrypt_type = m_login_base_message.encrypt_type;
|
||||
h.unk3 = m_login_base_message.unk3;
|
||||
|
||||
// not serializing any of the variable length strings so just use struct directly
|
||||
PlayerLoginReply r{};
|
||||
r.base_reply.success = true;
|
||||
r.base_reply.error_str_id = 101; // No Error
|
||||
r.unk1 = 0;
|
||||
r.unk2 = 0;
|
||||
r.lsid = a.id;
|
||||
r.failed_attempts = 0;
|
||||
r.show_player_count = server.options.IsShowPlayerCountEnabled();
|
||||
r.offer_min_days = 99;
|
||||
r.offer_min_views = -1;
|
||||
r.offer_cooldown_minutes = 0;
|
||||
r.web_offer_number = 0;
|
||||
r.web_offer_min_days = 99;
|
||||
r.web_offer_min_views = -1;
|
||||
r.web_offer_cooldown_minutes = 0;
|
||||
memcpy(r.key, m_key.c_str(), m_key.size());
|
||||
constexpr int outsize = sizeof(LoginBaseMessage) + sizeof(encrypted_buffer);
|
||||
auto outapp = std::make_unique<EQApplicationPacket>(OP_LoginAccepted, outsize);
|
||||
outapp->WriteData(&h, sizeof(h));
|
||||
outapp->WriteData(&encrypted_buffer, sizeof(encrypted_buffer));
|
||||
|
||||
SendExpansionPacketData(r);
|
||||
|
||||
char encrypted_buffer[80] = { 0 };
|
||||
|
||||
auto rc = eqcrypt_block((const char*)&r, sizeof(r), encrypted_buffer, 1);
|
||||
if (rc == nullptr) {
|
||||
LogDebug("Failed to encrypt eqcrypt block");
|
||||
}
|
||||
|
||||
constexpr int outsize = sizeof(LoginBaseMessage) + sizeof(encrypted_buffer);
|
||||
auto outapp = std::make_unique<EQApplicationPacket>(OP_LoginAccepted, outsize);
|
||||
outapp->WriteData(&h, sizeof(h));
|
||||
outapp->WriteData(&encrypted_buffer, sizeof(encrypted_buffer));
|
||||
|
||||
m_connection->QueuePacket(outapp.get());
|
||||
}
|
||||
m_connection->QueuePacket(outapp.get());
|
||||
|
||||
m_client_status = cs_logged_in;
|
||||
}
|
||||
@@ -620,7 +547,7 @@ void Client::SendExpansionPacketData(PlayerLoginReply &plrs)
|
||||
buf.WriteInt32(0xFFFFFFFF);
|
||||
}
|
||||
|
||||
auto out = std::make_unique<EQApplicationPacket>(OP_LoginExpansionPacketData, buf);
|
||||
auto out = std::make_unique<EQApplicationPacket>(OP_LoginExpansionPacketData, std::move(buf));
|
||||
m_connection->QueuePacket(out.get());
|
||||
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ void CheckSoDOpcodeFile(const std::string &path)
|
||||
}
|
||||
}
|
||||
|
||||
void CheckSteamLatestOpcodeFile(const std::string &path)
|
||||
void CheckLarionOpcodeFile(const std::string &path)
|
||||
{
|
||||
if (File::Exists(path)) {
|
||||
return;
|
||||
@@ -87,15 +87,15 @@ void CheckSteamLatestOpcodeFile(const std::string &path)
|
||||
fprintf(f, "OP_Login=0x0002\n");
|
||||
fprintf(f, "OP_ServerListRequest=0x0004\n");
|
||||
fprintf(f, "OP_PlayEverquestRequest=0x000d\n");
|
||||
fprintf(f, "OP_PlayEverquestResponse=0x0023\n");
|
||||
fprintf(f, "OP_ChatMessage=0x0018\n");
|
||||
fprintf(f, "OP_LoginAccepted=0x0019\n");
|
||||
fprintf(f, "OP_ServerListResponse=0x001a\n");
|
||||
fprintf(f, "OP_Poll=0x002a\n");
|
||||
fprintf(f, "OP_PlayEverquestResponse=0x0022\n");
|
||||
fprintf(f, "OP_ChatMessage=0x0017\n");
|
||||
fprintf(f, "OP_LoginAccepted=0x0018\n");
|
||||
fprintf(f, "OP_ServerListResponse=0x0019\n");
|
||||
fprintf(f, "OP_Poll=0x0029\n");
|
||||
fprintf(f, "OP_EnterChat=0x000f\n");
|
||||
fprintf(f, "OP_PollResponse=0x0011\n");
|
||||
fprintf(f, "OP_SystemFingerprint=0x0016\n");
|
||||
fprintf(f, "OP_ExpansionList=0x0031\n");
|
||||
fprintf(f, "OP_ExpansionList=0x0030\n");
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
@@ -177,40 +177,40 @@ ClientManager::ClientManager()
|
||||
}
|
||||
);
|
||||
|
||||
int steam_latest_port = server.config.GetVariableInt("client_configuration", "steam_latest_port", 15900);
|
||||
int larion_port = server.config.GetVariableInt("client_configuration", "larion_port", 15900);
|
||||
|
||||
EQStreamManagerInterfaceOptions steam_latest_opts(steam_latest_port, false, false);
|
||||
EQStreamManagerInterfaceOptions larion_opts(larion_port, false, false);
|
||||
|
||||
m_steam_latest_stream = new EQ::Net::EQStreamManager(steam_latest_opts);
|
||||
m_steam_latest_ops = new RegularOpcodeManager;
|
||||
m_larion_stream = new EQ::Net::EQStreamManager(larion_opts);
|
||||
m_larion_ops = new RegularOpcodeManager;
|
||||
|
||||
opcodes_path = fmt::format(
|
||||
"{}/{}",
|
||||
PathManager::Instance()->GetOpcodePath(),
|
||||
"login_opcodes_steam_latest.conf"
|
||||
"login_opcodes_larion.conf"
|
||||
);
|
||||
|
||||
CheckSteamLatestOpcodeFile(opcodes_path);
|
||||
CheckLarionOpcodeFile(opcodes_path);
|
||||
|
||||
if (!m_steam_latest_ops->LoadOpcodes(opcodes_path.c_str())) {
|
||||
if (!m_larion_ops->LoadOpcodes(opcodes_path.c_str())) {
|
||||
LogError(
|
||||
"ClientManager fatal error: couldn't load opcodes for Steam Latest file [{}]",
|
||||
server.config.GetVariableString("client_configuration", "steam_latest_opcodes", "login_opcodes.conf")
|
||||
"ClientManager fatal error: couldn't load opcodes for Larion file [{}]",
|
||||
server.config.GetVariableString("client_configuration", "larion_opcodes", "login_opcodes.conf")
|
||||
);
|
||||
|
||||
run_server = false;
|
||||
}
|
||||
|
||||
m_steam_latest_stream->OnNewConnection(
|
||||
m_larion_stream->OnNewConnection(
|
||||
[this](std::shared_ptr<EQ::Net::EQStream> stream) {
|
||||
LogInfo(
|
||||
"New Steam Latest client connection from [{}:{}]",
|
||||
"New Larion client connection from [{}:{}]",
|
||||
long2ip(stream->GetRemoteIP()),
|
||||
stream->GetRemotePort()
|
||||
);
|
||||
|
||||
stream->SetOpcodeManager(&m_steam_latest_ops);
|
||||
Client *c = new Client(stream, cv_steam_latest);
|
||||
stream->SetOpcodeManager(&m_larion_ops);
|
||||
Client *c = new Client(stream, cv_larion);
|
||||
m_clients.push_back(c);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -37,6 +37,6 @@ private:
|
||||
EQ::Net::EQStreamManager *m_titanium_stream;
|
||||
OpcodeManager *m_sod_ops;
|
||||
EQ::Net::EQStreamManager *m_sod_stream;
|
||||
OpcodeManager *m_steam_latest_ops;
|
||||
EQ::Net::EQStreamManager *m_steam_latest_stream;
|
||||
OpcodeManager *m_larion_ops;
|
||||
EQ::Net::EQStreamManager *m_larion_stream;
|
||||
};
|
||||
|
||||
+114
-28
@@ -16,11 +16,12 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "encryption.h"
|
||||
#include "common/compiler_macros.h"
|
||||
|
||||
#ifdef EQEMU_USE_OPENSSL
|
||||
#include <openssl/des.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/md5.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/provider.h>
|
||||
#endif
|
||||
#ifdef EQEMU_USE_MBEDTLS
|
||||
#include <mbedtls/des.h>
|
||||
@@ -32,6 +33,8 @@
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#ifdef ENABLE_SECURITY
|
||||
|
||||
#include <sodium.h>
|
||||
@@ -127,21 +130,104 @@ const char *eqcrypt_block(const char *buffer_in, size_t buffer_in_sz, char *buff
|
||||
#endif
|
||||
|
||||
#ifdef EQEMU_USE_OPENSSL
|
||||
DES_key_schedule k;
|
||||
DES_cblock v;
|
||||
|
||||
memset(&k, 0, sizeof(DES_key_schedule));
|
||||
memset(&v, 0, sizeof(DES_cblock));
|
||||
|
||||
// Decrypt requires block-aligned input; encrypt zero-pads a trailing
|
||||
// partial block to match the legacy DES_ncbc_encrypt semantics the
|
||||
// game protocol expects.
|
||||
if (!enc && buffer_in_sz && buffer_in_sz % 8 != 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DES_ncbc_encrypt((const unsigned char*)buffer_in, (unsigned char*)buffer_out, (long)buffer_in_sz, &k, &v, enc);
|
||||
unsigned char key[8] = {0};
|
||||
unsigned char iv[8] = {0};
|
||||
|
||||
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
|
||||
if (!ctx) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool result = EVP_CipherInit_ex2(ctx, EVP_des_cbc(), key, iv, enc, nullptr) == 1;
|
||||
if (result) {
|
||||
EVP_CIPHER_CTX_set_padding(ctx, 0);
|
||||
|
||||
const unsigned char* src = reinterpret_cast<const unsigned char*>(buffer_in);
|
||||
size_t src_len = buffer_in_sz;
|
||||
std::unique_ptr<unsigned char[]> padded;
|
||||
|
||||
if (enc && buffer_in_sz % 8 != 0) {
|
||||
src_len = ((buffer_in_sz / 8) + 1) * 8;
|
||||
padded.reset(new unsigned char[src_len]());
|
||||
memcpy(padded.get(), buffer_in, buffer_in_sz);
|
||||
src = padded.get();
|
||||
}
|
||||
|
||||
int outl = 0;
|
||||
int final_len = 0;
|
||||
result = EVP_CipherUpdate(ctx, reinterpret_cast<unsigned char*>(buffer_out), &outl, src, static_cast<int>(src_len)) == 1
|
||||
&& EVP_CipherFinal_ex(ctx, reinterpret_cast<unsigned char*>(buffer_out) + outl, &final_len) == 1;
|
||||
}
|
||||
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
if (!result) {
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
return buffer_out;
|
||||
}
|
||||
|
||||
#ifdef EQEMU_USE_OPENSSL
|
||||
static OSSL_PROVIDER *s_legacy_provider = nullptr;
|
||||
static OSSL_PROVIDER *s_default_provider = nullptr;
|
||||
#endif
|
||||
|
||||
bool eqcrypt_init()
|
||||
{
|
||||
#ifdef EQEMU_USE_OPENSSL
|
||||
#ifdef _WIN32
|
||||
// Set OpenSSL default provider search path to the executable directory.
|
||||
char* exe_path = nullptr;
|
||||
if (_get_pgmptr(&exe_path) == 0 && exe_path != nullptr && *exe_path != '\0') {
|
||||
std::string exe_dir{exe_path};
|
||||
if (auto sep = exe_dir.find_last_of("\\/"); sep != std::string::npos) {
|
||||
exe_dir.resize(sep);
|
||||
OSSL_PROVIDER_set_default_search_path(nullptr, exe_dir.c_str());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!s_default_provider) {
|
||||
s_default_provider = OSSL_PROVIDER_load(nullptr, "default");
|
||||
}
|
||||
if (!s_legacy_provider) {
|
||||
s_legacy_provider = OSSL_PROVIDER_load(nullptr, "legacy");
|
||||
}
|
||||
|
||||
if (!s_default_provider || !s_legacy_provider) {
|
||||
char buf[256];
|
||||
while (auto err = ERR_get_error()) {
|
||||
ERR_error_string_n(err, buf, sizeof(buf));
|
||||
LogError("OpenSSL provider load failure: {}", buf);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void eqcrypt_shutdown()
|
||||
{
|
||||
#ifdef EQEMU_USE_OPENSSL
|
||||
if (s_legacy_provider) {
|
||||
OSSL_PROVIDER_unload(s_legacy_provider);
|
||||
s_legacy_provider = nullptr;
|
||||
}
|
||||
if (s_default_provider) {
|
||||
OSSL_PROVIDER_unload(s_default_provider);
|
||||
s_default_provider = nullptr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string eqcrypt_md5(const std::string &msg)
|
||||
{
|
||||
std::string ret;
|
||||
@@ -164,12 +250,12 @@ std::string eqcrypt_md5(const std::string &msg)
|
||||
unsigned char md5_digest[16];
|
||||
char tmp[4];
|
||||
|
||||
MD5((const unsigned char*)msg.c_str(), msg.length(), md5_digest);
|
||||
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
sprintf(&tmp[0], "%02x", md5_digest[i]);
|
||||
ret.push_back(tmp[0]);
|
||||
ret.push_back(tmp[1]);
|
||||
if (EVP_Digest(msg.data(), msg.length(), md5_digest, nullptr, EVP_md5(), nullptr) == 1) {
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
sprintf(&tmp[0], "%02x", md5_digest[i]);
|
||||
ret.push_back(tmp[0]);
|
||||
ret.push_back(tmp[1]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -198,12 +284,12 @@ std::string eqcrypt_sha1(const std::string &msg)
|
||||
unsigned char sha_digest[20];
|
||||
char tmp[4];
|
||||
|
||||
SHA1((const unsigned char*)msg.c_str(), msg.length(), sha_digest);
|
||||
|
||||
for (int i = 0; i < 20; ++i) {
|
||||
sprintf(&tmp[0], "%02x", sha_digest[i]);
|
||||
ret.push_back(tmp[0]);
|
||||
ret.push_back(tmp[1]);
|
||||
if (EVP_Digest(msg.data(), msg.length(), sha_digest, nullptr, EVP_sha1(), nullptr) == 1) {
|
||||
for (int i = 0; i < 20; ++i) {
|
||||
sprintf(&tmp[0], "%02x", sha_digest[i]);
|
||||
ret.push_back(tmp[0]);
|
||||
ret.push_back(tmp[1]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -232,12 +318,12 @@ std::string eqcrypt_sha512(const std::string &msg)
|
||||
unsigned char sha_digest[64];
|
||||
char tmp[4];
|
||||
|
||||
SHA512((const unsigned char*)msg.c_str(), msg.length(), sha_digest);
|
||||
|
||||
for (int i = 0; i < 64; ++i) {
|
||||
sprintf(&tmp[0], "%02x", sha_digest[i]);
|
||||
ret.push_back(tmp[0]);
|
||||
ret.push_back(tmp[1]);
|
||||
if (EVP_Digest(msg.data(), msg.length(), sha_digest, nullptr, EVP_sha512(), nullptr) == 1) {
|
||||
for (int i = 0; i < 64; ++i) {
|
||||
sprintf(&tmp[0], "%02x", sha_digest[i]);
|
||||
ret.push_back(tmp[0]);
|
||||
ret.push_back(tmp[1]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -48,10 +48,20 @@ namespace CryptoHash {
|
||||
}
|
||||
|
||||
std::string GetEncryptionByModeId(uint32 mode);
|
||||
|
||||
// DES-CBC with an all-zero key and IV (EQ login protocol obfuscation, not security).
|
||||
// On encrypt, a trailing partial block is zero-padded to the next 8-byte boundary, so
|
||||
// buffer_out must be at least ((buffer_in_sz + 7) / 8) * 8 bytes. On decrypt, buffer_in_sz
|
||||
// must already be a multiple of 8 or the call returns nullptr.
|
||||
const char *eqcrypt_block(const char *buffer_in, size_t buffer_in_sz, char *buffer_out, bool enc);
|
||||
std::string eqcrypt_hash(const std::string &username, const std::string &password, int mode);
|
||||
bool eqcrypt_verify_hash(const std::string &username, const std::string &password, const std::string &pwhash, int mode);
|
||||
|
||||
// OpenSSL 3.0 moved DES behind the "legacy" provider; these load/unload it
|
||||
// for the lifetime of the process. No-op when built against mbedtls.
|
||||
bool eqcrypt_init();
|
||||
void eqcrypt_shutdown();
|
||||
|
||||
struct EncryptionResult {
|
||||
std::string password;
|
||||
int mode = 0;
|
||||
|
||||
@@ -67,21 +67,6 @@ struct PlayerLoginReply {
|
||||
char unknown[1]; // variable length, password unlikely? client doesn't send this on re-login from char select
|
||||
};
|
||||
|
||||
struct PlayerLoginReplySteamLatest
|
||||
{
|
||||
LoginBaseReplyMessage base_reply;
|
||||
int8_t unk1; // (default: 0)
|
||||
int8_t unk2; // (default: 0)
|
||||
int32_t lsid; // (default: -1)
|
||||
char key[11]; // client reads until null (variable length)
|
||||
int32_t failed_attempts;
|
||||
bool show_player_count; // admin flag, enables admin button and shows server player counts (default: false)
|
||||
int32_t unk3; // guess, needs more investigation (default: 0)
|
||||
int32_t unk4; // guess, needs more investigation (default: 0)
|
||||
char username[1]; // variable length, if not empty client attempts to re-login to server select when quitting from char select and sends this in a struct
|
||||
char unknown[1]; // variable length, password unlikely? client doesn't send this on re-login from char select
|
||||
};
|
||||
|
||||
// variable length, for reference
|
||||
struct LoginClientServerData {
|
||||
char ip[1];
|
||||
@@ -115,18 +100,12 @@ struct PlayEverquestResponse {
|
||||
uint32 server_number;
|
||||
};
|
||||
|
||||
//for reference
|
||||
struct SystemFingerprint {
|
||||
LoginBaseMessage base_header;
|
||||
char fingerprint[1];
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
||||
enum LSClientVersion {
|
||||
cv_titanium,
|
||||
cv_sod,
|
||||
cv_steam_latest
|
||||
cv_larion
|
||||
};
|
||||
|
||||
enum LSClientStatus {
|
||||
|
||||
+6
-6
@@ -3,12 +3,12 @@ OP_SessionReady=0x0001
|
||||
OP_Login=0x0002
|
||||
OP_ServerListRequest=0x0004
|
||||
OP_PlayEverquestRequest=0x000d
|
||||
OP_PlayEverquestResponse=0x0023
|
||||
OP_ChatMessage=0x0018
|
||||
OP_LoginAccepted=0x0019
|
||||
OP_ServerListResponse=0x001a
|
||||
OP_Poll=0x002a
|
||||
OP_PlayEverquestResponse=0x0022
|
||||
OP_ChatMessage=0x0017
|
||||
OP_LoginAccepted=0x0018
|
||||
OP_ServerListResponse=0x0019
|
||||
OP_Poll=0x0029
|
||||
OP_EnterChat=0x000f
|
||||
OP_PollResponse=0x0011
|
||||
OP_SystemFingerprint=0x0016
|
||||
OP_ExpansionList=0x0031
|
||||
OP_ExpansionList=0x0030
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "common/platform.h"
|
||||
#include "common/timer.h"
|
||||
#include "common/types.h"
|
||||
#include "loginserver/encryption.h"
|
||||
#include "loginserver/login_server.h"
|
||||
#include "loginserver/loginserver_command_handler.h"
|
||||
#include "loginserver/loginserver_webserver.h"
|
||||
@@ -158,12 +159,12 @@ void start_web_server()
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
RegisterExecutablePlatform(ExePlatformLogin);
|
||||
EQEmuLogSys::Instance()->LoadLogSettingsDefaults();
|
||||
set_exception_handler();
|
||||
|
||||
LogInfo("Logging System Init");
|
||||
|
||||
if (argc == 1) {
|
||||
EQEmuLogSys::Instance()->LoadLogSettingsDefaults();
|
||||
if (!eqcrypt_init()) {
|
||||
LogError("Failed to initialize crypto providers");
|
||||
return 1;
|
||||
}
|
||||
|
||||
PathManager::Instance()->Init();
|
||||
@@ -280,5 +281,7 @@ int main(int argc, char **argv)
|
||||
LogInfo("Server Manager Shutdown");
|
||||
delete server.server_manager;
|
||||
|
||||
eqcrypt_shutdown();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -706,17 +706,19 @@ bool WorldServer::ValidateWorldServerAdminLogin(
|
||||
|
||||
void WorldServer::SerializeForClientServerList(SerializeBuffer &out, bool use_local_ip, LSClientVersion version) const
|
||||
{
|
||||
if (version == cv_steam_latest) {
|
||||
if (use_local_ip) {
|
||||
out.WriteString(GetLocalIP());
|
||||
}
|
||||
else {
|
||||
out.WriteString(m_remote_ip_address);
|
||||
}
|
||||
// see LoginClientServerData_Struct
|
||||
if (use_local_ip) {
|
||||
out.WriteString(GetLocalIP());
|
||||
}
|
||||
else {
|
||||
out.WriteString(m_remote_ip_address);
|
||||
}
|
||||
|
||||
out.WriteInt32(9000); // port, not currently settable in eqemu but needed for compat
|
||||
if (version == cv_larion) {
|
||||
out.WriteUInt32(9000);
|
||||
}
|
||||
|
||||
switch (GetServerListID()) {
|
||||
switch (GetServerListID()) {
|
||||
case LS::ServerType::Legends:
|
||||
out.WriteInt32(LS::ServerTypeFlags::Legends);
|
||||
break;
|
||||
@@ -726,74 +728,35 @@ void WorldServer::SerializeForClientServerList(SerializeBuffer &out, bool use_lo
|
||||
default:
|
||||
out.WriteInt32(LS::ServerTypeFlags::Standard);
|
||||
break;
|
||||
}
|
||||
|
||||
out.WriteInt32(289); //unsure what this is yet
|
||||
out.WriteUInt32(m_server_id);
|
||||
|
||||
out.WriteString(m_server_long_name);
|
||||
out.WriteString("US"); // country code
|
||||
out.WriteString("EN"); // language code
|
||||
out.WriteString("Standard");
|
||||
out.WriteString("This server has no description set currently.");
|
||||
|
||||
if (GetStatus() < 0) {
|
||||
if (GetZonesBooted() == 0) {
|
||||
out.WriteInt32(LS::ServerStatusFlags::Down);
|
||||
}
|
||||
else {
|
||||
out.WriteInt32(LS::ServerStatusFlags::Locked);
|
||||
}
|
||||
}
|
||||
else {
|
||||
out.WriteInt32(LS::ServerStatusFlags::Up);
|
||||
}
|
||||
|
||||
out.WriteUInt32(GetPlayersOnline());
|
||||
out.WriteInt32(31); //expansions
|
||||
out.WriteInt32(0); //truebox
|
||||
}
|
||||
if (version == cv_larion) {
|
||||
auto server_id = m_server_id;
|
||||
//if this is 0, the client will not show the server in the list
|
||||
out.WriteUInt32(1);
|
||||
out.WriteUInt32(server_id);
|
||||
}
|
||||
else {
|
||||
// see LoginClientServerData_Struct
|
||||
if (use_local_ip) {
|
||||
out.WriteString(GetLocalIP());
|
||||
}
|
||||
else {
|
||||
out.WriteString(m_remote_ip_address);
|
||||
}
|
||||
|
||||
switch (GetServerListID()) {
|
||||
case LS::ServerType::Legends:
|
||||
out.WriteInt32(LS::ServerTypeFlags::Legends);
|
||||
break;
|
||||
case LS::ServerType::Preferred:
|
||||
out.WriteInt32(LS::ServerTypeFlags::Preferred);
|
||||
break;
|
||||
default:
|
||||
out.WriteInt32(LS::ServerTypeFlags::Standard);
|
||||
break;
|
||||
}
|
||||
|
||||
out.WriteUInt32(m_server_id);
|
||||
out.WriteString(m_server_long_name);
|
||||
out.WriteString("us"); // country code
|
||||
out.WriteString("en"); // language code
|
||||
|
||||
// 0 = Up, 1 = Down, 2 = Up, 3 = down, 4 = locked, 5 = locked(down)
|
||||
if (GetStatus() < 0) {
|
||||
if (GetZonesBooted() == 0) {
|
||||
out.WriteInt32(LS::ServerStatusFlags::Down);
|
||||
}
|
||||
else {
|
||||
out.WriteInt32(LS::ServerStatusFlags::Locked);
|
||||
}
|
||||
}
|
||||
else {
|
||||
out.WriteInt32(LS::ServerStatusFlags::Up);
|
||||
}
|
||||
|
||||
out.WriteUInt32(GetPlayersOnline());
|
||||
out.WriteUInt32(m_server_id);
|
||||
}
|
||||
|
||||
out.WriteString(m_server_long_name);
|
||||
out.WriteString("us"); // country code
|
||||
out.WriteString("en"); // language code
|
||||
|
||||
// 0 = Up, 1 = Down, 2 = Up, 3 = down, 4 = locked, 5 = locked(down)
|
||||
if (GetStatus() < 0) {
|
||||
if (GetZonesBooted() == 0) {
|
||||
out.WriteInt32(LS::ServerStatusFlags::Down);
|
||||
}
|
||||
else {
|
||||
out.WriteInt32(LS::ServerStatusFlags::Locked);
|
||||
}
|
||||
}
|
||||
else {
|
||||
out.WriteInt32(LS::ServerStatusFlags::Up);
|
||||
}
|
||||
|
||||
out.WriteUInt32(GetPlayersOnline());
|
||||
}
|
||||
|
||||
void WorldServer::FormatWorldServerName(char *name, int8 server_list_type)
|
||||
|
||||
@@ -153,7 +153,7 @@ std::unique_ptr<EQApplicationPacket> WorldServerManager::CreateServerListPacket(
|
||||
s->SerializeForClientServerList(buf, use_local_ip, client->GetClientVersion());
|
||||
}
|
||||
|
||||
return std::make_unique<EQApplicationPacket>(OP_ServerListResponse, buf);
|
||||
return std::make_unique<EQApplicationPacket>(OP_ServerListResponse, std::move(buf));
|
||||
}
|
||||
|
||||
void WorldServerManager::SendUserLoginToWorldRequest(
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
This is a bunch of ImHex patterns for viewing various Outer Brood packets
|
||||
@@ -1,23 +0,0 @@
|
||||
struct BaseResponse
|
||||
{
|
||||
u8 success;
|
||||
u32 error_str_id;
|
||||
char error_str[];
|
||||
};
|
||||
|
||||
struct Packet {
|
||||
BaseResponse base;
|
||||
s8 unk1; //I think this is just padding
|
||||
s8 unk2; //I think this is just padding
|
||||
u32 lsid;
|
||||
char key[];
|
||||
s32 failed_attempts;
|
||||
u8 show_player_count;
|
||||
s32 unk3; // 0
|
||||
s32 unk4; // 0
|
||||
char username[];
|
||||
char password[]; //I'm not sure this is correct, it feels like this might be some internal refresh token
|
||||
char paddingEnd[2];
|
||||
};
|
||||
|
||||
Packet p @ 0x00;
|
||||
@@ -1,19 +0,0 @@
|
||||
// 0x01
|
||||
|
||||
struct LoginBase
|
||||
{
|
||||
u32 sequence_id;
|
||||
u8 compressed;
|
||||
u8 encrypt_type;
|
||||
u32 unknown08;
|
||||
};
|
||||
|
||||
struct Packet {
|
||||
LoginBase base;
|
||||
u8 success;
|
||||
s32 error_str_id;
|
||||
char error_msg[];
|
||||
char other_msg[];
|
||||
};
|
||||
|
||||
Packet packet @0x00;
|
||||
@@ -1,22 +0,0 @@
|
||||
// 0x31
|
||||
|
||||
struct Expansion
|
||||
{
|
||||
u32 index;
|
||||
u8 owned;
|
||||
s32 expansion_name_string_id;
|
||||
s32 order_string_id;
|
||||
s32 unknown_string_id;
|
||||
u32 unknown17;
|
||||
|
||||
};
|
||||
|
||||
struct Packet {
|
||||
u32 unknown00;
|
||||
u32 unknown04;
|
||||
u16 unknown08;
|
||||
u32 expansion_count;
|
||||
Expansion expansions[expansion_count];
|
||||
};
|
||||
|
||||
Packet packet @0x00;
|
||||
@@ -1,18 +0,0 @@
|
||||
// 0x02
|
||||
|
||||
#include <std/mem.pat>
|
||||
|
||||
struct LoginBase
|
||||
{
|
||||
u32 sequence_id;
|
||||
u8 compressed;
|
||||
u8 encrypt_type;
|
||||
u32 unknown08;
|
||||
};
|
||||
|
||||
struct Packet {
|
||||
LoginBase base;
|
||||
u8 payload[std::mem::size() - $];
|
||||
};
|
||||
|
||||
Packet packet @0x00;
|
||||
@@ -1,18 +0,0 @@
|
||||
// 0x19
|
||||
|
||||
#include <std/mem.pat>
|
||||
|
||||
struct LoginBase
|
||||
{
|
||||
u32 sequence_id;
|
||||
u8 compressed;
|
||||
u8 encrypt_type;
|
||||
u32 unknown08;
|
||||
};
|
||||
|
||||
struct Packet {
|
||||
LoginBase base;
|
||||
u8 payload[std::mem::size() - $];
|
||||
};
|
||||
|
||||
Packet packet @0x00;
|
||||
@@ -1,20 +0,0 @@
|
||||
// 0xd
|
||||
|
||||
struct LoginBase
|
||||
{
|
||||
u32 sequence_id;
|
||||
u8 compressed;
|
||||
u8 encrypt_type;
|
||||
u32 unknown08;
|
||||
};
|
||||
|
||||
struct Packet {
|
||||
LoginBase base;
|
||||
u32 server_id;
|
||||
char fingerprint[];
|
||||
u32 unknown1;
|
||||
u8 unknown2;
|
||||
u32 unknown3;
|
||||
};
|
||||
|
||||
Packet packet @0x00;
|
||||
@@ -1,19 +0,0 @@
|
||||
// 0x23
|
||||
|
||||
struct LoginBase
|
||||
{
|
||||
u32 sequence_id;
|
||||
u8 compressed;
|
||||
u8 encrypt_type;
|
||||
u32 unknown08;
|
||||
};
|
||||
|
||||
struct Packet {
|
||||
LoginBase base;
|
||||
u8 success;
|
||||
u32 login_server_string_id;
|
||||
char login_server_string;
|
||||
|
||||
};
|
||||
|
||||
Packet packet @0x00;
|
||||
@@ -1,15 +0,0 @@
|
||||
// 0x04
|
||||
|
||||
struct LoginBase
|
||||
{
|
||||
u32 sequence_id;
|
||||
u8 compressed;
|
||||
u8 encrypt_type;
|
||||
u32 unknown08;
|
||||
};
|
||||
|
||||
struct Packet {
|
||||
LoginBase base;
|
||||
};
|
||||
|
||||
Packet packet @0x00;
|
||||
@@ -1,44 +0,0 @@
|
||||
// 0x1a
|
||||
// work in progress
|
||||
|
||||
struct LoginBase
|
||||
{
|
||||
u32 sequence_id;
|
||||
u8 compressed;
|
||||
u8 encrypt_type;
|
||||
u32 unknown08;
|
||||
};
|
||||
|
||||
struct Realm
|
||||
{
|
||||
char address[];
|
||||
u32 port;
|
||||
u32 server_category;
|
||||
//not sure yet, seen 289 on a lot of classic servers
|
||||
//41 fangbreaker, teek, oakwynd, tormax
|
||||
//31 yelniak
|
||||
//33 vaniki, mischief
|
||||
u32 status_code;
|
||||
u32 server_id;
|
||||
char name[];
|
||||
char language[];
|
||||
char region[];
|
||||
char server_type_desc[];
|
||||
char server_desc[];
|
||||
u32 server_flags;
|
||||
u32 players_online;
|
||||
u32 expansion; //I think
|
||||
u32 truebox_max_clients;
|
||||
};
|
||||
|
||||
struct Packet {
|
||||
LoginBase base;
|
||||
|
||||
u8 success;
|
||||
u32 login_server_string_id;
|
||||
char login_server_string[];
|
||||
u32 realm_count;
|
||||
Realm realms[realm_count];
|
||||
};
|
||||
|
||||
Packet packet @0x00;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user