mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-31 13:16:39 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 808a86525f |
@@ -1,26 +0,0 @@
|
|||||||
# automatic eol conversions
|
|
||||||
* text=auto
|
|
||||||
|
|
||||||
*.c text
|
|
||||||
*.cc text
|
|
||||||
*.cpp text
|
|
||||||
*.h text
|
|
||||||
*.hpp text
|
|
||||||
*.txt text
|
|
||||||
*.pl text
|
|
||||||
*.sql text
|
|
||||||
*.xml text
|
|
||||||
*.yaml text
|
|
||||||
*.conf text
|
|
||||||
*.resx text
|
|
||||||
*.cs text
|
|
||||||
*.ini text
|
|
||||||
*.settings text
|
|
||||||
*.html text
|
|
||||||
*.css text
|
|
||||||
*.js text
|
|
||||||
*.types text
|
|
||||||
|
|
||||||
*.vcproj text merge=union
|
|
||||||
*.csproj text merge=union
|
|
||||||
*.sln text merge=union eol=crlf
|
|
||||||
-37
@@ -1,37 +0,0 @@
|
|||||||
# Object files
|
|
||||||
*.o
|
|
||||||
*.obj
|
|
||||||
|
|
||||||
# Libraries
|
|
||||||
*.lib
|
|
||||||
*.a
|
|
||||||
|
|
||||||
# Shared objects (inc. Windows DLLs)
|
|
||||||
*.dll
|
|
||||||
*.so
|
|
||||||
*.so.*
|
|
||||||
*.dylib
|
|
||||||
|
|
||||||
# Executables
|
|
||||||
*.exe
|
|
||||||
*.out
|
|
||||||
*.app
|
|
||||||
|
|
||||||
# CMake
|
|
||||||
CMakeCache.txt
|
|
||||||
CMakeFiles
|
|
||||||
Makefile
|
|
||||||
cmake_install.cmake
|
|
||||||
install_manifest.txt
|
|
||||||
Build/
|
|
||||||
build/
|
|
||||||
Build32/
|
|
||||||
build32/
|
|
||||||
Build64/
|
|
||||||
build64/
|
|
||||||
Build_32/
|
|
||||||
build_32/
|
|
||||||
Build_64/
|
|
||||||
build_64/
|
|
||||||
log/
|
|
||||||
logs/
|
|
||||||
-332
@@ -1,332 +0,0 @@
|
|||||||
#EQEmu Cmake
|
|
||||||
|
|
||||||
#We set a fairly new version (as of 2013) because I found finding perl was a bit... buggy on older ones
|
|
||||||
#Can change this if you really want but you should upgrade!
|
|
||||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
|
|
||||||
|
|
||||||
#FindMySQL is located here so lets make it so CMake can find it
|
|
||||||
SET(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/" ${CMAKE_MODULE_PATH})
|
|
||||||
|
|
||||||
#For checking includes
|
|
||||||
INCLUDE (CheckIncludeFiles)
|
|
||||||
|
|
||||||
#Our project name is EQEmu
|
|
||||||
PROJECT(EQEmu)
|
|
||||||
|
|
||||||
#Default build type is set to RelWithDebInfo for generators that honor that like makefiles
|
|
||||||
IF(NOT CMAKE_BUILD_TYPE)
|
|
||||||
SET(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build." FORCE)
|
|
||||||
ENDIF(NOT CMAKE_BUILD_TYPE)
|
|
||||||
|
|
||||||
#Add our various windows definitions
|
|
||||||
IF(MSVC OR MINGW)
|
|
||||||
ADD_DEFINITIONS(-D_WINDOWS)
|
|
||||||
IF(CMAKE_CL_64)
|
|
||||||
ADD_DEFINITIONS(-DWIN64)
|
|
||||||
ELSE(CMAKE_CL_64)
|
|
||||||
ADD_DEFINITIONS(-DWIN32)
|
|
||||||
ENDIF(CMAKE_CL_64)
|
|
||||||
ENDIF(MSVC OR MINGW)
|
|
||||||
|
|
||||||
IF(MSVC)
|
|
||||||
#Set our default locations for zlib/mysql based on x86/x64
|
|
||||||
IF(CMAKE_CL_64)
|
|
||||||
SET(ZLIB_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/zlib_x64")
|
|
||||||
SET(MYSQL_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/mysql_x64")
|
|
||||||
SET(LUA_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/luaj_x64")
|
|
||||||
ELSE(CMAKE_CL_64)
|
|
||||||
SET(ZLIB_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/zlib_x86")
|
|
||||||
SET(MYSQL_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/mysql_x86")
|
|
||||||
SET(LUA_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/luaj_x86")
|
|
||||||
ENDIF(CMAKE_CL_64)
|
|
||||||
|
|
||||||
#disable CRT warnings on windows cause they're annoying as shit and we use C functions everywhere
|
|
||||||
OPTION(EQEMU_DISABLE_CRT_SECURE_WARNINGS "Disable Secure CRT Warnings" ON)
|
|
||||||
IF(EQEMU_DISABLE_CRT_SECURE_WARNINGS)
|
|
||||||
ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS)
|
|
||||||
ENDIF(EQEMU_DISABLE_CRT_SECURE_WARNINGS)
|
|
||||||
|
|
||||||
#fast FP if you'd like it
|
|
||||||
OPTION(EQEMU_FAST_FLOATINGPOINT "Use MSVC /fp:fast option" ON)
|
|
||||||
IF(EQEMU_FAST_FLOATINGPOINT)
|
|
||||||
ADD_DEFINITIONS(/fp:fast)
|
|
||||||
ENDIF(EQEMU_FAST_FLOATINGPOINT)
|
|
||||||
|
|
||||||
#crash logging currently only works on windows x86/x64
|
|
||||||
OPTION(EQEMU_ENABLE_CRASH_LOGGING "Enable crash logging" ON)
|
|
||||||
IF(EQEMU_ENABLE_CRASH_LOGGING)
|
|
||||||
ADD_DEFINITIONS(-DCRASH_LOGGING)
|
|
||||||
ENDIF(EQEMU_ENABLE_CRASH_LOGGING)
|
|
||||||
|
|
||||||
#Disable safe SEH or not?
|
|
||||||
OPTION(EQEMU_DISABLE_SAFESEH "Disable Safe SEH (Needed for Strawberry Perl)" OFF)
|
|
||||||
IF(EQEMU_DISABLE_SAFESEH)
|
|
||||||
SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} /SAFESEH:NO")
|
|
||||||
SET(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "${CMAKE_EXE_LINKER_FLAGS_MINSIZEREL} /SAFESEH:NO")
|
|
||||||
SET(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /SAFESEH:NO")
|
|
||||||
SET(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} /SAFESEH:NO")
|
|
||||||
SET(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} /SAFESEH:NO")
|
|
||||||
SET(CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL "${CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL} /SAFESEH:NO")
|
|
||||||
SET(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /SAFESEH:NO")
|
|
||||||
SET(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO} /SAFESEH:NO")
|
|
||||||
SET(CMAKE_MODULE_LINKER_FLAGS_DEBUG "${CMAKE_MODULE_LINKER_FLAGS_DEBUG} /SAFESEH:NO")
|
|
||||||
SET(CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL "${CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL} /SAFESEH:NO")
|
|
||||||
SET(CMAKE_MODULE_LINKER_FLAGS_RELEASE "${CMAKE_MODULE_LINKER_FLAGS_RELEASE} /SAFESEH:NO")
|
|
||||||
SET(CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO} /SAFESEH:NO")
|
|
||||||
ENDIF(EQEMU_DISABLE_SAFESEH)
|
|
||||||
|
|
||||||
OPTION(EQEMU_BUILD_MSVC_MP "Enable build with multiple processes." TRUE)
|
|
||||||
IF(EQEMU_BUILD_MSVC_MP)
|
|
||||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
|
|
||||||
ENDIF(EQEMU_BUILD_MSVC_MP)
|
|
||||||
|
|
||||||
#We want to compile /MT not /MD so we change that
|
|
||||||
FOREACH(flag_var CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_RELWITHDEBINFO CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELEASE CMAKE_C_FLAGS_RELWITHDEBINFO)
|
|
||||||
IF(${flag_var} MATCHES "/MD")
|
|
||||||
STRING(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
|
|
||||||
ENDIF(${flag_var} MATCHES "/MD")
|
|
||||||
ENDFOREACH(flag_var)
|
|
||||||
|
|
||||||
ADD_DEFINITIONS(-DNOMINMAX)
|
|
||||||
ELSE(MSVC)
|
|
||||||
#Normally set by perl but we don't use the perl flags anymore so we set it.
|
|
||||||
ADD_DEFINITIONS(-DHAS_UNION_SEMUN)
|
|
||||||
ENDIF(MSVC)
|
|
||||||
|
|
||||||
#FreeBSD support
|
|
||||||
IF(UNIX)
|
|
||||||
IF(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
|
|
||||||
ADD_DEFINITIONS(-DFREEBSD)
|
|
||||||
SET(FREEBSD TRUE)
|
|
||||||
ENDIF(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
|
|
||||||
IF(CMAKE_SYSTEM_NAME MATCHES "Darwin")
|
|
||||||
ADD_DEFINITIONS(-DDARWIN)
|
|
||||||
SET(DARWIN TRUE)
|
|
||||||
ENDIF(CMAKE_SYSTEM_NAME MATCHES "Darwin")
|
|
||||||
ENDIF(UNIX)
|
|
||||||
|
|
||||||
#use stdint.h types if they exist for this platform (we have to guess otherwise)
|
|
||||||
CHECK_INCLUDE_FILES(stdint.h HAVE_STDINT_H)
|
|
||||||
IF(HAVE_STDINT_H)
|
|
||||||
ADD_DEFINITIONS(-DEQEMU_USE_STDINT)
|
|
||||||
ENDIF(HAVE_STDINT_H)
|
|
||||||
|
|
||||||
#debug level, 5 is default. Most people wont ever change this but it's there if you want to
|
|
||||||
SET(EQEMU_DEBUG_LEVEL 5 CACHE STRING "EQEmu debug level:
|
|
||||||
0 - Quiet mode Errors to file Status and Normal ignored
|
|
||||||
1 - Status and Normal to console, Errors to logfile
|
|
||||||
2 - Status, Normal, and Error to console and logfile
|
|
||||||
3 - Light debug release errors and status
|
|
||||||
4 - Moderate debug release errors and status
|
|
||||||
5 - Maximum debug release errors and status
|
|
||||||
10 - More errors than you ever wanted to see"
|
|
||||||
)
|
|
||||||
|
|
||||||
SET(EQEMU_LOG_LEVEL_STATUS 2 CACHE STRING "EQEmu logging level for [Status]:
|
|
||||||
0 - Disabled
|
|
||||||
1 - Ouput to File Enabled
|
|
||||||
2 - Output to stdout Enabled
|
|
||||||
3 - Output to File and stdout Enabled
|
|
||||||
8 - Output to stderr Enabled
|
|
||||||
9 - Output to File and stderr Enabled
|
|
||||||
11 - Output to File, stdout and stderr Enabled"
|
|
||||||
)
|
|
||||||
|
|
||||||
SET(EQEMU_LOG_LEVEL_NORMAL 3 CACHE STRING "EQEmu logging level for [Normal]:
|
|
||||||
0 - Disabled
|
|
||||||
1 - Ouput to File Enabled
|
|
||||||
2 - Output to stdout Enabled
|
|
||||||
3 - Output to File and stdout Enabled
|
|
||||||
8 - Output to stderr Enabled
|
|
||||||
9 - Output to File and stderr Enabled
|
|
||||||
11 - Output to File, stdout and stderr Enabled"
|
|
||||||
)
|
|
||||||
|
|
||||||
SET(EQEMU_LOG_LEVEL_ERROR 2 CACHE STRING "EQEmu logging level for [Error]:
|
|
||||||
0 - Disabled
|
|
||||||
1 - Ouput to File Enabled
|
|
||||||
2 - Output to stdout Enabled
|
|
||||||
3 - Output to File and stdout Enabled
|
|
||||||
8 - Output to stderr Enabled
|
|
||||||
9 - Output to File and stderr Enabled
|
|
||||||
11 - Output to File, stdout and stderr Enabled"
|
|
||||||
)
|
|
||||||
|
|
||||||
SET(EQEMU_LOG_LEVEL_DEBUG 3 CACHE STRING "EQEmu logging level for [Debug]:
|
|
||||||
0 - Disabled
|
|
||||||
1 - Ouput to File Enabled
|
|
||||||
2 - Output to stdout Enabled
|
|
||||||
3 - Output to File and stdout Enabled
|
|
||||||
8 - Output to stderr Enabled
|
|
||||||
9 - Output to File and stderr Enabled
|
|
||||||
11 - Output to File, stdout and stderr Enabled"
|
|
||||||
)
|
|
||||||
|
|
||||||
SET(EQEMU_LOG_LEVEL_QUEST 2 CACHE STRING "EQEmu logging level for [Quest]:
|
|
||||||
0 - Disabled
|
|
||||||
1 - Ouput to File Enabled
|
|
||||||
2 - Output to stdout Enabled
|
|
||||||
3 - Output to File and stdout Enabled
|
|
||||||
8 - Output to stderr Enabled
|
|
||||||
9 - Output to File and stderr Enabled
|
|
||||||
11 - Output to File, stdout and stderr Enabled"
|
|
||||||
)
|
|
||||||
|
|
||||||
SET(EQEMU_LOG_LEVEL_COMMANDS 1 CACHE STRING "EQEmu logging level for [Commands]:
|
|
||||||
0 - Disabled
|
|
||||||
1 - Ouput to File Enabled
|
|
||||||
2 - Output to stdout Enabled
|
|
||||||
3 - Output to File and stdout Enabled
|
|
||||||
8 - Output to stderr Enabled
|
|
||||||
9 - Output to File and stderr Enabled
|
|
||||||
11 - Output to File, stdout and stderr Enabled"
|
|
||||||
)
|
|
||||||
|
|
||||||
SET(EQEMU_LOG_LEVEL_CRASH 3 CACHE STRING "EQEmu logging level for [Crash]:
|
|
||||||
0 - Disabled
|
|
||||||
1 - Ouput to File Enabled
|
|
||||||
2 - Output to stdout Enabled
|
|
||||||
3 - Output to File and stdout Enabled
|
|
||||||
8 - Output to stderr Enabled
|
|
||||||
9 - Output to File and stderr Enabled
|
|
||||||
11 - Output to File, stdout and stderr Enabled"
|
|
||||||
)
|
|
||||||
|
|
||||||
MARK_AS_ADVANCED(EQEMU_LOG_LEVEL_STATUS EQEMU_LOG_LEVEL_NORMAL EQEMU_LOG_LEVEL_ERROR EQEMU_LOG_LEVEL_DEBUG EQEMU_LOG_LEVEL_QUEST EQEMU_LOG_LEVEL_COMMANDS EQEMU_LOG_LEVEL_CRASH)
|
|
||||||
|
|
||||||
SET(EQEMU_STREAM_SEND_RATE 1048576 CACHE STRING "Advanced: Base amount of data stream can send before throttle.")
|
|
||||||
SET(EQEMU_STREAM_DECAY_RATE 78642 CACHE STRING "Advanced: Base amount of data stream recovers per tic.")
|
|
||||||
SET(EQEMU_STREAM_RETRANSMIT_TIMEOUT_MUL 3.0 CACHE STRING "Advanced: Multiplier on retransmit timeout.")
|
|
||||||
SET(EQEMU_STREAM_RETRANSMIT_TIMEOUT_MAX 5000 CACHE STRING "Advanced: Max in ms for retransmit timeout timer.")
|
|
||||||
SET(EQEMU_STREAM_AVERAGE_DELTA_MAX 2500 CACHE STRING "Advanced: The maximum average delta in ms allowed.")
|
|
||||||
SET(EQEMU_STREAM_RETRANSMIT_ACKED_PACKETS TRUE CACHE BOOL "Advanced: Whether or not acked packets can be retransmitted")
|
|
||||||
MARK_AS_ADVANCED(EQEMU_STREAM_SEND_RATE EQEMU_STREAM_DECAY_RATE EQEMU_STREAM_RETRANSMIT_TIMEOUT_MUL EQEMU_STREAM_RETRANSMIT_TIMEOUT_MAX EQEMU_STREAM_AVERAGE_DELTA_MAX EQEMU_STREAM_RETRANSMIT_ACKED_PACKETS)
|
|
||||||
|
|
||||||
#NPC Types Cache Behavior
|
|
||||||
OPTION(EQEMU_DEPOP_INVALIDATES_CACHE "#repop invalidates the npc_types cache (will cause a larger database hit on #repop but is more convienent)." ON)
|
|
||||||
|
|
||||||
#Bots are a compile time option so on/off
|
|
||||||
OPTION(EQEMU_ENABLE_BOTS "Enable Bots" OFF)
|
|
||||||
|
|
||||||
#Disable entire _mlog system (excludes trade/command logs)
|
|
||||||
OPTION(EQEMU_DISABLE_LOGSYS "Disable Logging INI System" ON)
|
|
||||||
|
|
||||||
#Enable GM Command log system
|
|
||||||
OPTION(EQEMU_COMMANDS_LOGGING "Enable GM Command logs" ON)
|
|
||||||
|
|
||||||
IF(EQEMU_COMMANDS_LOGGING)
|
|
||||||
ADD_DEFINITIONS(-DCOMMANDS_LOGGING)
|
|
||||||
ENDIF(EQEMU_COMMANDS_LOGGING)
|
|
||||||
|
|
||||||
IF(EQEMU_DISABLE_LOGSYS)
|
|
||||||
ADD_DEFINITIONS(-DDISABLE_LOGSYS)
|
|
||||||
ENDIF(EQEMU_DISABLE_LOGSYS)
|
|
||||||
|
|
||||||
IF(EQEMU_ENABLE_BOTS)
|
|
||||||
ADD_DEFINITIONS(-DBOTS)
|
|
||||||
ENDIF(EQEMU_ENABLE_BOTS)
|
|
||||||
|
|
||||||
#What to build
|
|
||||||
OPTION(EQEMU_BUILD_SERVER "Build the game server." ON)
|
|
||||||
OPTION(EQEMU_BUILD_LOGIN "Build the login server." OFF)
|
|
||||||
OPTION(EQEMU_BUILD_AZONE "Build azone utility." OFF)
|
|
||||||
OPTION(EQEMU_BUILD_TESTS "Build utility tests." OFF)
|
|
||||||
OPTION(EQEMU_BUILD_PERL "Build Perl parser." ON)
|
|
||||||
OPTION(EQEMU_BUILD_LUA "Build Lua parser." OFF)
|
|
||||||
OPTION(EQEMU_BUILD_CLIENT_FILES "Build Client Inport/Export Data Programs." ON)
|
|
||||||
|
|
||||||
#C++11 stuff
|
|
||||||
IF(NOT MSVC)
|
|
||||||
ADD_DEFINITIONS(-std=c++0x)
|
|
||||||
ENDIF(NOT MSVC)
|
|
||||||
|
|
||||||
#Various definitions
|
|
||||||
IF(EQEMU_BUILD_PERL)
|
|
||||||
ADD_DEFINITIONS(-DEMBPERL)
|
|
||||||
ADD_DEFINITIONS(-DEMBPERL_PLUGIN)
|
|
||||||
ENDIF(EQEMU_BUILD_PERL)
|
|
||||||
IF(EQEMU_BUILD_LUA)
|
|
||||||
ADD_DEFINITIONS(-DLUA_EQEMU)
|
|
||||||
ENDIF(EQEMU_BUILD_LUA)
|
|
||||||
|
|
||||||
SET(EQEMU_MAP_DIR "./Maps" CACHE STRING "The dir that maps, water maps, and paths are located in.")
|
|
||||||
|
|
||||||
ADD_DEFINITIONS(-DEQDEBUG=${EQEMU_DEBUG_LEVEL})
|
|
||||||
ADD_DEFINITIONS(-DINVERSEXY)
|
|
||||||
ADD_DEFINITIONS(-DFIELD_ITEMS)
|
|
||||||
ADD_DEFINITIONS(-DMAP_DIR="${EQEMU_MAP_DIR}")
|
|
||||||
ADD_DEFINITIONS(-DRATEBASE=${EQEMU_STREAM_SEND_RATE})
|
|
||||||
ADD_DEFINITIONS(-DDECAYBASE=${EQEMU_STREAM_DECAY_RATE})
|
|
||||||
ADD_DEFINITIONS(-DRETRANSMIT_TIMEOUT_MULT=${EQEMU_STREAM_RETRANSMIT_TIMEOUT_MUL})
|
|
||||||
ADD_DEFINITIONS(-DRETRANSMIT_TIMEOUT_MAX=${EQEMU_STREAM_RETRANSMIT_TIMEOUT_MAX})
|
|
||||||
ADD_DEFINITIONS(-DAVERAGE_DELTA_MAX=${EQEMU_STREAM_AVERAGE_DELTA_MAX})
|
|
||||||
ADD_DEFINITIONS(-DLOG_LEVEL_STATUS=${EQEMU_LOG_LEVEL_STATUS})
|
|
||||||
ADD_DEFINITIONS(-DLOG_LEVEL_NORMAL=${EQEMU_LOG_LEVEL_NORMAL})
|
|
||||||
ADD_DEFINITIONS(-DLOG_LEVEL_ERROR=${EQEMU_LOG_LEVEL_ERROR})
|
|
||||||
ADD_DEFINITIONS(-DLOG_LEVEL_DEBUG=${EQEMU_LOG_LEVEL_DEBUG})
|
|
||||||
ADD_DEFINITIONS(-DLOG_LEVEL_QUEST=${EQEMU_LOG_LEVEL_QUEST})
|
|
||||||
ADD_DEFINITIONS(-DLOG_LEVEL_COMMANDS=${EQEMU_LOG_LEVEL_COMMANDS})
|
|
||||||
ADD_DEFINITIONS(-DLOG_LEVEL_CRASH=${EQEMU_LOG_LEVEL_CRASH})
|
|
||||||
|
|
||||||
IF(EQEMU_STREAM_RETRANSMIT_ACKED_PACKETS)
|
|
||||||
ADD_DEFINITIONS(-DRETRANSMIT_ACKED_PACKETS=true)
|
|
||||||
ELSE(EQEMU_STREAM_RETRANSMIT_ACKED_PACKETS)
|
|
||||||
ADD_DEFINITIONS(-DRETRANSMIT_ACKED_PACKETS=false)
|
|
||||||
ENDIF(EQEMU_STREAM_RETRANSMIT_ACKED_PACKETS)
|
|
||||||
|
|
||||||
#Find everything we need
|
|
||||||
FIND_PACKAGE(ZLIB REQUIRED)
|
|
||||||
FIND_PACKAGE(MySQL REQUIRED)
|
|
||||||
IF(EQEMU_BUILD_PERL)
|
|
||||||
FIND_PACKAGE(PerlLibs REQUIRED)
|
|
||||||
INCLUDE_DIRECTORIES("${PERL_INCLUDE_PATH}")
|
|
||||||
ENDIF(EQEMU_BUILD_PERL)
|
|
||||||
|
|
||||||
IF(EQEMU_BUILD_LUA)
|
|
||||||
FIND_PACKAGE(EQLua51 REQUIRED)
|
|
||||||
SET(Boost_USE_STATIC_LIBS OFF)
|
|
||||||
SET(Boost_USE_MULTITHREADED ON)
|
|
||||||
SET(Boost_USE_STATIC_RUNTIME OFF)
|
|
||||||
SET(BOOST_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/boost")
|
|
||||||
|
|
||||||
FIND_PACKAGE(Boost REQUIRED)
|
|
||||||
INCLUDE_DIRECTORIES("${LUA_INCLUDE_DIR}" "${Boost_INCLUDE_DIRS}" "luabind")
|
|
||||||
|
|
||||||
OPTION(EQEMU_SANITIZE_LUA_LIBS "Sanitize Lua Libraries (Remove OS and IO standard libraries from being able to run)." ON)
|
|
||||||
IF(EQEMU_SANITIZE_LUA_LIBS)
|
|
||||||
ADD_DEFINITIONS(-DSANITIZE_LUA_LIBS)
|
|
||||||
ENDIF(EQEMU_SANITIZE_LUA_LIBS)
|
|
||||||
ENDIF(EQEMU_BUILD_LUA)
|
|
||||||
|
|
||||||
INCLUDE_DIRECTORIES("${ZLIB_INCLUDE_DIRS}" "${MySQL_INCLUDE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/common/glm/glm")
|
|
||||||
|
|
||||||
IF(EQEMU_BUILD_LUA)
|
|
||||||
ADD_SUBDIRECTORY(luabind)
|
|
||||||
ENDIF(EQEMU_BUILD_LUA)
|
|
||||||
|
|
||||||
IF(EQEMU_BUILD_SERVER OR EQEMU_BUILD_LOGIN OR EQEMU_BUILD_TESTS)
|
|
||||||
ADD_SUBDIRECTORY(common)
|
|
||||||
ENDIF(EQEMU_BUILD_SERVER OR EQEMU_BUILD_LOGIN OR EQEMU_BUILD_TESTS)
|
|
||||||
IF(EQEMU_BUILD_SERVER)
|
|
||||||
ADD_SUBDIRECTORY(shared_memory)
|
|
||||||
ADD_SUBDIRECTORY(world)
|
|
||||||
ADD_SUBDIRECTORY(zone)
|
|
||||||
ADD_SUBDIRECTORY(ucs)
|
|
||||||
ADD_SUBDIRECTORY(queryserv)
|
|
||||||
ADD_SUBDIRECTORY(eqlaunch)
|
|
||||||
ENDIF(EQEMU_BUILD_SERVER)
|
|
||||||
IF(EQEMU_BUILD_LOGIN)
|
|
||||||
ADD_SUBDIRECTORY(loginserver)
|
|
||||||
ENDIF(EQEMU_BUILD_LOGIN)
|
|
||||||
|
|
||||||
IF(EQEMU_BUILD_AZONE)
|
|
||||||
ADD_SUBDIRECTORY(utils)
|
|
||||||
ENDIF(EQEMU_BUILD_AZONE)
|
|
||||||
|
|
||||||
IF(EQEMU_BUILD_TESTS)
|
|
||||||
ADD_SUBDIRECTORY(tests)
|
|
||||||
ENDIF(EQEMU_BUILD_TESTS)
|
|
||||||
|
|
||||||
IF(EQEMU_BUILD_CLIENT_FILES)
|
|
||||||
ADD_SUBDIRECTORY(client_files)
|
|
||||||
ENDIF(EQEMU_BUILD_CLIENT_FILES)
|
|
||||||
@@ -1,339 +0,0 @@
|
|||||||
GNU GENERAL PUBLIC LICENSE
|
|
||||||
Version 2, June 1991
|
|
||||||
|
|
||||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
|
||||||
of this license document, but changing it is not allowed.
|
|
||||||
|
|
||||||
Preamble
|
|
||||||
|
|
||||||
The licenses for most software are designed to take away your
|
|
||||||
freedom to share and change it. By contrast, the GNU General Public
|
|
||||||
License is intended to guarantee your freedom to share and change free
|
|
||||||
software--to make sure the software is free for all its users. This
|
|
||||||
General Public License applies to most of the Free Software
|
|
||||||
Foundation's software and to any other program whose authors commit to
|
|
||||||
using it. (Some other Free Software Foundation software is covered by
|
|
||||||
the GNU Lesser General Public License instead.) You can apply it to
|
|
||||||
your programs, too.
|
|
||||||
|
|
||||||
When we speak of free software, we are referring to freedom, not
|
|
||||||
price. Our General Public Licenses are designed to make sure that you
|
|
||||||
have the freedom to distribute copies of free software (and charge for
|
|
||||||
this service if you wish), that you receive source code or can get it
|
|
||||||
if you want it, that you can change the software or use pieces of it
|
|
||||||
in new free programs; and that you know you can do these things.
|
|
||||||
|
|
||||||
To protect your rights, we need to make restrictions that forbid
|
|
||||||
anyone to deny you these rights or to ask you to surrender the rights.
|
|
||||||
These restrictions translate to certain responsibilities for you if you
|
|
||||||
distribute copies of the software, or if you modify it.
|
|
||||||
|
|
||||||
For example, if you distribute copies of such a program, whether
|
|
||||||
gratis or for a fee, you must give the recipients all the rights that
|
|
||||||
you have. You must make sure that they, too, receive or can get the
|
|
||||||
source code. And you must show them these terms so they know their
|
|
||||||
rights.
|
|
||||||
|
|
||||||
We protect your rights with two steps: (1) copyright the software, and
|
|
||||||
(2) offer you this license which gives you legal permission to copy,
|
|
||||||
distribute and/or modify the software.
|
|
||||||
|
|
||||||
Also, for each author's protection and ours, we want to make certain
|
|
||||||
that everyone understands that there is no warranty for this free
|
|
||||||
software. If the software is modified by someone else and passed on, we
|
|
||||||
want its recipients to know that what they have is not the original, so
|
|
||||||
that any problems introduced by others will not reflect on the original
|
|
||||||
authors' reputations.
|
|
||||||
|
|
||||||
Finally, any free program is threatened constantly by software
|
|
||||||
patents. We wish to avoid the danger that redistributors of a free
|
|
||||||
program will individually obtain patent licenses, in effect making the
|
|
||||||
program proprietary. To prevent this, we have made it clear that any
|
|
||||||
patent must be licensed for everyone's free use or not licensed at all.
|
|
||||||
|
|
||||||
The precise terms and conditions for copying, distribution and
|
|
||||||
modification follow.
|
|
||||||
|
|
||||||
GNU GENERAL PUBLIC LICENSE
|
|
||||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
|
||||||
|
|
||||||
0. This License applies to any program or other work which contains
|
|
||||||
a notice placed by the copyright holder saying it may be distributed
|
|
||||||
under the terms of this General Public License. The "Program", below,
|
|
||||||
refers to any such program or work, and a "work based on the Program"
|
|
||||||
means either the Program or any derivative work under copyright law:
|
|
||||||
that is to say, a work containing the Program or a portion of it,
|
|
||||||
either verbatim or with modifications and/or translated into another
|
|
||||||
language. (Hereinafter, translation is included without limitation in
|
|
||||||
the term "modification".) Each licensee is addressed as "you".
|
|
||||||
|
|
||||||
Activities other than copying, distribution and modification are not
|
|
||||||
covered by this License; they are outside its scope. The act of
|
|
||||||
running the Program is not restricted, and the output from the Program
|
|
||||||
is covered only if its contents constitute a work based on the
|
|
||||||
Program (independent of having been made by running the Program).
|
|
||||||
Whether that is true depends on what the Program does.
|
|
||||||
|
|
||||||
1. You may copy and distribute verbatim copies of the Program's
|
|
||||||
source code as you receive it, in any medium, provided that you
|
|
||||||
conspicuously and appropriately publish on each copy an appropriate
|
|
||||||
copyright notice and disclaimer of warranty; keep intact all the
|
|
||||||
notices that refer to this License and to the absence of any warranty;
|
|
||||||
and give any other recipients of the Program a copy of this License
|
|
||||||
along with the Program.
|
|
||||||
|
|
||||||
You may charge a fee for the physical act of transferring a copy, and
|
|
||||||
you may at your option offer warranty protection in exchange for a fee.
|
|
||||||
|
|
||||||
2. You may modify your copy or copies of the Program or any portion
|
|
||||||
of it, thus forming a work based on the Program, and copy and
|
|
||||||
distribute such modifications or work under the terms of Section 1
|
|
||||||
above, provided that you also meet all of these conditions:
|
|
||||||
|
|
||||||
a) You must cause the modified files to carry prominent notices
|
|
||||||
stating that you changed the files and the date of any change.
|
|
||||||
|
|
||||||
b) You must cause any work that you distribute or publish, that in
|
|
||||||
whole or in part contains or is derived from the Program or any
|
|
||||||
part thereof, to be licensed as a whole at no charge to all third
|
|
||||||
parties under the terms of this License.
|
|
||||||
|
|
||||||
c) If the modified program normally reads commands interactively
|
|
||||||
when run, you must cause it, when started running for such
|
|
||||||
interactive use in the most ordinary way, to print or display an
|
|
||||||
announcement including an appropriate copyright notice and a
|
|
||||||
notice that there is no warranty (or else, saying that you provide
|
|
||||||
a warranty) and that users may redistribute the program under
|
|
||||||
these conditions, and telling the user how to view a copy of this
|
|
||||||
License. (Exception: if the Program itself is interactive but
|
|
||||||
does not normally print such an announcement, your work based on
|
|
||||||
the Program is not required to print an announcement.)
|
|
||||||
|
|
||||||
These requirements apply to the modified work as a whole. If
|
|
||||||
identifiable sections of that work are not derived from the Program,
|
|
||||||
and can be reasonably considered independent and separate works in
|
|
||||||
themselves, then this License, and its terms, do not apply to those
|
|
||||||
sections when you distribute them as separate works. But when you
|
|
||||||
distribute the same sections as part of a whole which is a work based
|
|
||||||
on the Program, the distribution of the whole must be on the terms of
|
|
||||||
this License, whose permissions for other licensees extend to the
|
|
||||||
entire whole, and thus to each and every part regardless of who wrote it.
|
|
||||||
|
|
||||||
Thus, it is not the intent of this section to claim rights or contest
|
|
||||||
your rights to work written entirely by you; rather, the intent is to
|
|
||||||
exercise the right to control the distribution of derivative or
|
|
||||||
collective works based on the Program.
|
|
||||||
|
|
||||||
In addition, mere aggregation of another work not based on the Program
|
|
||||||
with the Program (or with a work based on the Program) on a volume of
|
|
||||||
a storage or distribution medium does not bring the other work under
|
|
||||||
the scope of this License.
|
|
||||||
|
|
||||||
3. You may copy and distribute the Program (or a work based on it,
|
|
||||||
under Section 2) in object code or executable form under the terms of
|
|
||||||
Sections 1 and 2 above provided that you also do one of the following:
|
|
||||||
|
|
||||||
a) Accompany it with the complete corresponding machine-readable
|
|
||||||
source code, which must be distributed under the terms of Sections
|
|
||||||
1 and 2 above on a medium customarily used for software interchange; or,
|
|
||||||
|
|
||||||
b) Accompany it with a written offer, valid for at least three
|
|
||||||
years, to give any third party, for a charge no more than your
|
|
||||||
cost of physically performing source distribution, a complete
|
|
||||||
machine-readable copy of the corresponding source code, to be
|
|
||||||
distributed under the terms of Sections 1 and 2 above on a medium
|
|
||||||
customarily used for software interchange; or,
|
|
||||||
|
|
||||||
c) Accompany it with the information you received as to the offer
|
|
||||||
to distribute corresponding source code. (This alternative is
|
|
||||||
allowed only for noncommercial distribution and only if you
|
|
||||||
received the program in object code or executable form with such
|
|
||||||
an offer, in accord with Subsection b above.)
|
|
||||||
|
|
||||||
The source code for a work means the preferred form of the work for
|
|
||||||
making modifications to it. For an executable work, complete source
|
|
||||||
code means all the source code for all modules it contains, plus any
|
|
||||||
associated interface definition files, plus the scripts used to
|
|
||||||
control compilation and installation of the executable. However, as a
|
|
||||||
special exception, the source code distributed need not include
|
|
||||||
anything that is normally distributed (in either source or binary
|
|
||||||
form) with the major components (compiler, kernel, and so on) of the
|
|
||||||
operating system on which the executable runs, unless that component
|
|
||||||
itself accompanies the executable.
|
|
||||||
|
|
||||||
If distribution of executable or object code is made by offering
|
|
||||||
access to copy from a designated place, then offering equivalent
|
|
||||||
access to copy the source code from the same place counts as
|
|
||||||
distribution of the source code, even though third parties are not
|
|
||||||
compelled to copy the source along with the object code.
|
|
||||||
|
|
||||||
4. You may not copy, modify, sublicense, or distribute the Program
|
|
||||||
except as expressly provided under this License. Any attempt
|
|
||||||
otherwise to copy, modify, sublicense or distribute the Program is
|
|
||||||
void, and will automatically terminate your rights under this License.
|
|
||||||
However, parties who have received copies, or rights, from you under
|
|
||||||
this License will not have their licenses terminated so long as such
|
|
||||||
parties remain in full compliance.
|
|
||||||
|
|
||||||
5. You are not required to accept this License, since you have not
|
|
||||||
signed it. However, nothing else grants you permission to modify or
|
|
||||||
distribute the Program or its derivative works. These actions are
|
|
||||||
prohibited by law if you do not accept this License. Therefore, by
|
|
||||||
modifying or distributing the Program (or any work based on the
|
|
||||||
Program), you indicate your acceptance of this License to do so, and
|
|
||||||
all its terms and conditions for copying, distributing or modifying
|
|
||||||
the Program or works based on it.
|
|
||||||
|
|
||||||
6. Each time you redistribute the Program (or any work based on the
|
|
||||||
Program), the recipient automatically receives a license from the
|
|
||||||
original licensor to copy, distribute or modify the Program subject to
|
|
||||||
these terms and conditions. You may not impose any further
|
|
||||||
restrictions on the recipients' exercise of the rights granted herein.
|
|
||||||
You are not responsible for enforcing compliance by third parties to
|
|
||||||
this License.
|
|
||||||
|
|
||||||
7. If, as a consequence of a court judgment or allegation of patent
|
|
||||||
infringement or for any other reason (not limited to patent issues),
|
|
||||||
conditions are imposed on you (whether by court order, agreement or
|
|
||||||
otherwise) that contradict the conditions of this License, they do not
|
|
||||||
excuse you from the conditions of this License. If you cannot
|
|
||||||
distribute so as to satisfy simultaneously your obligations under this
|
|
||||||
License and any other pertinent obligations, then as a consequence you
|
|
||||||
may not distribute the Program at all. For example, if a patent
|
|
||||||
license would not permit royalty-free redistribution of the Program by
|
|
||||||
all those who receive copies directly or indirectly through you, then
|
|
||||||
the only way you could satisfy both it and this License would be to
|
|
||||||
refrain entirely from distribution of the Program.
|
|
||||||
|
|
||||||
If any portion of this section is held invalid or unenforceable under
|
|
||||||
any particular circumstance, the balance of the section is intended to
|
|
||||||
apply and the section as a whole is intended to apply in other
|
|
||||||
circumstances.
|
|
||||||
|
|
||||||
It is not the purpose of this section to induce you to infringe any
|
|
||||||
patents or other property right claims or to contest validity of any
|
|
||||||
such claims; this section has the sole purpose of protecting the
|
|
||||||
integrity of the free software distribution system, which is
|
|
||||||
implemented by public license practices. Many people have made
|
|
||||||
generous contributions to the wide range of software distributed
|
|
||||||
through that system in reliance on consistent application of that
|
|
||||||
system; it is up to the author/donor to decide if he or she is willing
|
|
||||||
to distribute software through any other system and a licensee cannot
|
|
||||||
impose that choice.
|
|
||||||
|
|
||||||
This section is intended to make thoroughly clear what is believed to
|
|
||||||
be a consequence of the rest of this License.
|
|
||||||
|
|
||||||
8. If the distribution and/or use of the Program is restricted in
|
|
||||||
certain countries either by patents or by copyrighted interfaces, the
|
|
||||||
original copyright holder who places the Program under this License
|
|
||||||
may add an explicit geographical distribution limitation excluding
|
|
||||||
those countries, so that distribution is permitted only in or among
|
|
||||||
countries not thus excluded. In such case, this License incorporates
|
|
||||||
the limitation as if written in the body of this License.
|
|
||||||
|
|
||||||
9. The Free Software Foundation may publish revised and/or new versions
|
|
||||||
of the General Public License from time to time. Such new versions will
|
|
||||||
be similar in spirit to the present version, but may differ in detail to
|
|
||||||
address new problems or concerns.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the Program
|
|
||||||
specifies a version number of this License which applies to it and "any
|
|
||||||
later version", you have the option of following the terms and conditions
|
|
||||||
either of that version or of any later version published by the Free
|
|
||||||
Software Foundation. If the Program does not specify a version number of
|
|
||||||
this License, you may choose any version ever published by the Free Software
|
|
||||||
Foundation.
|
|
||||||
|
|
||||||
10. If you wish to incorporate parts of the Program into other free
|
|
||||||
programs whose distribution conditions are different, write to the author
|
|
||||||
to ask for permission. For software which is copyrighted by the Free
|
|
||||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
|
||||||
make exceptions for this. Our decision will be guided by the two goals
|
|
||||||
of preserving the free status of all derivatives of our free software and
|
|
||||||
of promoting the sharing and reuse of software generally.
|
|
||||||
|
|
||||||
NO WARRANTY
|
|
||||||
|
|
||||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
|
||||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
|
||||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
|
||||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
|
||||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
|
||||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
|
||||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
|
||||||
REPAIR OR CORRECTION.
|
|
||||||
|
|
||||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
|
||||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
|
||||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
|
||||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
|
||||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
|
||||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
|
||||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
|
||||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
|
||||||
POSSIBILITY OF SUCH DAMAGES.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
How to Apply These Terms to Your New Programs
|
|
||||||
|
|
||||||
If you develop a new program, and you want it to be of the greatest
|
|
||||||
possible use to the public, the best way to achieve this is to make it
|
|
||||||
free software which everyone can redistribute and change under these terms.
|
|
||||||
|
|
||||||
To do so, attach the following notices to the program. It is safest
|
|
||||||
to attach them to the start of each source file to most effectively
|
|
||||||
convey the exclusion of warranty; and each file should have at least
|
|
||||||
the "copyright" line and a pointer to where the full notice is found.
|
|
||||||
|
|
||||||
<one line to give the program's name and a brief idea of what it does.>
|
|
||||||
Copyright (C) <year> <name of author>
|
|
||||||
|
|
||||||
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 2 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, write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
|
||||||
|
|
||||||
If the program is interactive, make it output a short notice like this
|
|
||||||
when it starts in an interactive mode:
|
|
||||||
|
|
||||||
Gnomovision version 69, Copyright (C) year name of author
|
|
||||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
|
||||||
This is free software, and you are welcome to redistribute it
|
|
||||||
under certain conditions; type `show c' for details.
|
|
||||||
|
|
||||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
|
||||||
parts of the General Public License. Of course, the commands you use may
|
|
||||||
be called something other than `show w' and `show c'; they could even be
|
|
||||||
mouse-clicks or menu items--whatever suits your program.
|
|
||||||
|
|
||||||
You should also get your employer (if you work as a programmer) or your
|
|
||||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
|
||||||
necessary. Here is a sample; alter the names:
|
|
||||||
|
|
||||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
|
||||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
|
||||||
|
|
||||||
<signature of Ty Coon>, 1 April 1989
|
|
||||||
Ty Coon, President of Vice
|
|
||||||
|
|
||||||
This General Public License does not permit incorporating your program into
|
|
||||||
proprietary programs. If your program is a subroutine library, you may
|
|
||||||
consider it more useful to permit linking proprietary applications with the
|
|
||||||
library. If this is what you want to do, use the GNU Lesser General
|
|
||||||
Public License instead of this License.
|
|
||||||
-12
@@ -1,12 +0,0 @@
|
|||||||
The server code and utilities are released under GPLv3.
|
|
||||||
|
|
||||||
We also include some small libraries for convienence that may be under different licensing:
|
|
||||||
|
|
||||||
SocketLib - GPL
|
|
||||||
LibXML - ZLib License
|
|
||||||
StackWalker - New BSD License
|
|
||||||
ZLib - ZLib License
|
|
||||||
MySQL - GPL
|
|
||||||
Perl - GPL / ActiveState (under the assumption that this is a free project).
|
|
||||||
CPPUnit - GLP
|
|
||||||
StringUtilities - Apache
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
EQEmu - Custom Game Implementation for EverQuest
|
|
||||||
|
|
||||||
Dependencies can be obtained at http://eqemu.github.io
|
|
||||||
|
|
||||||
More Information: https://github.com/EQEmu/Server/wiki
|
|
||||||
-8744
File diff suppressed because it is too large
Load Diff
@@ -1,4 +0,0 @@
|
|||||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
|
|
||||||
|
|
||||||
add_subdirectory(import)
|
|
||||||
add_subdirectory(export)
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
|
|
||||||
|
|
||||||
SET(export_sources
|
|
||||||
main.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
SET(export_headers
|
|
||||||
)
|
|
||||||
|
|
||||||
ADD_EXECUTABLE(export_client_files ${export_sources} ${export_headers})
|
|
||||||
|
|
||||||
INSTALL(TARGETS export_client_files RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX})
|
|
||||||
|
|
||||||
TARGET_LINK_LIBRARIES(export_client_files Common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} ${ZLIB_LIBRARY})
|
|
||||||
|
|
||||||
IF(MSVC)
|
|
||||||
SET_TARGET_PROPERTIES(export_client_files PROPERTIES LINK_FLAGS_RELEASE "/OPT:REF /OPT:ICF")
|
|
||||||
TARGET_LINK_LIBRARIES(export_client_files "Ws2_32.lib")
|
|
||||||
ENDIF(MSVC)
|
|
||||||
|
|
||||||
IF(MINGW)
|
|
||||||
TARGET_LINK_LIBRARIES(export_client_files "WS2_32")
|
|
||||||
ENDIF(MINGW)
|
|
||||||
|
|
||||||
IF(UNIX)
|
|
||||||
TARGET_LINK_LIBRARIES(export_client_files "${CMAKE_DL_LIBS}")
|
|
||||||
TARGET_LINK_LIBRARIES(export_client_files "z")
|
|
||||||
TARGET_LINK_LIBRARIES(export_client_files "m")
|
|
||||||
IF(NOT DARWIN)
|
|
||||||
TARGET_LINK_LIBRARIES(export_client_files "rt")
|
|
||||||
ENDIF(NOT DARWIN)
|
|
||||||
TARGET_LINK_LIBRARIES(export_client_files "pthread")
|
|
||||||
ADD_DEFINITIONS(-fPIC)
|
|
||||||
ENDIF(UNIX)
|
|
||||||
|
|
||||||
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/Bin)
|
|
||||||
@@ -1,203 +0,0 @@
|
|||||||
/* EQEMu: Everquest Server Emulator
|
|
||||||
Copyright (C) 2001-2013 EQEMu Development Team (http://eqemulator.net)
|
|
||||||
|
|
||||||
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; version 2 of the License.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
||||||
are required to give you total support for your newly bought product;
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "../../common/debug.h"
|
|
||||||
#include "../../common/shareddb.h"
|
|
||||||
#include "../../common/EQEmuConfig.h"
|
|
||||||
#include "../../common/platform.h"
|
|
||||||
#include "../../common/crash.h"
|
|
||||||
#include "../../common/rulesys.h"
|
|
||||||
#include "../../common/StringUtil.h"
|
|
||||||
|
|
||||||
void ExportSpells(SharedDatabase *db);
|
|
||||||
void ExportSkillCaps(SharedDatabase *db);
|
|
||||||
void ExportBaseData(SharedDatabase *db);
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
|
||||||
RegisterExecutablePlatform(ExePlatformClientExport);
|
|
||||||
set_exception_handler();
|
|
||||||
|
|
||||||
LogFile->write(EQEMuLog::Status, "Client Files Export Utility");
|
|
||||||
if(!EQEmuConfig::LoadConfig()) {
|
|
||||||
LogFile->write(EQEMuLog::Error, "Unable to load configuration file.");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
const EQEmuConfig *config = EQEmuConfig::get();
|
|
||||||
if(!load_log_settings(config->LogSettingsFile.c_str())) {
|
|
||||||
LogFile->write(EQEMuLog::Error, "Warning: unable to read %s.", config->LogSettingsFile.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
SharedDatabase database;
|
|
||||||
LogFile->write(EQEMuLog::Status, "Connecting to database...");
|
|
||||||
if(!database.Connect(config->DatabaseHost.c_str(), config->DatabaseUsername.c_str(),
|
|
||||||
config->DatabasePassword.c_str(), config->DatabaseDB.c_str(), config->DatabasePort)) {
|
|
||||||
LogFile->write(EQEMuLog::Error, "Unable to connect to the database, cannot continue without a "
|
|
||||||
"database connection");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ExportSpells(&database);
|
|
||||||
ExportSkillCaps(&database);
|
|
||||||
ExportBaseData(&database);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExportSpells(SharedDatabase *db) {
|
|
||||||
LogFile->write(EQEMuLog::Status, "Exporting Spells...");
|
|
||||||
|
|
||||||
FILE *f = fopen("export/spells_us.txt", "w");
|
|
||||||
if(!f) {
|
|
||||||
LogFile->write(EQEMuLog::Error, "Unable to open export/spells_us.txt to write, skipping.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
|
||||||
char *query = "SELECT * FROM spells_new ORDER BY id";
|
|
||||||
MYSQL_RES *result;
|
|
||||||
MYSQL_ROW row;
|
|
||||||
if(db->RunQuery(query, strlen(query), errbuf, &result)) {
|
|
||||||
while(row = mysql_fetch_row(result)) {
|
|
||||||
std::string line;
|
|
||||||
unsigned int fields = mysql_num_fields(result);
|
|
||||||
for(unsigned int i = 0; i < fields; ++i) {
|
|
||||||
if(i != 0) {
|
|
||||||
line.push_back('^');
|
|
||||||
}
|
|
||||||
|
|
||||||
line += row[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(f, "%s\n", line.c_str());
|
|
||||||
}
|
|
||||||
mysql_free_result(result);
|
|
||||||
} else {
|
|
||||||
LogFile->write(EQEMuLog::Error, "Error in ExportSpells query '%s' %s", query, errbuf);
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SkillUsable(SharedDatabase *db, int skill_id, int class_id) {
|
|
||||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
|
||||||
char *query = nullptr;
|
|
||||||
MYSQL_RES *result;
|
|
||||||
MYSQL_ROW row;
|
|
||||||
bool res = false;
|
|
||||||
if(db->RunQuery(query, MakeAnyLenString(&query, "SELECT max(cap) FROM skill_caps WHERE class=%d AND skillID=%d",
|
|
||||||
class_id, skill_id), errbuf, &result)) {
|
|
||||||
if(row = mysql_fetch_row(result)) {
|
|
||||||
if(row[0] && atoi(row[0]) > 0) {
|
|
||||||
res = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mysql_free_result(result);
|
|
||||||
} else {
|
|
||||||
LogFile->write(EQEMuLog::Error, "Error in skill_usable query '%s' %s", query, errbuf);
|
|
||||||
}
|
|
||||||
|
|
||||||
safe_delete_array(query);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
int GetSkill(SharedDatabase *db, int skill_id, int class_id, int level) {
|
|
||||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
|
||||||
char *query = nullptr;
|
|
||||||
MYSQL_RES *result;
|
|
||||||
MYSQL_ROW row;
|
|
||||||
int res = 0;
|
|
||||||
if(db->RunQuery(query, MakeAnyLenString(&query, "SELECT cap FROM skill_caps WHERE class=%d AND skillID=%d AND level=%d",
|
|
||||||
class_id, skill_id, level), errbuf, &result)) {
|
|
||||||
if(row = mysql_fetch_row(result)) {
|
|
||||||
res = atoi(row[0]);
|
|
||||||
}
|
|
||||||
mysql_free_result(result);
|
|
||||||
} else {
|
|
||||||
LogFile->write(EQEMuLog::Error, "Error in get_skill query '%s' %s", query, errbuf);
|
|
||||||
}
|
|
||||||
|
|
||||||
safe_delete_array(query);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExportSkillCaps(SharedDatabase *db) {
|
|
||||||
LogFile->write(EQEMuLog::Status, "Exporting Skill Caps...");
|
|
||||||
|
|
||||||
FILE *f = fopen("export/SkillCaps.txt", "w");
|
|
||||||
if(!f) {
|
|
||||||
LogFile->write(EQEMuLog::Error, "Unable to open export/SkillCaps.txt to write, skipping.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int cl = 1; cl <= 16; ++cl) {
|
|
||||||
for(int skill = 0; skill <= 77; ++skill) {
|
|
||||||
if(SkillUsable(db, skill, cl)) {
|
|
||||||
int previous_cap = 0;
|
|
||||||
for(int level = 1; level <= 100; ++level) {
|
|
||||||
int cap = GetSkill(db, skill, cl, level);
|
|
||||||
if(cap < previous_cap) {
|
|
||||||
cap = previous_cap;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(f, "%d^%d^%d^%d^0\n", cl, skill, level, cap);
|
|
||||||
previous_cap = cap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExportBaseData(SharedDatabase *db) {
|
|
||||||
LogFile->write(EQEMuLog::Status, "Exporting Base Data...");
|
|
||||||
|
|
||||||
FILE *f = fopen("export/BaseData.txt", "w");
|
|
||||||
if(!f) {
|
|
||||||
LogFile->write(EQEMuLog::Error, "Unable to open export/BaseData.txt to write, skipping.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
|
||||||
char *query = "SELECT * FROM base_data ORDER BY level, class";
|
|
||||||
MYSQL_RES *result;
|
|
||||||
MYSQL_ROW row;
|
|
||||||
if(db->RunQuery(query, strlen(query), errbuf, &result)) {
|
|
||||||
while(row = mysql_fetch_row(result)) {
|
|
||||||
std::string line;
|
|
||||||
unsigned int fields = mysql_num_fields(result);
|
|
||||||
for(unsigned int i = 0; i < fields; ++i) {
|
|
||||||
if(i != 0) {
|
|
||||||
line.push_back('^');
|
|
||||||
}
|
|
||||||
|
|
||||||
line += row[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(f, "%s\n", line.c_str());
|
|
||||||
}
|
|
||||||
mysql_free_result(result);
|
|
||||||
} else {
|
|
||||||
LogFile->write(EQEMuLog::Error, "Error in ExportBaseData query '%s' %s", query, errbuf);
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
|
|
||||||
|
|
||||||
SET(import_sources
|
|
||||||
main.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
SET(import_headers
|
|
||||||
)
|
|
||||||
|
|
||||||
ADD_EXECUTABLE(import_client_files ${import_sources} ${import_headers})
|
|
||||||
|
|
||||||
INSTALL(TARGETS import_client_files RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX})
|
|
||||||
|
|
||||||
TARGET_LINK_LIBRARIES(import_client_files Common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} ${ZLIB_LIBRARY})
|
|
||||||
|
|
||||||
IF(MSVC)
|
|
||||||
SET_TARGET_PROPERTIES(import_client_files PROPERTIES LINK_FLAGS_RELEASE "/OPT:REF /OPT:ICF")
|
|
||||||
TARGET_LINK_LIBRARIES(import_client_files "Ws2_32.lib")
|
|
||||||
ENDIF(MSVC)
|
|
||||||
|
|
||||||
IF(MINGW)
|
|
||||||
TARGET_LINK_LIBRARIES(import_client_files "WS2_32")
|
|
||||||
ENDIF(MINGW)
|
|
||||||
|
|
||||||
IF(UNIX)
|
|
||||||
TARGET_LINK_LIBRARIES(import_client_files "${CMAKE_DL_LIBS}")
|
|
||||||
TARGET_LINK_LIBRARIES(import_client_files "z")
|
|
||||||
TARGET_LINK_LIBRARIES(import_client_files "m")
|
|
||||||
IF(NOT DARWIN)
|
|
||||||
TARGET_LINK_LIBRARIES(import_client_files "rt")
|
|
||||||
ENDIF(NOT DARWIN)
|
|
||||||
TARGET_LINK_LIBRARIES(import_client_files "pthread")
|
|
||||||
ADD_DEFINITIONS(-fPIC)
|
|
||||||
ENDIF(UNIX)
|
|
||||||
|
|
||||||
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/Bin)
|
|
||||||
@@ -1,237 +0,0 @@
|
|||||||
/* EQEMu: Everquest Server Emulator
|
|
||||||
Copyright (C) 2001-2013 EQEMu Development Team (http://eqemulator.net)
|
|
||||||
|
|
||||||
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; version 2 of the License.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
||||||
are required to give you total support for your newly bought product;
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "../../common/debug.h"
|
|
||||||
#include "../../common/shareddb.h"
|
|
||||||
#include "../../common/EQEmuConfig.h"
|
|
||||||
#include "../../common/platform.h"
|
|
||||||
#include "../../common/crash.h"
|
|
||||||
#include "../../common/rulesys.h"
|
|
||||||
#include "../../common/StringUtil.h"
|
|
||||||
|
|
||||||
void ImportSpells(SharedDatabase *db);
|
|
||||||
void ImportSkillCaps(SharedDatabase *db);
|
|
||||||
void ImportBaseData(SharedDatabase *db);
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
|
||||||
RegisterExecutablePlatform(ExePlatformClientImport);
|
|
||||||
set_exception_handler();
|
|
||||||
|
|
||||||
LogFile->write(EQEMuLog::Status, "Client Files Import Utility");
|
|
||||||
if(!EQEmuConfig::LoadConfig()) {
|
|
||||||
LogFile->write(EQEMuLog::Error, "Unable to load configuration file.");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
const EQEmuConfig *config = EQEmuConfig::get();
|
|
||||||
if(!load_log_settings(config->LogSettingsFile.c_str())) {
|
|
||||||
LogFile->write(EQEMuLog::Error, "Warning: unable to read %s.", config->LogSettingsFile.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
SharedDatabase database;
|
|
||||||
LogFile->write(EQEMuLog::Status, "Connecting to database...");
|
|
||||||
if(!database.Connect(config->DatabaseHost.c_str(), config->DatabaseUsername.c_str(),
|
|
||||||
config->DatabasePassword.c_str(), config->DatabaseDB.c_str(), config->DatabasePort)) {
|
|
||||||
LogFile->write(EQEMuLog::Error, "Unable to connect to the database, cannot continue without a "
|
|
||||||
"database connection");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImportSpells(&database);
|
|
||||||
ImportSkillCaps(&database);
|
|
||||||
ImportBaseData(&database);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int GetSpellColumns(SharedDatabase *db) {
|
|
||||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
|
||||||
char *query = "DESCRIBE spells_new";
|
|
||||||
MYSQL_RES *result;
|
|
||||||
MYSQL_ROW row;
|
|
||||||
int res = 0;
|
|
||||||
if(db->RunQuery(query, (uint32)strlen(query), errbuf, &result)) {
|
|
||||||
while(row = mysql_fetch_row(result)) {
|
|
||||||
++res;
|
|
||||||
}
|
|
||||||
mysql_free_result(result);
|
|
||||||
} else {
|
|
||||||
LogFile->write(EQEMuLog::Error, "Error in GetSpellColumns query '%s' %s", query, errbuf);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImportSpells(SharedDatabase *db) {
|
|
||||||
LogFile->write(EQEMuLog::Status, "Importing Spells...");
|
|
||||||
FILE *f = fopen("import/spells_us.txt", "r");
|
|
||||||
if(!f) {
|
|
||||||
LogFile->write(EQEMuLog::Error, "Unable to open import/spells_us.txt to read, skipping.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string delete_sql = "DELETE FROM spells_new";
|
|
||||||
db->RunQuery(delete_sql.c_str(), (uint32)delete_sql.length());
|
|
||||||
|
|
||||||
int columns = GetSpellColumns(db);
|
|
||||||
int spells_imported = 0;
|
|
||||||
|
|
||||||
char buffer[2048];
|
|
||||||
while(fgets(buffer, 2048, f)) {
|
|
||||||
for(int i = 0; i < 2048; ++i) {
|
|
||||||
if(buffer[i] == '\n') {
|
|
||||||
buffer[i] = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string escaped = ::EscapeString(buffer);
|
|
||||||
auto split = SplitString(escaped, '^');
|
|
||||||
int line_columns = (int)split.size();
|
|
||||||
std::string sql;
|
|
||||||
|
|
||||||
if(line_columns >= columns) {
|
|
||||||
sql = "INSERT INTO spells_new VALUES(";
|
|
||||||
for(int i = 0; i < columns; ++i) {
|
|
||||||
if(i != 0) {
|
|
||||||
sql += ", '";
|
|
||||||
} else {
|
|
||||||
sql += "'";
|
|
||||||
}
|
|
||||||
|
|
||||||
sql += split[i];
|
|
||||||
sql += "'";
|
|
||||||
}
|
|
||||||
|
|
||||||
sql += ");";
|
|
||||||
} else {
|
|
||||||
int i = 0;
|
|
||||||
sql = "INSERT INTO spells_new VALUES(";
|
|
||||||
for(; i < line_columns; ++i) {
|
|
||||||
if(i != 0) {
|
|
||||||
sql += ", '";
|
|
||||||
} else {
|
|
||||||
sql += "'";
|
|
||||||
}
|
|
||||||
|
|
||||||
sql += split[i];
|
|
||||||
sql += "'";
|
|
||||||
}
|
|
||||||
|
|
||||||
for(; i < columns; ++i) {
|
|
||||||
sql += ", '0'";
|
|
||||||
}
|
|
||||||
|
|
||||||
sql += ");";
|
|
||||||
}
|
|
||||||
|
|
||||||
db->RunQuery(sql.c_str(), (uint32)sql.length());
|
|
||||||
|
|
||||||
spells_imported++;
|
|
||||||
if(spells_imported % 1000 == 0) {
|
|
||||||
LogFile->write(EQEMuLog::Status, "%d spells imported.", spells_imported);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(spells_imported % 1000 != 0) {
|
|
||||||
LogFile->write(EQEMuLog::Status, "%d spells imported.", spells_imported);
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImportSkillCaps(SharedDatabase *db) {
|
|
||||||
LogFile->write(EQEMuLog::Status, "Importing Skill Caps...");
|
|
||||||
|
|
||||||
FILE *f = fopen("import/SkillCaps.txt", "r");
|
|
||||||
if(!f) {
|
|
||||||
LogFile->write(EQEMuLog::Error, "Unable to open import/SkillCaps.txt to read, skipping.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string delete_sql = "DELETE FROM skill_caps";
|
|
||||||
db->RunQuery(delete_sql.c_str(), (uint32)delete_sql.length());
|
|
||||||
|
|
||||||
char buffer[2048];
|
|
||||||
while(fgets(buffer, 2048, f)) {
|
|
||||||
auto split = SplitString(buffer, '^');
|
|
||||||
|
|
||||||
if(split.size() < 4) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string sql;
|
|
||||||
int class_id, skill_id, level, cap;
|
|
||||||
class_id = atoi(split[0].c_str());
|
|
||||||
skill_id = atoi(split[1].c_str());
|
|
||||||
level = atoi(split[2].c_str());
|
|
||||||
cap = atoi(split[3].c_str());
|
|
||||||
|
|
||||||
StringFormat(sql, "INSERT INTO skill_caps(class, skillID, level, cap) VALUES(%d, %d, %d, %d)",
|
|
||||||
class_id, skill_id, level, cap);
|
|
||||||
|
|
||||||
db->RunQuery(sql.c_str(), (uint32)sql.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImportBaseData(SharedDatabase *db) {
|
|
||||||
LogFile->write(EQEMuLog::Status, "Importing Base Data...");
|
|
||||||
|
|
||||||
FILE *f = fopen("import/BaseData.txt", "r");
|
|
||||||
if(!f) {
|
|
||||||
LogFile->write(EQEMuLog::Error, "Unable to open import/BaseData.txt to read, skipping.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string delete_sql = "DELETE FROM base_data";
|
|
||||||
db->RunQuery(delete_sql.c_str(), (uint32)delete_sql.length());
|
|
||||||
|
|
||||||
char buffer[2048];
|
|
||||||
while(fgets(buffer, 2048, f)) {
|
|
||||||
auto split = SplitString(buffer, '^');
|
|
||||||
|
|
||||||
if(split.size() < 10) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string sql;
|
|
||||||
int level, class_id;
|
|
||||||
double hp, mana, end, unk1, unk2, hp_fac, mana_fac, end_fac;
|
|
||||||
|
|
||||||
level = atoi(split[0].c_str());
|
|
||||||
class_id = atoi(split[1].c_str());
|
|
||||||
hp = atof(split[2].c_str());
|
|
||||||
mana = atof(split[3].c_str());
|
|
||||||
end = atof(split[4].c_str());
|
|
||||||
unk1 = atof(split[5].c_str());
|
|
||||||
unk2 = atof(split[6].c_str());
|
|
||||||
hp_fac = atof(split[7].c_str());
|
|
||||||
mana_fac = atof(split[8].c_str());
|
|
||||||
end_fac = atof(split[9].c_str());
|
|
||||||
|
|
||||||
StringFormat(sql, "INSERT INTO base_data(level, class, hp, mana, end, unk1, unk2, hp_fac, "
|
|
||||||
"mana_fac, end_fac) VALUES(%d, %d, %f, %f, %f, %f, %f, %f, %f, %f)",
|
|
||||||
level, class_id, hp, mana, end, unk1, unk2, hp_fac, mana_fac, end_fac);
|
|
||||||
|
|
||||||
db->RunQuery(sql.c_str(), (uint32)sql.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(f);
|
|
||||||
}
|
|
||||||
@@ -1,124 +0,0 @@
|
|||||||
#CMake - Cross Platform Makefile Generator
|
|
||||||
#Copyright 2000-2011 Kitware, Inc., Insight Software Consortium
|
|
||||||
#All rights reserved.
|
|
||||||
#
|
|
||||||
#Redistribution and use in source and binary forms, with or without
|
|
||||||
#modification, are permitted provided that the following conditions
|
|
||||||
#are met:
|
|
||||||
#
|
|
||||||
#* Redistributions of source code must retain the above copyright
|
|
||||||
# notice, this list of conditions and the following disclaimer.
|
|
||||||
#
|
|
||||||
#* Redistributions in binary form must reproduce the above copyright
|
|
||||||
# notice, this list of conditions and the following disclaimer in the
|
|
||||||
# documentation and/or other materials provided with the distribution.
|
|
||||||
#
|
|
||||||
#* Neither the names of Kitware, Inc., the Insight Software Consortium,
|
|
||||||
# nor the names of their contributors may be used to endorse or promote
|
|
||||||
# products derived from this software without specific prior written
|
|
||||||
# permission.
|
|
||||||
#
|
|
||||||
#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
#"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
#LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
#A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
#HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
#SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
#LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
#DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
#THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
#(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
#OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
# This module defines
|
|
||||||
# LUA51_FOUND, if false, do not try to link to Lua
|
|
||||||
# LUA_LIBRARIES
|
|
||||||
# LUA_INCLUDE_DIR, where to find lua.h
|
|
||||||
# LUA_VERSION_STRING, the version of Lua found (since CMake 2.8.8)
|
|
||||||
|
|
||||||
IF(LUA_ROOT)
|
|
||||||
FIND_PATH(LUA_INCLUDE_DIR
|
|
||||||
NAMES lua.h
|
|
||||||
HINTS
|
|
||||||
ENV LUA_DIR
|
|
||||||
PATHS
|
|
||||||
${LUA_ROOT}
|
|
||||||
~/Library/Frameworks
|
|
||||||
/Library/Frameworks
|
|
||||||
/sw
|
|
||||||
/opt/local
|
|
||||||
/opt/csw
|
|
||||||
/opt
|
|
||||||
PATH_SUFFIXES include/lua51 include/lua5.1 include/lua include src
|
|
||||||
)
|
|
||||||
|
|
||||||
FIND_LIBRARY(LUA_LIBRARY
|
|
||||||
NAMES lua51 lua5.1 lua-5.1 lua
|
|
||||||
HINTS
|
|
||||||
ENV LUA_DIR
|
|
||||||
PATHS
|
|
||||||
${LUA_ROOT}
|
|
||||||
~/Library/Frameworks
|
|
||||||
/Library/Frameworks
|
|
||||||
/sw
|
|
||||||
/opt/local
|
|
||||||
/opt/csw
|
|
||||||
/opt
|
|
||||||
PATH_SUFFIXES lib bin
|
|
||||||
)
|
|
||||||
ELSE(LUA_ROOT)
|
|
||||||
FIND_PATH(LUA_INCLUDE_DIR
|
|
||||||
NAMES lua.h
|
|
||||||
HINTS
|
|
||||||
ENV LUA_DIR
|
|
||||||
PATHS
|
|
||||||
~/Library/Frameworks
|
|
||||||
/Library/Frameworks
|
|
||||||
/sw
|
|
||||||
/opt/local
|
|
||||||
/opt/csw
|
|
||||||
/opt
|
|
||||||
PATH_SUFFIXES include/lua51 include/lua5.1 include/lua include
|
|
||||||
)
|
|
||||||
|
|
||||||
FIND_LIBRARY(LUA_LIBRARY
|
|
||||||
NAMES lua51 lua5.1 lua-5.1 lua
|
|
||||||
HINTS
|
|
||||||
ENV LUA_DIR
|
|
||||||
PATHS
|
|
||||||
~/Library/Frameworks
|
|
||||||
/Library/Frameworks
|
|
||||||
/sw
|
|
||||||
/opt/local
|
|
||||||
/opt/csw
|
|
||||||
/opt
|
|
||||||
PATH_SUFFIXES lib bin
|
|
||||||
)
|
|
||||||
ENDIF(LUA_ROOT)
|
|
||||||
|
|
||||||
IF(LUA_LIBRARY)
|
|
||||||
# include the math library for Unix
|
|
||||||
IF(UNIX AND NOT APPLE)
|
|
||||||
FIND_LIBRARY(LUA_MATH_LIBRARY m)
|
|
||||||
SET(LUA_LIBRARIES "${LUA_LIBRARY};${LUA_MATH_LIBRARY}" CACHE STRING "Lua Libraries")
|
|
||||||
# For Windows and Mac, don't need to explicitly include the math library
|
|
||||||
ELSE()
|
|
||||||
SET( LUA_LIBRARIES "${LUA_LIBRARY}" CACHE STRING "Lua Libraries")
|
|
||||||
ENDIF()
|
|
||||||
ENDIF()
|
|
||||||
|
|
||||||
IF(LUA_INCLUDE_DIR AND EXISTS "${LUA_INCLUDE_DIR}/lua.h")
|
|
||||||
FILE(STRINGS "${LUA_INCLUDE_DIR}/lua.h" lua_version_str REGEX "^#define[ \t]+LUA_RELEASE[ \t]+\"Lua .+\"")
|
|
||||||
|
|
||||||
STRING(REGEX REPLACE "^#define[ \t]+LUA_RELEASE[ \t]+\"Lua ([^\"]+)\".*" "\\1" LUA_VERSION_STRING "${lua_version_str}")
|
|
||||||
UNSET(lua_version_str)
|
|
||||||
ENDIF()
|
|
||||||
|
|
||||||
INCLUDE(FindPackageHandleStandardArgs)
|
|
||||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Lua51
|
|
||||||
REQUIRED_VARS LUA_LIBRARIES LUA_INCLUDE_DIR
|
|
||||||
VERSION_VAR LUA_VERSION_STRING)
|
|
||||||
|
|
||||||
MARK_AS_ADVANCED(LUA_INCLUDE_DIR LUA_LIBRARIES LUA_LIBRARY LUA_MATH_LIBRARY)
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
# - Find mysqlclient
|
|
||||||
#
|
|
||||||
# -*- cmake -*-
|
|
||||||
#
|
|
||||||
# Find the native MySQL includes and library
|
|
||||||
#
|
|
||||||
# MySQL_INCLUDE_DIR - where to find mysql.h, etc.
|
|
||||||
# MySQL_LIBRARIES - List of libraries when using MySQL.
|
|
||||||
# MySQL_FOUND - True if MySQL found.
|
|
||||||
# The following can be used as a hint as to where to search:
|
|
||||||
# MYSQL_ROOT
|
|
||||||
|
|
||||||
IF (MySQL_INCLUDE_DIR AND MySQL_LIBRARIES)
|
|
||||||
# Already in cache, be silent
|
|
||||||
SET(MySQL_FIND_QUIETLY TRUE)
|
|
||||||
ENDIF (MySQL_INCLUDE_DIR AND MySQL_LIBRARIES)
|
|
||||||
|
|
||||||
# Include dir
|
|
||||||
IF(MYSQL_ROOT)
|
|
||||||
FIND_PATH(MySQL_INCLUDE_DIR
|
|
||||||
NAMES mysql.h
|
|
||||||
PATHS ${MYSQL_ROOT}/include
|
|
||||||
PATH_SUFFIXES mysql
|
|
||||||
)
|
|
||||||
ELSE(MYSQL_ROOT)
|
|
||||||
FIND_PATH(MySQL_INCLUDE_DIR
|
|
||||||
NAMES mysql.h
|
|
||||||
PATH_SUFFIXES mysql
|
|
||||||
)
|
|
||||||
ENDIF(MYSQL_ROOT)
|
|
||||||
|
|
||||||
# Library
|
|
||||||
SET(MySQL_NAMES mysqlclient_r mysqlclient)
|
|
||||||
IF(MYSQL_ROOT)
|
|
||||||
FIND_LIBRARY(MySQL_LIBRARY_DEBUG
|
|
||||||
NAMES ${MySQL_NAMES}
|
|
||||||
PATHS ${MYSQL_ROOT}/lib/debug /usr/lib /usr/local/lib /usr/lib64 /usr/local/lib64
|
|
||||||
PATH_SUFFIXES mysql
|
|
||||||
)
|
|
||||||
|
|
||||||
FIND_LIBRARY(MySQL_LIBRARY_RELEASE
|
|
||||||
NAMES ${MySQL_NAMES}
|
|
||||||
PATHS ${MYSQL_ROOT}/lib /usr/lib /usr/local/lib /usr/lib64 /usr/local/lib64
|
|
||||||
PATH_SUFFIXES mysql
|
|
||||||
)
|
|
||||||
ELSE(MYSQL_ROOT)
|
|
||||||
FIND_LIBRARY(MySQL_LIBRARY_DEBUG
|
|
||||||
NAMES ${MySQL_NAMES}
|
|
||||||
PATHS /usr/lib /usr/local/lib /usr/lib64 /usr/local/lib64
|
|
||||||
PATH_SUFFIXES mysql
|
|
||||||
)
|
|
||||||
|
|
||||||
FIND_LIBRARY(MySQL_LIBRARY_RELEASE
|
|
||||||
NAMES ${MySQL_NAMES}
|
|
||||||
PATHS /usr/lib /usr/local/lib /usr/lib64 /usr/local/lib64
|
|
||||||
PATH_SUFFIXES mysql
|
|
||||||
)
|
|
||||||
ENDIF(MYSQL_ROOT)
|
|
||||||
|
|
||||||
IF (MySQL_INCLUDE_DIR AND MySQL_LIBRARY_DEBUG AND MySQL_LIBRARY_RELEASE)
|
|
||||||
SET(MySQL_FOUND TRUE)
|
|
||||||
SET( MySQL_LIBRARIES ${MySQL_LIBRARY_DEBUG} ${MySQL_LIBRARY_RELEASE} )
|
|
||||||
ELSE (MySQL_INCLUDE_DIR AND MySQL_LIBRARY_DEBUG AND MySQL_LIBRARY_RELEASE)
|
|
||||||
SET(MySQL_FOUND FALSE)
|
|
||||||
SET( MySQL_LIBRARIES )
|
|
||||||
ENDIF (MySQL_INCLUDE_DIR AND MySQL_LIBRARY_DEBUG AND MySQL_LIBRARY_RELEASE)
|
|
||||||
|
|
||||||
|
|
||||||
# handle the QUIETLY and REQUIRED arguments and set MySQL_FOUND to TRUE if
|
|
||||||
# all listed variables are TRUE
|
|
||||||
INCLUDE(FindPackageHandleStandardArgs)
|
|
||||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(MySQL DEFAULT_MSG MySQL_LIBRARY_DEBUG MySQL_LIBRARY_RELEASE MySQL_INCLUDE_DIR)
|
|
||||||
|
|
||||||
IF(MySQL_FOUND)
|
|
||||||
SET( MySQL_LIBRARIES ${MySQL_LIBRARY_DEBUG} ${MySQL_LIBRARY_RELEASE} )
|
|
||||||
ELSE(MySQL_FOUND)
|
|
||||||
SET( MySQL_LIBRARIES )
|
|
||||||
ENDIF(MySQL_FOUND)
|
|
||||||
|
|
||||||
MARK_AS_ADVANCED(
|
|
||||||
MySQL_LIBRARY_DEBUG
|
|
||||||
MySQL_LIBRARY_RELEASE
|
|
||||||
MySQL_INCLUDE_DIR
|
|
||||||
)
|
|
||||||
@@ -1,126 +0,0 @@
|
|||||||
/* EQEMu: Everquest Server Emulator
|
|
||||||
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
|
|
||||||
|
|
||||||
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; version 2 of the License.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
||||||
are required to give you total support for your newly bought product;
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
#include "debug.h"
|
|
||||||
#include "BasePacket.h"
|
|
||||||
#include "misc.h"
|
|
||||||
#include "packet_dump.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
BasePacket::BasePacket(const unsigned char *buf, uint32 len)
|
|
||||||
{
|
|
||||||
this->pBuffer=nullptr;
|
|
||||||
this->size=0;
|
|
||||||
this->_wpos = 0;
|
|
||||||
this->_rpos = 0;
|
|
||||||
this->timestamp.tv_sec = 0;
|
|
||||||
if (len>0) {
|
|
||||||
this->size=len;
|
|
||||||
pBuffer= new unsigned char[len];
|
|
||||||
if (buf) {
|
|
||||||
memcpy(this->pBuffer,buf,len);
|
|
||||||
} else {
|
|
||||||
memset(this->pBuffer,0,len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BasePacket::~BasePacket()
|
|
||||||
{
|
|
||||||
if (pBuffer)
|
|
||||||
delete[] pBuffer;
|
|
||||||
pBuffer=nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void BasePacket::build_raw_header_dump(char *buffer, uint16 seq) const
|
|
||||||
{
|
|
||||||
if (timestamp.tv_sec) {
|
|
||||||
char temp[20];
|
|
||||||
strftime(temp,20,"%F %T",localtime((const time_t *)×tamp.tv_sec));
|
|
||||||
buffer += sprintf(buffer, "%s.%06lu ",temp,timestamp.tv_usec);
|
|
||||||
}
|
|
||||||
if (src_ip) {
|
|
||||||
std::string sIP,dIP;;
|
|
||||||
sIP=long2ip(src_ip);
|
|
||||||
dIP=long2ip(dst_ip);
|
|
||||||
buffer += sprintf(buffer, "[%s:%d->%s:%d]\n",sIP.c_str(),src_port,dIP.c_str(),dst_port);
|
|
||||||
}
|
|
||||||
if (seq != 0xffff)
|
|
||||||
buffer += sprintf(buffer, "[Seq=%u] ",seq);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BasePacket::DumpRawHeader(uint16 seq, FILE *to) const
|
|
||||||
{
|
|
||||||
char buff[128];
|
|
||||||
build_raw_header_dump(buff, seq);
|
|
||||||
fprintf(to, "%s", buff);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BasePacket::build_header_dump(char *buffer) const
|
|
||||||
{
|
|
||||||
sprintf(buffer, "[packet]\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void BasePacket::DumpRawHeaderNoTime(uint16 seq, FILE *to) const
|
|
||||||
{
|
|
||||||
if (src_ip) {
|
|
||||||
std::string sIP,dIP;;
|
|
||||||
sIP=long2ip(src_ip);
|
|
||||||
dIP=long2ip(dst_ip);
|
|
||||||
fprintf(to, "[%s:%d->%s:%d] ",sIP.c_str(),src_port,dIP.c_str(),dst_port);
|
|
||||||
}
|
|
||||||
if (seq != 0xffff)
|
|
||||||
fprintf(to, "[Seq=%u] ",seq);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BasePacket::DumpRaw(FILE *to) const
|
|
||||||
{
|
|
||||||
DumpRawHeader();
|
|
||||||
if (pBuffer && size)
|
|
||||||
dump_message_column(pBuffer, size, " ", to);
|
|
||||||
fprintf(to, "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void BasePacket::ReadString(char *str, uint32 Offset, uint32 MaxLength) const
|
|
||||||
{
|
|
||||||
uint32 i = 0, j = Offset;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
str[i++] = pBuffer[j++];
|
|
||||||
}
|
|
||||||
while((j < size) && (i < MaxLength) && (str[i - 1] != 0));
|
|
||||||
|
|
||||||
str[i - 1] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
void DumpPacketHex(const BasePacket* app)
|
|
||||||
{
|
|
||||||
DumpPacketHex(app->pBuffer, app->size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DumpPacketAscii(const BasePacket* app)
|
|
||||||
{
|
|
||||||
DumpPacketAscii(app->pBuffer, app->size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DumpPacketBin(const BasePacket* app) {
|
|
||||||
DumpPacketBin(app->pBuffer, app->size);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
/* EQEMu: Everquest Server Emulator
|
|
||||||
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
|
|
||||||
|
|
||||||
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; version 2 of the License.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
||||||
are required to give you total support for your newly bought product;
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
#ifndef BASEPACKET_H_
|
|
||||||
#define BASEPACKET_H_
|
|
||||||
|
|
||||||
#include "types.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
#include <time.h>
|
|
||||||
#include <windows.h>
|
|
||||||
#include <winsock2.h>
|
|
||||||
#else
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class BasePacket {
|
|
||||||
public:
|
|
||||||
unsigned char *pBuffer;
|
|
||||||
uint32 size, _wpos, _rpos;
|
|
||||||
uint32 src_ip,dst_ip;
|
|
||||||
uint16 src_port,dst_port;
|
|
||||||
uint32 priority;
|
|
||||||
timeval timestamp;
|
|
||||||
|
|
||||||
virtual void build_raw_header_dump(char *buffer, uint16 seq=0xffff) const;
|
|
||||||
virtual void build_header_dump(char *buffer) const;
|
|
||||||
virtual void DumpRawHeader(uint16 seq=0xffff, FILE *to = stdout) const;
|
|
||||||
virtual void DumpRawHeaderNoTime(uint16 seq=0xffff, FILE *to = stdout) const;
|
|
||||||
void DumpRaw(FILE *to = stdout) const;
|
|
||||||
|
|
||||||
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 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));
|
|
||||||
}
|
|
||||||
|
|
||||||
void WriteUInt8(uint8 value) { *(uint8 *)(pBuffer + _wpos) = value; _wpos += sizeof(uint8); }
|
|
||||||
void WriteUInt32(uint32 value) { *(uint32 *)(pBuffer + _wpos) = value; _wpos += sizeof(uint32); }
|
|
||||||
void WriteUInt64(uint64 value) { *(uint64 *)(pBuffer + _wpos) = value; _wpos += sizeof(uint64); }
|
|
||||||
void WriteUInt16(uint32 value) { *(uint16 *)(pBuffer + _wpos) = value; _wpos += sizeof(uint16); }
|
|
||||||
void WriteSInt32(int32 value) { *(int32 *)(pBuffer + _wpos) = value; _wpos += sizeof(int32); }
|
|
||||||
void WriteFloat(float value) { *(float *)(pBuffer + _wpos) = value; _wpos += sizeof(float); }
|
|
||||||
void WriteDouble(double value) { *(double *)(pBuffer + _wpos) = value; _wpos += sizeof(double); }
|
|
||||||
void WriteString(const char * str) { uint32 len = static_cast<uint32>(strlen(str)) + 1; memcpy(pBuffer + _wpos, str, len); _wpos += len; }
|
|
||||||
|
|
||||||
uint8 ReadUInt8() { uint8 value = *(uint8 *)(pBuffer + _rpos); _rpos += sizeof(uint8); return value; }
|
|
||||||
uint8 ReadUInt8(uint32 Offset) const { uint8 value = *(uint8 *)(pBuffer + Offset); return value; }
|
|
||||||
uint32 ReadUInt32() { uint32 value = *(uint32 *)(pBuffer + _rpos); _rpos += sizeof(uint32); return value; }
|
|
||||||
uint32 ReadUInt32(uint32 Offset) const { uint32 value = *(uint32 *)(pBuffer + Offset); return value; }
|
|
||||||
void ReadString(char *str) { uint32 len = static_cast<uint32>(strlen((char *)(pBuffer + _rpos))) + 1; memcpy(str, pBuffer + _rpos, len); _rpos += len; }
|
|
||||||
void ReadString(char *str, uint32 Offset, uint32 MaxLength) const;
|
|
||||||
|
|
||||||
uint32 GetWritePosition() { return _wpos; }
|
|
||||||
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);
|
|
||||||
};
|
|
||||||
|
|
||||||
extern void DumpPacketHex(const BasePacket* app);
|
|
||||||
extern void DumpPacketAscii(const BasePacket* app);
|
|
||||||
extern void DumpPacketBin(const BasePacket* app);
|
|
||||||
|
|
||||||
#endif /*BASEPACKET_H_*/
|
|
||||||
|
|
||||||
@@ -1,321 +0,0 @@
|
|||||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
|
|
||||||
|
|
||||||
SET(common_sources
|
|
||||||
BasePacket.cpp
|
|
||||||
classes.cpp
|
|
||||||
Condition.cpp
|
|
||||||
crash.cpp
|
|
||||||
CRC16.cpp
|
|
||||||
crc32.cpp
|
|
||||||
database.cpp
|
|
||||||
dbasync.cpp
|
|
||||||
dbcore.cpp
|
|
||||||
debug.cpp
|
|
||||||
emu_opcodes.cpp
|
|
||||||
EmuTCPConnection.cpp
|
|
||||||
EmuTCPServer.cpp
|
|
||||||
EQDB.cpp
|
|
||||||
EQDBRes.cpp
|
|
||||||
eqemu_exception.cpp
|
|
||||||
EQEmuConfig.cpp
|
|
||||||
EQEMuError.cpp
|
|
||||||
EQPacket.cpp
|
|
||||||
EQStream.cpp
|
|
||||||
EQStreamFactory.cpp
|
|
||||||
EQStreamIdent.cpp
|
|
||||||
EQStreamProxy.cpp
|
|
||||||
eqtime.cpp
|
|
||||||
extprofile.cpp
|
|
||||||
faction.cpp
|
|
||||||
guild_base.cpp
|
|
||||||
guilds.cpp
|
|
||||||
ipc_mutex.cpp
|
|
||||||
Item.cpp
|
|
||||||
logsys.cpp
|
|
||||||
logsys_eqemu.cpp
|
|
||||||
md5.cpp
|
|
||||||
memory_mapped_file.cpp
|
|
||||||
misc.cpp
|
|
||||||
MiscFunctions.cpp
|
|
||||||
moremath.cpp
|
|
||||||
Mutex.cpp
|
|
||||||
opcode_map.cpp
|
|
||||||
opcodemgr.cpp
|
|
||||||
packet_dump.cpp
|
|
||||||
packet_dump_file.cpp
|
|
||||||
packet_functions.cpp
|
|
||||||
perl_EQDB.cpp
|
|
||||||
perl_EQDBRes.cpp
|
|
||||||
ProcLauncher.cpp
|
|
||||||
ptimer.cpp
|
|
||||||
races.cpp
|
|
||||||
rdtsc.cpp
|
|
||||||
rulesys.cpp
|
|
||||||
serverinfo.cpp
|
|
||||||
shareddb.cpp
|
|
||||||
spdat.cpp
|
|
||||||
StringUtil.cpp
|
|
||||||
StructStrategy.cpp
|
|
||||||
TCPConnection.cpp
|
|
||||||
TCPServer.cpp
|
|
||||||
timeoutmgr.cpp
|
|
||||||
timer.cpp
|
|
||||||
unix.cpp
|
|
||||||
worldconn.cpp
|
|
||||||
XMLParser.cpp
|
|
||||||
platform.cpp
|
|
||||||
patches/Client62.cpp
|
|
||||||
patches/patches.cpp
|
|
||||||
patches/SoD.cpp
|
|
||||||
patches/SoF.cpp
|
|
||||||
patches/RoF.cpp
|
|
||||||
patches/Titanium.cpp
|
|
||||||
patches/Underfoot.cpp
|
|
||||||
SocketLib/Base64.cpp
|
|
||||||
SocketLib/File.cpp
|
|
||||||
SocketLib/HttpdCookies.cpp
|
|
||||||
SocketLib/HttpdForm.cpp
|
|
||||||
SocketLib/HttpdSocket.cpp
|
|
||||||
SocketLib/HTTPSocket.cpp
|
|
||||||
SocketLib/MemFile.cpp
|
|
||||||
SocketLib/Mime.cpp
|
|
||||||
SocketLib/Parse.cpp
|
|
||||||
SocketLib/socket_include.cpp
|
|
||||||
SocketLib/Utility.cpp
|
|
||||||
StackWalker/StackWalker.cpp
|
|
||||||
tinyxml/tinystr.cpp
|
|
||||||
tinyxml/tinyxml.cpp
|
|
||||||
tinyxml/tinyxmlerror.cpp
|
|
||||||
tinyxml/tinyxmlparser.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
SET(common_headers
|
|
||||||
BasePacket.h
|
|
||||||
base_data.h
|
|
||||||
bodytypes.h
|
|
||||||
breakdowns.h
|
|
||||||
classes.h
|
|
||||||
Condition.h
|
|
||||||
crash.h
|
|
||||||
CRC16.h
|
|
||||||
crc32.h
|
|
||||||
database.h
|
|
||||||
dbasync.h
|
|
||||||
dbcore.h
|
|
||||||
debug.h
|
|
||||||
deity.h
|
|
||||||
emu_opcodes.h
|
|
||||||
emu_oplist.h
|
|
||||||
EmuTCPConnection.h
|
|
||||||
EmuTCPServer.h
|
|
||||||
eq_constants.h
|
|
||||||
eq_packet_structs.h
|
|
||||||
EQDB.h
|
|
||||||
EQDBRes.h
|
|
||||||
eqemu_exception.h
|
|
||||||
EQEmuConfig.h
|
|
||||||
EQEmuConfig_elements.h
|
|
||||||
EQEMuError.h
|
|
||||||
EQPacket.h
|
|
||||||
EQStream.h
|
|
||||||
EQStreamFactory.h
|
|
||||||
EQStreamIdent.h
|
|
||||||
EQStreamIntf.h
|
|
||||||
EQStreamLocator.h
|
|
||||||
EQStreamProxy.h
|
|
||||||
EQStreamType.h
|
|
||||||
eqtime.h
|
|
||||||
errmsg.h
|
|
||||||
extprofile.h
|
|
||||||
faction.h
|
|
||||||
features.h
|
|
||||||
fixed_memory_hash_set.h
|
|
||||||
fixed_memory_variable_hash_set.h
|
|
||||||
guild_base.h
|
|
||||||
guilds.h
|
|
||||||
ipc_mutex.h
|
|
||||||
Item.h
|
|
||||||
item_fieldlist.h
|
|
||||||
item_struct.h
|
|
||||||
languages.h
|
|
||||||
linked_list.h
|
|
||||||
logsys.h
|
|
||||||
logtypes.h
|
|
||||||
loottable.h
|
|
||||||
mail_oplist.h
|
|
||||||
md5.h
|
|
||||||
memory_mapped_file.h
|
|
||||||
misc.h
|
|
||||||
MiscFunctions.h
|
|
||||||
moremath.h
|
|
||||||
Mutex.h
|
|
||||||
op_codes.h
|
|
||||||
opcode_dispatch.h
|
|
||||||
opcodemgr.h
|
|
||||||
packet_dump.h
|
|
||||||
packet_dump_file.h
|
|
||||||
packet_functions.h
|
|
||||||
ProcLauncher.h
|
|
||||||
profiler.h
|
|
||||||
ptimer.h
|
|
||||||
queue.h
|
|
||||||
races.h
|
|
||||||
rdtsc.h
|
|
||||||
rulesys.h
|
|
||||||
ruletypes.h
|
|
||||||
seperator.h
|
|
||||||
serverinfo.h
|
|
||||||
servertalk.h
|
|
||||||
shareddb.h
|
|
||||||
skills.h
|
|
||||||
spdat.h
|
|
||||||
StringUtil.h
|
|
||||||
StructStrategy.h
|
|
||||||
TCPBasicServer.h
|
|
||||||
TCPConnection.h
|
|
||||||
TCPServer.h
|
|
||||||
timeoutmgr.h
|
|
||||||
timer.h
|
|
||||||
types.h
|
|
||||||
unix.h
|
|
||||||
useperl.h
|
|
||||||
version.h
|
|
||||||
worldconn.h
|
|
||||||
XMLParser.h
|
|
||||||
ZoneNumbers.h
|
|
||||||
platform.h
|
|
||||||
patches/Client62.h
|
|
||||||
patches/Client62_itemfields.h
|
|
||||||
patches/Client62_ops.h
|
|
||||||
patches/Client62_structs.h
|
|
||||||
patches/patches.h
|
|
||||||
patches/SoD.h
|
|
||||||
patches/SoD_itemfields.h
|
|
||||||
patches/SoD_ops.h
|
|
||||||
patches/SoD_structs.h
|
|
||||||
patches/SoF.h
|
|
||||||
patches/SoF_itemfields.h
|
|
||||||
patches/SoF_opcode_list.h
|
|
||||||
patches/SoF_ops.h
|
|
||||||
patches/SoF_structs.h
|
|
||||||
patches/SSDeclare.h
|
|
||||||
patches/SSDefine.h
|
|
||||||
patches/SSRegister.h
|
|
||||||
patches/RoF.h
|
|
||||||
patches/RoF_itemfields.h
|
|
||||||
patches/RoF_ops.h
|
|
||||||
patches/RoF_structs.h
|
|
||||||
patches/Titanium.h
|
|
||||||
patches/Titanium_itemfields.h
|
|
||||||
patches/Titanium_ops.h
|
|
||||||
patches/Titanium_structs.h
|
|
||||||
patches/Underfoot.h
|
|
||||||
patches/Underfoot_itemfields.h
|
|
||||||
patches/Underfoot_ops.h
|
|
||||||
patches/Underfoot_structs.h
|
|
||||||
SocketLib/Base64.h
|
|
||||||
SocketLib/File.h
|
|
||||||
SocketLib/HttpdCookies.h
|
|
||||||
SocketLib/HttpdForm.h
|
|
||||||
SocketLib/HttpdSocket.h
|
|
||||||
SocketLib/HTTPSocket.h
|
|
||||||
SocketLib/IFile.h
|
|
||||||
SocketLib/MemFile.h
|
|
||||||
SocketLib/Mime.h
|
|
||||||
SocketLib/Parse.h
|
|
||||||
SocketLib/socket_include.h
|
|
||||||
SocketLib/Utility.h
|
|
||||||
StackWalker/StackWalker.h
|
|
||||||
tinyxml/tinystr.h
|
|
||||||
tinyxml/tinyxml.h
|
|
||||||
)
|
|
||||||
|
|
||||||
SOURCE_GROUP(Patches FILES
|
|
||||||
patches/Client62.h
|
|
||||||
patches/Client62_itemfields.h
|
|
||||||
patches/Client62_ops.h
|
|
||||||
patches/Client62_structs.h
|
|
||||||
patches/patches.h
|
|
||||||
patches/SoD.h
|
|
||||||
patches/SoD_itemfields.h
|
|
||||||
patches/SoD_ops.h
|
|
||||||
patches/SoD_structs.h
|
|
||||||
patches/SoF.h
|
|
||||||
patches/SoF_itemfields.h
|
|
||||||
patches/SoF_opcode_list.h
|
|
||||||
patches/SoF_ops.h
|
|
||||||
patches/SoF_structs.h
|
|
||||||
patches/SSDeclare.h
|
|
||||||
patches/SSDefine.h
|
|
||||||
patches/SSRegister.h
|
|
||||||
patches/RoF.h
|
|
||||||
patches/RoF_itemfields.h
|
|
||||||
patches/RoF_ops.h
|
|
||||||
patches/RoF_structs.h
|
|
||||||
patches/Titanium.h
|
|
||||||
patches/Titanium_itemfields.h
|
|
||||||
patches/Titanium_ops.h
|
|
||||||
patches/Titanium_structs.h
|
|
||||||
patches/Underfoot.h
|
|
||||||
patches/Underfoot_itemfields.h
|
|
||||||
patches/Underfoot_ops.h
|
|
||||||
patches/Underfoot_structs.h
|
|
||||||
patches/Client62.cpp
|
|
||||||
patches/patches.cpp
|
|
||||||
patches/SoD.cpp
|
|
||||||
patches/SoF.cpp
|
|
||||||
patches/RoF.cpp
|
|
||||||
patches/Titanium.cpp
|
|
||||||
patches/Underfoot.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
SOURCE_GROUP(SocketLib FILES
|
|
||||||
SocketLib/Base64.h
|
|
||||||
SocketLib/File.h
|
|
||||||
SocketLib/HttpdCookies.h
|
|
||||||
SocketLib/HttpdForm.h
|
|
||||||
SocketLib/HttpdSocket.h
|
|
||||||
SocketLib/HTTPSocket.h
|
|
||||||
SocketLib/IFile.h
|
|
||||||
SocketLib/MemFile.h
|
|
||||||
SocketLib/Mime.h
|
|
||||||
SocketLib/Parse.h
|
|
||||||
SocketLib/socket_include.h
|
|
||||||
SocketLib/Utility.h
|
|
||||||
SocketLib/Base64.cpp
|
|
||||||
SocketLib/File.cpp
|
|
||||||
SocketLib/HttpdCookies.cpp
|
|
||||||
SocketLib/HttpdForm.cpp
|
|
||||||
SocketLib/HttpdSocket.cpp
|
|
||||||
SocketLib/HTTPSocket.cpp
|
|
||||||
SocketLib/MemFile.cpp
|
|
||||||
SocketLib/Mime.cpp
|
|
||||||
SocketLib/Parse.cpp
|
|
||||||
SocketLib/socket_include.cpp
|
|
||||||
SocketLib/Utility.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
SOURCE_GROUP(StackWalker FILES
|
|
||||||
StackWalker/StackWalker.h
|
|
||||||
StackWalker/StackWalker.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
SOURCE_GROUP(TinyXML FILES
|
|
||||||
tinyxml/tinystr.h
|
|
||||||
tinyxml/tinyxml.h
|
|
||||||
tinyxml/tinystr.cpp
|
|
||||||
tinyxml/tinyxml.cpp
|
|
||||||
tinyxml/tinyxmlerror.cpp
|
|
||||||
tinyxml/tinyxmlparser.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
INCLUDE_DIRECTORIES(Patches SocketLib StackWalker TinyXML)
|
|
||||||
|
|
||||||
ADD_LIBRARY(Common ${common_sources} ${common_headers})
|
|
||||||
|
|
||||||
IF(UNIX)
|
|
||||||
ADD_DEFINITIONS(-fPIC)
|
|
||||||
SET_SOURCE_FILES_PROPERTIES("patches/SoD.cpp" "patches/SoF.cpp" "patches/RoF.cpp" "patches/Underfoot.cpp" PROPERTIES COMPILE_FLAGS -O0)
|
|
||||||
ENDIF(UNIX)
|
|
||||||
|
|
||||||
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/Bin)
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
#include "crc32.h"
|
|
||||||
|
|
||||||
uint16 CRC16(const unsigned char *buf, int size, int key)
|
|
||||||
{
|
|
||||||
// This is computed as the lowest 16 bits of an Ethernet CRC32 checksum
|
|
||||||
// where the key is prepended to the data in little endian order.
|
|
||||||
uint8 keyBuf[] = {(uint8)((key >> 0) & 0xff),
|
|
||||||
(uint8)((key >> 8) & 0xff),
|
|
||||||
(uint8)((key >> 16) & 0xff),
|
|
||||||
(uint8)((key >> 24) & 0xff)};
|
|
||||||
uint32 crc = CRC32::Update(keyBuf, sizeof(uint32));
|
|
||||||
crc = CRC32::Update(buf, size, crc);
|
|
||||||
return CRC32::Finish(crc) & 0xffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
#ifndef _CRC16_H
|
|
||||||
#define _CRC16_H
|
|
||||||
#include "types.h"
|
|
||||||
|
|
||||||
uint16 CRC16(const unsigned char *buf, int size, int key);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,148 +0,0 @@
|
|||||||
/* EQEMu: Everquest Server Emulator
|
|
||||||
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
|
|
||||||
|
|
||||||
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; version 2 of the License.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
||||||
are required to give you total support for your newly bought product;
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "debug.h"
|
|
||||||
#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,56 +0,0 @@
|
|||||||
/* EQEMu: Everquest Server Emulator
|
|
||||||
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
|
|
||||||
|
|
||||||
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; version 2 of the License.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
||||||
are required to give you total support for your newly bought product;
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
#ifndef __CONDITION_H
|
|
||||||
#define __CONDITION_H
|
|
||||||
|
|
||||||
#include "debug.h"
|
|
||||||
#ifndef WIN32
|
|
||||||
#include <pthread.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//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();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
/* EQEMu: Everquest Server Emulator
|
|
||||||
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
|
|
||||||
|
|
||||||
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; version 2 of the License.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
||||||
are required to give you total support for your newly bought product;
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
#include "debug.h"
|
|
||||||
#include "EQDB.h"
|
|
||||||
#include "database.h"
|
|
||||||
#include <mysql.h>
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
EQDB EQDB::s_EQDB;
|
|
||||||
|
|
||||||
EQDB::EQDB() {
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int EQDB::field_count() {
|
|
||||||
return mysql_field_count(mysql_ref);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long EQDB::affected_rows() {
|
|
||||||
return mysql_affected_rows(mysql_ref);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long EQDB::insert_id() {
|
|
||||||
return mysql_insert_id(mysql_ref);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int EQDB::get_errno() {
|
|
||||||
return mysql_errno(mysql_ref);
|
|
||||||
}
|
|
||||||
|
|
||||||
Const_char * EQDB::error() {
|
|
||||||
return mysql_error(mysql_ref);
|
|
||||||
}
|
|
||||||
|
|
||||||
EQDBRes * EQDB::query(Const_char *q) {
|
|
||||||
if (mysql_real_query(mysql_ref,q,strlen(q))==0) {
|
|
||||||
if (mysql_field_count(mysql_ref)) {
|
|
||||||
MYSQL_RES *r=mysql_store_result(mysql_ref);
|
|
||||||
return new EQDBRes(r);
|
|
||||||
} else {
|
|
||||||
//no result, give them back a 'true but empty' result set
|
|
||||||
return(new EQDBRes(nullptr));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
//NOT THREAD SAFE!
|
|
||||||
Const_char *EQDB::escape_string(Const_char *from) {
|
|
||||||
int len = strlen(from);
|
|
||||||
char *res = new char[len*2+1];
|
|
||||||
|
|
||||||
mysql_real_escape_string(mysql_ref,res,from,len);
|
|
||||||
|
|
||||||
res[len*2] = '\0';
|
|
||||||
m_escapeBuffer = res;
|
|
||||||
delete[] res;
|
|
||||||
return(m_escapeBuffer.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
/* EQEMu: Everquest Server Emulator
|
|
||||||
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
|
|
||||||
|
|
||||||
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; version 2 of the License.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
||||||
are required to give you total support for your newly bought product;
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
#ifndef EQDB_H_
|
|
||||||
#define EQDB_H_
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <map>
|
|
||||||
#include "types.h"
|
|
||||||
#include "EQDBRes.h"
|
|
||||||
#include <mysql.h>
|
|
||||||
|
|
||||||
//this is the main object exported to perl.
|
|
||||||
class EQDB {
|
|
||||||
EQDB();
|
|
||||||
public:
|
|
||||||
static EQDB *Singleton() { return(&s_EQDB); }
|
|
||||||
|
|
||||||
static void SetMySQL(MYSQL *m) { s_EQDB.mysql_ref=m; }
|
|
||||||
|
|
||||||
//BEGIN PERL EXPORT
|
|
||||||
//NOTE: you must have a space after the * of a return value
|
|
||||||
|
|
||||||
unsigned int field_count();
|
|
||||||
unsigned long affected_rows();
|
|
||||||
unsigned long insert_id();
|
|
||||||
unsigned int get_errno();
|
|
||||||
Const_char * error();
|
|
||||||
EQDBRes * query(Const_char *q);
|
|
||||||
Const_char * escape_string(Const_char *from); //NOT THREAD SAFE! (m_escapeBuffer)
|
|
||||||
//END PERL EXPORT
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string m_escapeBuffer;
|
|
||||||
static EQDB s_EQDB;
|
|
||||||
MYSQL *mysql_ref;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /*EQDB_H_*/
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
/* EQEMu: Everquest Server Emulator
|
|
||||||
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
|
|
||||||
|
|
||||||
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; version 2 of the License.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
||||||
are required to give you total support for your newly bought product;
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
#include "debug.h"
|
|
||||||
#include "EQDBRes.h"
|
|
||||||
#include <mysql.h>
|
|
||||||
|
|
||||||
std::vector<std::string> EQDBRes::fetch_row_array() {
|
|
||||||
std::vector<std::string> array;
|
|
||||||
if(res == nullptr)
|
|
||||||
return(array);
|
|
||||||
|
|
||||||
int count=mysql_num_fields(res);
|
|
||||||
MYSQL_ROW row=mysql_fetch_row(res);
|
|
||||||
for (int i=0;i<count;i++)
|
|
||||||
array.push_back(row[i]);
|
|
||||||
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::map<std::string,std::string> EQDBRes::fetch_row_hash() {
|
|
||||||
std::map<std::string,std::string> rowhash;
|
|
||||||
if(res == nullptr)
|
|
||||||
return(rowhash);
|
|
||||||
|
|
||||||
MYSQL_FIELD *fields;
|
|
||||||
MYSQL_ROW row;
|
|
||||||
unsigned long num_fields,i;
|
|
||||||
|
|
||||||
if (res && (num_fields=mysql_num_fields(res)) && (row = mysql_fetch_row(res))!=nullptr && (fields = mysql_fetch_fields(res))!=nullptr) {
|
|
||||||
for(i=0;i<num_fields;i++) {
|
|
||||||
rowhash[fields[i].name]=(row[i] ? row[i] : "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rowhash;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
/* EQEMu: Everquest Server Emulator
|
|
||||||
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
|
|
||||||
|
|
||||||
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; version 2 of the License.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
||||||
are required to give you total support for your newly bought product;
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
#ifndef EQDBRes_H_
|
|
||||||
#define EQDBRes_H_
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <map>
|
|
||||||
#include "types.h"
|
|
||||||
#include "database.h"
|
|
||||||
#include <mysql.h>
|
|
||||||
|
|
||||||
//this is the main object exported to perl.
|
|
||||||
class EQDBRes {
|
|
||||||
public:
|
|
||||||
EQDBRes(MYSQL_RES *r) { res=r; }
|
|
||||||
~EQDBRes() { finish(); }
|
|
||||||
|
|
||||||
//BEGIN PERL EXPORT
|
|
||||||
unsigned long num_rows() { return (res) ? mysql_num_rows(res) : 0; }
|
|
||||||
unsigned long num_fields() { return (res) ? mysql_num_fields(res) : 0; }
|
|
||||||
void DESTROY() { }
|
|
||||||
void finish() { if (res) mysql_free_result(res); res=nullptr; };
|
|
||||||
std::vector<std::string> fetch_row_array();
|
|
||||||
std::map<std::string,std::string> fetch_row_hash();
|
|
||||||
unsigned long * fetch_lengths() { return (res) ? mysql_fetch_lengths(res) : 0; }
|
|
||||||
//END PERL EXPORT
|
|
||||||
|
|
||||||
private:
|
|
||||||
MYSQL_RES *res;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /*EQDBRes_H_*/
|
|
||||||
@@ -1,135 +0,0 @@
|
|||||||
/* EQEMu: Everquest Server Emulator
|
|
||||||
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
|
|
||||||
|
|
||||||
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; version 2 of the License.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
||||||
are required to give you total support for your newly bought product;
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
#include <windows.h>
|
|
||||||
#endif
|
|
||||||
#include "EQEMuError.h"
|
|
||||||
#include "linked_list.h"
|
|
||||||
#include "Mutex.h"
|
|
||||||
#include "MiscFunctions.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
#include <conio.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void UpdateWindowTitle(char* iNewTitle = 0);
|
|
||||||
void CatchSignal(int sig_num);
|
|
||||||
|
|
||||||
const char* EQEMuErrorText[EQEMuError_MaxErrorID] = { "ErrorID# 0, No Error",
|
|
||||||
"MySQL Error #1405 or #2001 means your mysql server rejected the username and password you presented it.",
|
|
||||||
"MySQL Error #2003 means you were unable to connect to the mysql server.",
|
|
||||||
"MySQL Error #2005 means you there are too many connections on the mysql server. The server is overloaded.",
|
|
||||||
"MySQL Error #2007 means you the server is out of memory. The server is overloaded.",
|
|
||||||
};
|
|
||||||
|
|
||||||
LinkedList<char*>* EQEMuErrorList;
|
|
||||||
Mutex* MEQEMuErrorList;
|
|
||||||
AutoDelete< LinkedList<char*> > ADEQEMuErrorList(&EQEMuErrorList);
|
|
||||||
AutoDelete<Mutex> ADMEQEMuErrorList(&MEQEMuErrorList);
|
|
||||||
|
|
||||||
const char* GetErrorText(uint32 iError) {
|
|
||||||
if (iError >= EQEMuError_MaxErrorID)
|
|
||||||
return "ErrorID# out of range";
|
|
||||||
else
|
|
||||||
return EQEMuErrorText[iError];
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddEQEMuError(eEQEMuError iError, bool iExitNow) {
|
|
||||||
if (!iError)
|
|
||||||
return;
|
|
||||||
if (!EQEMuErrorList) {
|
|
||||||
EQEMuErrorList = new LinkedList<char*>;
|
|
||||||
MEQEMuErrorList = new Mutex;
|
|
||||||
}
|
|
||||||
LockMutex lock(MEQEMuErrorList);
|
|
||||||
|
|
||||||
LinkedListIterator<char*> iterator(*EQEMuErrorList);
|
|
||||||
iterator.Reset();
|
|
||||||
while (iterator.MoreElements()) {
|
|
||||||
if (iterator.GetData()[0] == 1) {
|
|
||||||
//Umm... this gets a big WTF...
|
|
||||||
// if (*((uint32*) iterator.GetData()[1]) == iError)
|
|
||||||
//not sure whats going on, using a character as a pointer....
|
|
||||||
if (*((eEQEMuError*) &(iterator.GetData()[1])) == iError)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
iterator.Advance();
|
|
||||||
}
|
|
||||||
|
|
||||||
char* tmp = new char[6];
|
|
||||||
tmp[0] = 1;
|
|
||||||
tmp[5] = 0;
|
|
||||||
*((uint32*) &tmp[1]) = iError;
|
|
||||||
EQEMuErrorList->Append(tmp);
|
|
||||||
|
|
||||||
if (iExitNow)
|
|
||||||
CatchSignal(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddEQEMuError(char* iError, bool iExitNow) {
|
|
||||||
if (!iError)
|
|
||||||
return;
|
|
||||||
if (!EQEMuErrorList) {
|
|
||||||
EQEMuErrorList = new LinkedList<char*>;
|
|
||||||
MEQEMuErrorList = new Mutex;
|
|
||||||
}
|
|
||||||
LockMutex lock(MEQEMuErrorList);
|
|
||||||
char* tmp = strcpy(new char[strlen(iError) + 1], iError);
|
|
||||||
EQEMuErrorList->Append(tmp);
|
|
||||||
|
|
||||||
if (iExitNow)
|
|
||||||
CatchSignal(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 CheckEQEMuError() {
|
|
||||||
if (!EQEMuErrorList)
|
|
||||||
return 0;
|
|
||||||
uint32 ret = 0;
|
|
||||||
char* tmp = 0;
|
|
||||||
bool HeaderPrinted = false;
|
|
||||||
LockMutex lock(MEQEMuErrorList);
|
|
||||||
|
|
||||||
while ((tmp = EQEMuErrorList->Pop() )) {
|
|
||||||
if (!HeaderPrinted) {
|
|
||||||
fprintf(stdout, "===============================\nRuntime errors:\n\n");
|
|
||||||
HeaderPrinted = true;
|
|
||||||
}
|
|
||||||
if (tmp[0] == 1) {
|
|
||||||
fprintf(stdout, "%s\n", GetErrorText(*((uint32*) &tmp[1])));
|
|
||||||
fprintf(stdout, "For more information on this error, visit http://www.eqemu.net/eqemuerror.php?id=%u\n\n", *((uint32*) &tmp[1]));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
fprintf(stdout, "%s\n\n", tmp);
|
|
||||||
}
|
|
||||||
safe_delete(tmp);
|
|
||||||
ret++;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CheckEQEMuErrorAndPause() {
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
if (CheckEQEMuError()) {
|
|
||||||
fprintf(stdout, "Hit any key to exit\n");
|
|
||||||
UpdateWindowTitle("Error");
|
|
||||||
getch();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
/* EQEMu: Everquest Server Emulator
|
|
||||||
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
|
|
||||||
|
|
||||||
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; version 2 of the License.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
||||||
are required to give you total support for your newly bought product;
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
#ifndef EQEMuError_H
|
|
||||||
#define EQEMuError_H
|
|
||||||
|
|
||||||
#include "../common/types.h"
|
|
||||||
|
|
||||||
enum eEQEMuError { EQEMuError_NoError,
|
|
||||||
EQEMuError_Mysql_1405,
|
|
||||||
EQEMuError_Mysql_2003,
|
|
||||||
EQEMuError_Mysql_2005,
|
|
||||||
EQEMuError_Mysql_2007,
|
|
||||||
EQEMuError_MaxErrorID };
|
|
||||||
|
|
||||||
void AddEQEMuError(eEQEMuError iError, bool iExitNow = false);
|
|
||||||
void AddEQEMuError(char* iError, bool iExitNow = false);
|
|
||||||
uint32 CheckEQEMuError();
|
|
||||||
void CheckEQEMuErrorAndPause();
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@@ -1,448 +0,0 @@
|
|||||||
/* EQEMu: Everquest Server Emulator
|
|
||||||
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
|
|
||||||
|
|
||||||
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; version 2 of the License.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
||||||
are required to give you total support for your newly bought product;
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
#include "../common/debug.h"
|
|
||||||
#include "EQEmuConfig.h"
|
|
||||||
#include "MiscFunctions.h"
|
|
||||||
#include <iostream>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
std::string EQEmuConfig::ConfigFile = "eqemu_config.xml";
|
|
||||||
EQEmuConfig *EQEmuConfig::_config = nullptr;
|
|
||||||
|
|
||||||
void EQEmuConfig::do_world(TiXmlElement *ele) {
|
|
||||||
const char *text;
|
|
||||||
TiXmlElement * sub_ele;;
|
|
||||||
|
|
||||||
text= ParseTextBlock(ele,"shortname");
|
|
||||||
if (text)
|
|
||||||
ShortName=text;
|
|
||||||
|
|
||||||
text = ParseTextBlock(ele,"longname");
|
|
||||||
if (text)
|
|
||||||
LongName=text;
|
|
||||||
|
|
||||||
text = ParseTextBlock(ele,"address",true);
|
|
||||||
if (text)
|
|
||||||
WorldAddress=text;
|
|
||||||
|
|
||||||
text = ParseTextBlock(ele,"localaddress",true);
|
|
||||||
if (text)
|
|
||||||
LocalAddress=text;
|
|
||||||
|
|
||||||
text = ParseTextBlock(ele,"maxclients",true);
|
|
||||||
if (text)
|
|
||||||
MaxClients=atoi(text);
|
|
||||||
|
|
||||||
// Get the <key> element
|
|
||||||
text = ParseTextBlock(ele,"key",true);
|
|
||||||
if (text)
|
|
||||||
SharedKey=text;
|
|
||||||
|
|
||||||
// Get the <loginserver> element
|
|
||||||
sub_ele = ele->FirstChildElement("loginserver");
|
|
||||||
if (sub_ele) {
|
|
||||||
text=ParseTextBlock(sub_ele,"host",true);
|
|
||||||
if (text)
|
|
||||||
LoginHost=text;
|
|
||||||
|
|
||||||
text=ParseTextBlock(sub_ele,"port",true);
|
|
||||||
if (text)
|
|
||||||
LoginPort=atoi(text);
|
|
||||||
|
|
||||||
text=ParseTextBlock(sub_ele,"account",true);
|
|
||||||
if (text)
|
|
||||||
LoginAccount=text;
|
|
||||||
|
|
||||||
text=ParseTextBlock(sub_ele,"password",true);
|
|
||||||
if (text)
|
|
||||||
LoginPassword=text;
|
|
||||||
} else {
|
|
||||||
char str[32];
|
|
||||||
do {
|
|
||||||
sprintf(str, "loginserver%i", ++LoginCount);
|
|
||||||
sub_ele = ele->FirstChildElement(str);
|
|
||||||
if (sub_ele) {
|
|
||||||
LoginConfig* loginconfig = new LoginConfig;
|
|
||||||
text=ParseTextBlock(sub_ele,"host",true);
|
|
||||||
if (text)
|
|
||||||
loginconfig->LoginHost=text;
|
|
||||||
|
|
||||||
text=ParseTextBlock(sub_ele,"port",true);
|
|
||||||
if (text)
|
|
||||||
loginconfig->LoginPort=atoi(text);
|
|
||||||
|
|
||||||
text=ParseTextBlock(sub_ele,"account",true);
|
|
||||||
if (text)
|
|
||||||
loginconfig->LoginAccount=text;
|
|
||||||
|
|
||||||
text=ParseTextBlock(sub_ele,"password",true);
|
|
||||||
if (text)
|
|
||||||
loginconfig->LoginPassword=text;
|
|
||||||
loginlist.Insert(loginconfig);
|
|
||||||
}
|
|
||||||
} while(sub_ele);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for locked
|
|
||||||
sub_ele = ele->FirstChildElement("locked");
|
|
||||||
if (sub_ele != nullptr)
|
|
||||||
Locked=true;
|
|
||||||
|
|
||||||
// Get the <tcp> element
|
|
||||||
sub_ele = ele->FirstChildElement("tcp");
|
|
||||||
if(sub_ele != nullptr) {
|
|
||||||
|
|
||||||
text = sub_ele->Attribute("ip");
|
|
||||||
if (text)
|
|
||||||
WorldIP=text;
|
|
||||||
|
|
||||||
text = sub_ele->Attribute("port");
|
|
||||||
if (text)
|
|
||||||
WorldTCPPort=atoi(text);
|
|
||||||
|
|
||||||
text = sub_ele->Attribute("telnet");
|
|
||||||
if (text && !strcasecmp(text,"enabled"))
|
|
||||||
TelnetEnabled=true;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the <http> element
|
|
||||||
sub_ele = ele->FirstChildElement("http");
|
|
||||||
if(sub_ele != nullptr) {
|
|
||||||
|
|
||||||
// text = sub_ele->Attribute("ip");
|
|
||||||
// if (text)
|
|
||||||
// WorldIP=text;
|
|
||||||
|
|
||||||
text = sub_ele->Attribute("mimefile");
|
|
||||||
if (text)
|
|
||||||
WorldHTTPMimeFile=text;
|
|
||||||
|
|
||||||
text = sub_ele->Attribute("port");
|
|
||||||
if (text)
|
|
||||||
WorldHTTPPort=atoi(text);
|
|
||||||
|
|
||||||
text = sub_ele->Attribute("enabled");
|
|
||||||
if (text && !strcasecmp(text,"true"))
|
|
||||||
WorldHTTPEnabled=true;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQEmuConfig::do_chatserver(TiXmlElement *ele) {
|
|
||||||
const char *text;
|
|
||||||
|
|
||||||
text=ParseTextBlock(ele,"host",true);
|
|
||||||
if (text)
|
|
||||||
ChatHost=text;
|
|
||||||
|
|
||||||
text=ParseTextBlock(ele,"port",true);
|
|
||||||
if (text)
|
|
||||||
ChatPort=atoi(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQEmuConfig::do_mailserver(TiXmlElement *ele) {
|
|
||||||
const char *text;
|
|
||||||
|
|
||||||
text=ParseTextBlock(ele,"host",true);
|
|
||||||
if (text)
|
|
||||||
MailHost=text;
|
|
||||||
|
|
||||||
text=ParseTextBlock(ele,"port",true);
|
|
||||||
if (text)
|
|
||||||
MailPort=atoi(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQEmuConfig::do_database(TiXmlElement *ele) {
|
|
||||||
const char *text;
|
|
||||||
|
|
||||||
text=ParseTextBlock(ele,"host",true);
|
|
||||||
if (text)
|
|
||||||
DatabaseHost=text;
|
|
||||||
|
|
||||||
text=ParseTextBlock(ele,"port",true);
|
|
||||||
if (text)
|
|
||||||
DatabasePort=atoi(text);
|
|
||||||
|
|
||||||
text=ParseTextBlock(ele,"username",true);
|
|
||||||
if (text)
|
|
||||||
DatabaseUsername=text;
|
|
||||||
|
|
||||||
text=ParseTextBlock(ele,"password",true);
|
|
||||||
if (text)
|
|
||||||
DatabasePassword=text;
|
|
||||||
|
|
||||||
text=ParseTextBlock(ele,"db",true);
|
|
||||||
if (text)
|
|
||||||
DatabaseDB=text;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void EQEmuConfig::do_qsdatabase(TiXmlElement *ele) {
|
|
||||||
const char *text;
|
|
||||||
|
|
||||||
text=ParseTextBlock(ele,"host",true);
|
|
||||||
if (text)
|
|
||||||
QSDatabaseHost=text;
|
|
||||||
|
|
||||||
text=ParseTextBlock(ele,"port",true);
|
|
||||||
if (text)
|
|
||||||
QSDatabasePort=atoi(text);
|
|
||||||
|
|
||||||
text=ParseTextBlock(ele,"username",true);
|
|
||||||
if (text)
|
|
||||||
QSDatabaseUsername=text;
|
|
||||||
|
|
||||||
text=ParseTextBlock(ele,"password",true);
|
|
||||||
if (text)
|
|
||||||
QSDatabasePassword=text;
|
|
||||||
|
|
||||||
text=ParseTextBlock(ele,"db",true);
|
|
||||||
if (text)
|
|
||||||
QSDatabaseDB=text;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQEmuConfig::do_zones(TiXmlElement *ele) {
|
|
||||||
const char *text;
|
|
||||||
TiXmlElement *sub_ele;
|
|
||||||
// TiXmlNode *node,*sub_node;
|
|
||||||
|
|
||||||
text=ParseTextBlock(ele,"defaultstatus",true);
|
|
||||||
if (text)
|
|
||||||
DefaultStatus=atoi(text);
|
|
||||||
|
|
||||||
// Get the <ports> element
|
|
||||||
sub_ele = ele->FirstChildElement("ports");
|
|
||||||
if(sub_ele != nullptr) {
|
|
||||||
|
|
||||||
text = sub_ele->Attribute("low");
|
|
||||||
if (text)
|
|
||||||
ZonePortLow=atoi(text);;
|
|
||||||
|
|
||||||
text = sub_ele->Attribute("high");
|
|
||||||
if (text)
|
|
||||||
ZonePortHigh=atoi(text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQEmuConfig::do_files(TiXmlElement *ele) {
|
|
||||||
const char *text;
|
|
||||||
|
|
||||||
text=ParseTextBlock(ele,"spells",true);
|
|
||||||
if (text)
|
|
||||||
SpellsFile=text;
|
|
||||||
|
|
||||||
text=ParseTextBlock(ele,"opcodes",true);
|
|
||||||
if (text)
|
|
||||||
OpCodesFile=text;
|
|
||||||
|
|
||||||
text=ParseTextBlock(ele,"logsettings",true);
|
|
||||||
if (text)
|
|
||||||
LogSettingsFile=text;
|
|
||||||
|
|
||||||
text=ParseTextBlock(ele,"eqtime",true);
|
|
||||||
if (text)
|
|
||||||
EQTimeFile=text;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQEmuConfig::do_directories(TiXmlElement *ele) {
|
|
||||||
const char *text;
|
|
||||||
|
|
||||||
text=ParseTextBlock(ele,"maps",true);
|
|
||||||
if (text)
|
|
||||||
MapDir=text;
|
|
||||||
|
|
||||||
text=ParseTextBlock(ele,"quests",true);
|
|
||||||
if (text)
|
|
||||||
QuestDir=text;
|
|
||||||
|
|
||||||
text=ParseTextBlock(ele,"plugins",true);
|
|
||||||
if (text)
|
|
||||||
PluginDir=text;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQEmuConfig::do_launcher(TiXmlElement *ele) {
|
|
||||||
const char *text;
|
|
||||||
TiXmlElement *sub_ele;
|
|
||||||
|
|
||||||
text=ParseTextBlock(ele,"logprefix",true);
|
|
||||||
if (text)
|
|
||||||
LogPrefix = text;
|
|
||||||
|
|
||||||
text=ParseTextBlock(ele,"logsuffix",true);
|
|
||||||
if (text)
|
|
||||||
LogSuffix = text;
|
|
||||||
|
|
||||||
// Get the <exe> element
|
|
||||||
text = ParseTextBlock(ele,"exe",true);
|
|
||||||
if (text)
|
|
||||||
ZoneExe = text;
|
|
||||||
|
|
||||||
// Get the <timers> element
|
|
||||||
sub_ele = ele->FirstChildElement("timers");
|
|
||||||
if(sub_ele != nullptr) {
|
|
||||||
text = sub_ele->Attribute("restart");
|
|
||||||
if (text)
|
|
||||||
RestartWait = atoi(text);
|
|
||||||
|
|
||||||
text = sub_ele->Attribute("reterminate");
|
|
||||||
if (text)
|
|
||||||
TerminateWait = atoi(text);
|
|
||||||
|
|
||||||
text = sub_ele->Attribute("initial");
|
|
||||||
if (text)
|
|
||||||
InitialBootWait = atoi(text);
|
|
||||||
|
|
||||||
text = sub_ele->Attribute("interval");
|
|
||||||
if (text)
|
|
||||||
ZoneBootInterval = atoi(text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string EQEmuConfig::GetByName(const std::string &var_name) const {
|
|
||||||
if(var_name == "ShortName")
|
|
||||||
return(ShortName);
|
|
||||||
if(var_name == "LongName")
|
|
||||||
return(LongName);
|
|
||||||
if(var_name == "WorldAddress")
|
|
||||||
return(WorldAddress);
|
|
||||||
if(var_name == "LoginHost")
|
|
||||||
return(LoginHost);
|
|
||||||
if(var_name == "LoginAccount")
|
|
||||||
return(LoginAccount);
|
|
||||||
if(var_name == "LoginPassword")
|
|
||||||
return(LoginPassword);
|
|
||||||
if(var_name == "LoginPort")
|
|
||||||
return(itoa(LoginPort));
|
|
||||||
if(var_name == "Locked")
|
|
||||||
return(Locked?"true":"false");
|
|
||||||
if(var_name == "WorldTCPPort")
|
|
||||||
return(itoa(WorldTCPPort));
|
|
||||||
if(var_name == "WorldIP")
|
|
||||||
return(WorldIP);
|
|
||||||
if(var_name == "TelnetEnabled")
|
|
||||||
return(TelnetEnabled?"true":"false");
|
|
||||||
if(var_name == "WorldHTTPPort")
|
|
||||||
return(itoa(WorldHTTPPort));
|
|
||||||
if(var_name == "WorldHTTPMimeFile")
|
|
||||||
return(WorldHTTPMimeFile);
|
|
||||||
if(var_name == "WorldHTTPEnabled")
|
|
||||||
return(WorldHTTPEnabled?"true":"false");
|
|
||||||
if(var_name == "ChatHost")
|
|
||||||
return(ChatHost);
|
|
||||||
if(var_name == "ChatPort")
|
|
||||||
return(itoa(ChatPort));
|
|
||||||
if(var_name == "MailHost")
|
|
||||||
return(MailHost);
|
|
||||||
if(var_name == "MailPort")
|
|
||||||
return(itoa(MailPort));
|
|
||||||
if(var_name == "DatabaseHost")
|
|
||||||
return(DatabaseHost);
|
|
||||||
if(var_name == "DatabaseUsername")
|
|
||||||
return(DatabaseUsername);
|
|
||||||
if(var_name == "DatabasePassword")
|
|
||||||
return(DatabasePassword);
|
|
||||||
if(var_name == "DatabaseDB")
|
|
||||||
return(DatabaseDB);
|
|
||||||
if(var_name == "DatabasePort")
|
|
||||||
return(itoa(DatabasePort));
|
|
||||||
if(var_name == "QSDatabaseHost")
|
|
||||||
return(QSDatabaseHost);
|
|
||||||
if(var_name == "QSDatabaseUsername")
|
|
||||||
return(QSDatabaseUsername);
|
|
||||||
if(var_name == "QSDatabasePassword")
|
|
||||||
return(QSDatabasePassword);
|
|
||||||
if(var_name == "QSDatabaseDB")
|
|
||||||
return(QSDatabaseDB);
|
|
||||||
if(var_name == "QSDatabasePort")
|
|
||||||
return(itoa(QSDatabasePort));
|
|
||||||
if(var_name == "SpellsFile")
|
|
||||||
return(SpellsFile);
|
|
||||||
if(var_name == "OpCodesFile")
|
|
||||||
return(OpCodesFile);
|
|
||||||
if(var_name == "EQTimeFile")
|
|
||||||
return(EQTimeFile);
|
|
||||||
if(var_name == "LogSettingsFile")
|
|
||||||
return(LogSettingsFile);
|
|
||||||
if(var_name == "MapDir")
|
|
||||||
return(MapDir);
|
|
||||||
if(var_name == "QuestDir")
|
|
||||||
return(QuestDir);
|
|
||||||
if(var_name == "PluginDir")
|
|
||||||
return(PluginDir);
|
|
||||||
if(var_name == "LogPrefix")
|
|
||||||
return(LogPrefix);
|
|
||||||
if(var_name == "LogSuffix")
|
|
||||||
return(LogSuffix);
|
|
||||||
if(var_name == "ZoneExe")
|
|
||||||
return(ZoneExe);
|
|
||||||
if(var_name == "ZonePortLow")
|
|
||||||
return(itoa(ZonePortLow));
|
|
||||||
if(var_name == "ZonePortHigh")
|
|
||||||
return(itoa(ZonePortHigh));
|
|
||||||
if(var_name == "DefaultStatus")
|
|
||||||
return(itoa(DefaultStatus));
|
|
||||||
// if(var_name == "DynamicCount")
|
|
||||||
// return(itoa(DynamicCount));
|
|
||||||
return("");
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQEmuConfig::Dump() const
|
|
||||||
{
|
|
||||||
std::cout << "ShortName = " << ShortName << std::endl;
|
|
||||||
std::cout << "LongName = " << LongName << std::endl;
|
|
||||||
std::cout << "WorldAddress = " << WorldAddress << std::endl;
|
|
||||||
std::cout << "LoginHost = " << LoginHost << std::endl;
|
|
||||||
std::cout << "LoginAccount = " << LoginAccount << std::endl;
|
|
||||||
std::cout << "LoginPassword = " << LoginPassword << std::endl;
|
|
||||||
std::cout << "LoginPort = " << LoginPort << std::endl;
|
|
||||||
std::cout << "Locked = " << Locked << std::endl;
|
|
||||||
std::cout << "WorldTCPPort = " << WorldTCPPort << std::endl;
|
|
||||||
std::cout << "WorldIP = " << WorldIP << std::endl;
|
|
||||||
std::cout << "TelnetEnabled = " << TelnetEnabled << std::endl;
|
|
||||||
std::cout << "WorldHTTPPort = " << WorldHTTPPort << std::endl;
|
|
||||||
std::cout << "WorldHTTPMimeFile = " << WorldHTTPMimeFile << std::endl;
|
|
||||||
std::cout << "WorldHTTPEnabled = " << WorldHTTPEnabled << std::endl;
|
|
||||||
std::cout << "ChatHost = " << ChatHost << std::endl;
|
|
||||||
std::cout << "ChatPort = " << ChatPort << std::endl;
|
|
||||||
std::cout << "MailHost = " << MailHost << std::endl;
|
|
||||||
std::cout << "MailPort = " << MailPort << std::endl;
|
|
||||||
std::cout << "DatabaseHost = " << DatabaseHost << std::endl;
|
|
||||||
std::cout << "DatabaseUsername = " << DatabaseUsername << std::endl;
|
|
||||||
std::cout << "DatabasePassword = " << DatabasePassword << std::endl;
|
|
||||||
std::cout << "DatabaseDB = " << DatabaseDB << std::endl;
|
|
||||||
std::cout << "DatabasePort = " << DatabasePort << std::endl;
|
|
||||||
std::cout << "QSDatabaseHost = " << QSDatabaseHost << std::endl;
|
|
||||||
std::cout << "QSDatabaseUsername = " << QSDatabaseUsername << std::endl;
|
|
||||||
std::cout << "QSDatabasePassword = " << QSDatabasePassword << std::endl;
|
|
||||||
std::cout << "QSDatabaseDB = " << QSDatabaseDB << std::endl;
|
|
||||||
std::cout << "QSDatabasePort = " << QSDatabasePort << std::endl;
|
|
||||||
std::cout << "SpellsFile = " << SpellsFile << std::endl;
|
|
||||||
std::cout << "OpCodesFile = " << OpCodesFile << std::endl;
|
|
||||||
std::cout << "EQTimeFile = " << EQTimeFile << std::endl;
|
|
||||||
std::cout << "LogSettingsFile = " << LogSettingsFile << std::endl;
|
|
||||||
std::cout << "MapDir = " << MapDir << std::endl;
|
|
||||||
std::cout << "QuestDir = " << QuestDir << std::endl;
|
|
||||||
std::cout << "PluginDir = " << PluginDir << std::endl;
|
|
||||||
std::cout << "ZonePortLow = " << ZonePortLow << std::endl;
|
|
||||||
std::cout << "ZonePortHigh = " << ZonePortHigh << std::endl;
|
|
||||||
std::cout << "DefaultStatus = " << (int)DefaultStatus << std::endl;
|
|
||||||
// std::cout << "DynamicCount = " << DynamicCount << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,227 +0,0 @@
|
|||||||
/* EQEMu: Everquest Server Emulator
|
|
||||||
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
|
|
||||||
|
|
||||||
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; version 2 of the License.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
||||||
are required to give you total support for your newly bought product;
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
#ifndef __EQEmuConfig_H
|
|
||||||
#define __EQEmuConfig_H
|
|
||||||
|
|
||||||
#include "XMLParser.h"
|
|
||||||
#include "linked_list.h"
|
|
||||||
|
|
||||||
struct LoginConfig {
|
|
||||||
std::string LoginHost;
|
|
||||||
std::string LoginAccount;
|
|
||||||
std::string LoginPassword;
|
|
||||||
uint16 LoginPort;
|
|
||||||
};
|
|
||||||
|
|
||||||
class EQEmuConfig : public XMLParser {
|
|
||||||
public:
|
|
||||||
virtual std::string GetByName(const std::string &var_name) const;
|
|
||||||
|
|
||||||
// From <world/>
|
|
||||||
std::string ShortName;
|
|
||||||
std::string LongName;
|
|
||||||
std::string WorldAddress;
|
|
||||||
std::string LocalAddress;
|
|
||||||
std::string LoginHost;
|
|
||||||
std::string LoginAccount;
|
|
||||||
std::string LoginPassword;
|
|
||||||
uint16 LoginPort;
|
|
||||||
uint32 LoginCount;
|
|
||||||
LinkedList<LoginConfig*> loginlist;
|
|
||||||
bool Locked;
|
|
||||||
uint16 WorldTCPPort;
|
|
||||||
std::string WorldIP;
|
|
||||||
bool TelnetEnabled;
|
|
||||||
int32 MaxClients;
|
|
||||||
bool WorldHTTPEnabled;
|
|
||||||
uint16 WorldHTTPPort;
|
|
||||||
std::string WorldHTTPMimeFile;
|
|
||||||
std::string SharedKey;
|
|
||||||
|
|
||||||
// From <chatserver/>
|
|
||||||
std::string ChatHost;
|
|
||||||
uint16 ChatPort;
|
|
||||||
|
|
||||||
// From <mailserver/>
|
|
||||||
std::string MailHost;
|
|
||||||
uint16 MailPort;
|
|
||||||
|
|
||||||
// From <database/>
|
|
||||||
std::string DatabaseHost;
|
|
||||||
std::string DatabaseUsername;
|
|
||||||
std::string DatabasePassword;
|
|
||||||
std::string DatabaseDB;
|
|
||||||
uint16 DatabasePort;
|
|
||||||
|
|
||||||
// From <qsdatabase> // QueryServ
|
|
||||||
std::string QSDatabaseHost;
|
|
||||||
std::string QSDatabaseUsername;
|
|
||||||
std::string QSDatabasePassword;
|
|
||||||
std::string QSDatabaseDB;
|
|
||||||
uint16 QSDatabasePort;
|
|
||||||
|
|
||||||
// From <files/>
|
|
||||||
std::string SpellsFile;
|
|
||||||
std::string OpCodesFile;
|
|
||||||
std::string EQTimeFile;
|
|
||||||
std::string LogSettingsFile;
|
|
||||||
|
|
||||||
// From <directories/>
|
|
||||||
std::string MapDir;
|
|
||||||
std::string QuestDir;
|
|
||||||
std::string PluginDir;
|
|
||||||
|
|
||||||
// From <launcher/>
|
|
||||||
std::string LogPrefix;
|
|
||||||
std::string LogSuffix;
|
|
||||||
std::string ZoneExe;
|
|
||||||
uint32 RestartWait;
|
|
||||||
uint32 TerminateWait;
|
|
||||||
uint32 InitialBootWait;
|
|
||||||
uint32 ZoneBootInterval;
|
|
||||||
|
|
||||||
// From <zones/>
|
|
||||||
uint16 ZonePortLow;
|
|
||||||
uint16 ZonePortHigh;
|
|
||||||
uint8 DefaultStatus;
|
|
||||||
|
|
||||||
// uint16 DynamicCount;
|
|
||||||
|
|
||||||
// map<string,uint16> StaticZones;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
static EQEmuConfig *_config;
|
|
||||||
|
|
||||||
static std::string ConfigFile;
|
|
||||||
|
|
||||||
#define ELEMENT(name) \
|
|
||||||
void do_##name(TiXmlElement *ele);
|
|
||||||
#include "EQEmuConfig_elements.h"
|
|
||||||
|
|
||||||
|
|
||||||
EQEmuConfig() {
|
|
||||||
// import the needed handler prototypes
|
|
||||||
#define ELEMENT(name) \
|
|
||||||
Handlers[#name]=(ElementHandler)&EQEmuConfig::do_##name;
|
|
||||||
#include "EQEmuConfig_elements.h"
|
|
||||||
|
|
||||||
// Set sane defaults
|
|
||||||
|
|
||||||
// Login server
|
|
||||||
LoginHost="eqemulator.net";
|
|
||||||
LoginPort=5998;
|
|
||||||
|
|
||||||
// World
|
|
||||||
Locked=false;
|
|
||||||
WorldTCPPort=9000;
|
|
||||||
TelnetEnabled=false;
|
|
||||||
WorldHTTPEnabled=false;
|
|
||||||
WorldHTTPPort=9080;
|
|
||||||
WorldHTTPMimeFile="mime.types";
|
|
||||||
SharedKey = ""; //blank disables authentication
|
|
||||||
|
|
||||||
// Mail
|
|
||||||
ChatHost="eqchat.eqemulator.net";
|
|
||||||
ChatPort=7778;
|
|
||||||
|
|
||||||
// Mail
|
|
||||||
MailHost="eqmail.eqemulator.net";
|
|
||||||
MailPort=7779;
|
|
||||||
|
|
||||||
// Mysql
|
|
||||||
DatabaseHost="localhost";
|
|
||||||
DatabasePort=3306;
|
|
||||||
DatabaseUsername="eq";
|
|
||||||
DatabasePassword="eq";
|
|
||||||
DatabaseDB="eq";
|
|
||||||
|
|
||||||
// QueryServ Database
|
|
||||||
QSDatabaseHost="localhost";
|
|
||||||
QSDatabasePort=3306;
|
|
||||||
QSDatabaseUsername="eq";
|
|
||||||
QSDatabasePassword="eq";
|
|
||||||
QSDatabaseDB="eq";
|
|
||||||
|
|
||||||
// Files
|
|
||||||
SpellsFile="spells_us.txt";
|
|
||||||
OpCodesFile="opcodes.conf";
|
|
||||||
EQTimeFile="eqtime.cfg";
|
|
||||||
LogSettingsFile="log.ini";
|
|
||||||
|
|
||||||
// Dirs
|
|
||||||
MapDir="Maps";
|
|
||||||
QuestDir="quests";
|
|
||||||
PluginDir="plugins";
|
|
||||||
|
|
||||||
// Launcher
|
|
||||||
LogPrefix = "logs/zone-";
|
|
||||||
LogSuffix = ".log";
|
|
||||||
RestartWait = 10000; //milliseconds
|
|
||||||
TerminateWait = 10000; //milliseconds
|
|
||||||
InitialBootWait = 20000; //milliseconds
|
|
||||||
ZoneBootInterval = 2000; //milliseconds
|
|
||||||
#ifdef WIN32
|
|
||||||
ZoneExe = "zone.exe";
|
|
||||||
#else
|
|
||||||
ZoneExe = "./zone";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Zones
|
|
||||||
ZonePortLow=7000;
|
|
||||||
ZonePortHigh=7999;
|
|
||||||
DefaultStatus=0;
|
|
||||||
|
|
||||||
// For where zones need to connect to.
|
|
||||||
WorldIP="127.0.0.1";
|
|
||||||
|
|
||||||
// Dynamics to start
|
|
||||||
//DynamicCount=5;
|
|
||||||
|
|
||||||
MaxClients=-1;
|
|
||||||
|
|
||||||
LoginCount=0;
|
|
||||||
|
|
||||||
}
|
|
||||||
virtual ~EQEmuConfig() {}
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
// Produce a const singleton
|
|
||||||
static const EQEmuConfig *get() {
|
|
||||||
if (_config == nullptr)
|
|
||||||
LoadConfig();
|
|
||||||
return(_config);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allow the use to set the conf file to be used.
|
|
||||||
static void SetConfigFile(std::string file) { EQEmuConfig::ConfigFile = file; }
|
|
||||||
|
|
||||||
// Load the config
|
|
||||||
static bool LoadConfig() {
|
|
||||||
if (_config != nullptr)
|
|
||||||
delete _config;
|
|
||||||
_config=new EQEmuConfig;
|
|
||||||
|
|
||||||
return _config->ParseFile(EQEmuConfig::ConfigFile.c_str(),"server");
|
|
||||||
}
|
|
||||||
|
|
||||||
void Dump() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
ELEMENT(world)
|
|
||||||
ELEMENT(chatserver)
|
|
||||||
ELEMENT(mailserver)
|
|
||||||
ELEMENT(zones)
|
|
||||||
ELEMENT(database)
|
|
||||||
ELEMENT(qsdatabase)
|
|
||||||
ELEMENT(files)
|
|
||||||
ELEMENT(directories)
|
|
||||||
ELEMENT(launcher)
|
|
||||||
|
|
||||||
#undef ELEMENT
|
|
||||||
@@ -1,405 +0,0 @@
|
|||||||
/* EQEMu: Everquest Server Emulator
|
|
||||||
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
|
||||||
|
|
||||||
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; version 2 of the License.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
||||||
are required to give you total support for your newly bought product;
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* EQStream classes, by Quagmire
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "../common/debug.h"
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <iomanip>
|
|
||||||
#ifdef WIN32
|
|
||||||
#include <process.h>
|
|
||||||
#else
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
#include "../common/unix.h"
|
|
||||||
#define SOCKET_ERROR -1
|
|
||||||
#endif
|
|
||||||
#include "EQNetwork.h"
|
|
||||||
#include "EQStream.h"
|
|
||||||
#include "../common/packet_dump.h"
|
|
||||||
#include "../common/packet_dump_file.h"
|
|
||||||
#include "../common/packet_functions.h"
|
|
||||||
#include "../common/MiscFunctions.h"
|
|
||||||
#include "../common/crc32.h"
|
|
||||||
#include "../common/eq_packet_structs.h"
|
|
||||||
|
|
||||||
#define EQN_DEBUG 0
|
|
||||||
#define EQN_DEBUG_Error 0
|
|
||||||
#define EQN_DEBUG_Packet 0
|
|
||||||
#define EQN_DEBUG_Fragment 0
|
|
||||||
#define EQN_DEBUG_ACK 0
|
|
||||||
#define EQN_DEBUG_Unknown 0
|
|
||||||
#define EQN_DEBUG_NewStream 0
|
|
||||||
#define LOG_PACKETS 0
|
|
||||||
#define LOG_RAW_PACKETS_OUT 0
|
|
||||||
#define LOG_RAW_PACKETS_IN 0
|
|
||||||
//#define PRIORITYTEST
|
|
||||||
|
|
||||||
template <typename type> // LO_BYTE
|
|
||||||
type LO_BYTE (type a) {return (a&=0xff);}
|
|
||||||
template <typename type> // HI_BYTE
|
|
||||||
type HI_BYTE (type a) {return (a&=0xff00);}
|
|
||||||
template <typename type> // LO_WORD
|
|
||||||
type LO_WORD (type a) {return (a&=0xffff);}
|
|
||||||
template <typename type> // HI_WORD
|
|
||||||
type HI_WORD (type a) {return (a&=0xffff0000);}
|
|
||||||
template <typename type> // HI_LOSWAPshort
|
|
||||||
type HI_LOSWAPshort (type a) {return (LO_BYTE(a)<<8) | (HI_BYTE(a)>>8);}
|
|
||||||
template <typename type> // HI_LOSWAPlong
|
|
||||||
type HI_LOSWAPlong (type x) {return (LO_WORD(a)<<16) | (HIWORD(a)>>16);}
|
|
||||||
|
|
||||||
EQStreamServer::EQStreamServer(uint16 iPort) {
|
|
||||||
RunLoop = false;
|
|
||||||
pPort = iPort;
|
|
||||||
pOpen = false;
|
|
||||||
#ifdef WIN32
|
|
||||||
WORD version = MAKEWORD (1,1);
|
|
||||||
WSADATA wsadata;
|
|
||||||
WSAStartup (version, &wsadata);
|
|
||||||
#endif
|
|
||||||
sock = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
EQStreamServer::~EQStreamServer() {
|
|
||||||
Close();
|
|
||||||
RunLoop = false;
|
|
||||||
MLoopRunning.lock();
|
|
||||||
MLoopRunning.unlock();
|
|
||||||
#ifdef WIN32
|
|
||||||
WSACleanup();
|
|
||||||
#endif
|
|
||||||
connection_list.clear();
|
|
||||||
while (!NewQueue.empty())
|
|
||||||
NewQueue.pop(); // they're deleted with the list, clear this queue so it doesnt try to delete them again
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EQStreamServer::Open(uint16 iPort) {
|
|
||||||
LockMutex lock(&MOpen);
|
|
||||||
if (iPort && pPort != iPort) {
|
|
||||||
if (pOpen)
|
|
||||||
return false;
|
|
||||||
pPort = iPort;
|
|
||||||
}
|
|
||||||
if (!RunLoop) {
|
|
||||||
RunLoop = true;
|
|
||||||
#ifdef WIN32
|
|
||||||
_beginthread(EQStreamServerLoop, 0, this);
|
|
||||||
#else
|
|
||||||
pthread_t thread;
|
|
||||||
pthread_create(&thread, NULL, &EQStreamServerLoop, this);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
if (pOpen) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
struct sockaddr_in address;
|
|
||||||
// int reuse_addr = 1;
|
|
||||||
int bufsize = 64 * 1024; // 64kbyte send/recieve buffers, up from default of 8k
|
|
||||||
#ifdef WIN32
|
|
||||||
unsigned long nonblocking = 1;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Setup internet address information.
|
|
||||||
This is used with the bind() call */
|
|
||||||
memset((char *) &address, 0, sizeof(address));
|
|
||||||
address.sin_family = AF_INET;
|
|
||||||
address.sin_port = htons(pPort);
|
|
||||||
address.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
||||||
|
|
||||||
/* Setting up UDP port for new clients */
|
|
||||||
sock = socket(AF_INET, SOCK_DGRAM, 0);
|
|
||||||
if (sock < 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//#ifdef WIN32
|
|
||||||
// setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse_addr, sizeof(reuse_addr));
|
|
||||||
setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*) &bufsize, sizeof(bufsize));
|
|
||||||
setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char*) &bufsize, sizeof(bufsize));
|
|
||||||
//#else
|
|
||||||
// setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr));
|
|
||||||
// setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(bufsize));
|
|
||||||
// setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize));
|
|
||||||
//#endif
|
|
||||||
|
|
||||||
if (bind(sock, (struct sockaddr *) &address, sizeof(address)) < 0) {
|
|
||||||
#ifdef WIN32
|
|
||||||
closesocket(sock);
|
|
||||||
#else
|
|
||||||
close(sock);
|
|
||||||
#endif
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
ioctlsocket (sock, FIONBIO, &nonblocking);
|
|
||||||
#else
|
|
||||||
fcntl(sock, F_SETFL, O_NONBLOCK);
|
|
||||||
#endif
|
|
||||||
pOpen = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQStreamServer::Close() {
|
|
||||||
SetOpen(false);
|
|
||||||
if (sock) {
|
|
||||||
#ifdef WIN32
|
|
||||||
closesocket(sock);
|
|
||||||
#else
|
|
||||||
close(sock);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
sock = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EQStreamServer::IsOpen() {
|
|
||||||
MOpen.lock();
|
|
||||||
bool ret = pOpen;
|
|
||||||
MOpen.unlock();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQStreamServer::SetOpen(bool iOpen) {
|
|
||||||
MOpen.lock();
|
|
||||||
pOpen = iOpen;
|
|
||||||
MOpen.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQStreamServer::Process() {
|
|
||||||
_CP(EQStreamServer_Process);
|
|
||||||
if (!IsOpen()) {
|
|
||||||
if (sock) {
|
|
||||||
#ifdef WIN32
|
|
||||||
closesocket(sock);
|
|
||||||
#else
|
|
||||||
close(sock);
|
|
||||||
#endif
|
|
||||||
sock = 0;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uchar buffer[1518];
|
|
||||||
|
|
||||||
int status;
|
|
||||||
struct sockaddr_in from;
|
|
||||||
unsigned int fromlen;
|
|
||||||
|
|
||||||
from.sin_family = AF_INET;
|
|
||||||
fromlen = sizeof(from);
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
#ifdef WIN32
|
|
||||||
status = recvfrom(sock, (char *) buffer, sizeof(buffer), 0,(struct sockaddr*) &from, (int *) &fromlen);
|
|
||||||
#else
|
|
||||||
status = recvfrom(sock, buffer, sizeof(buffer), 0,(struct sockaddr*) &from, &fromlen);
|
|
||||||
#endif
|
|
||||||
if (status >= 1) {
|
|
||||||
cout << "Got data from recvfrom" << endl;
|
|
||||||
RecvData(buffer, status, from.sin_addr.s_addr, from.sin_port);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::map <std::string, EQStream*>::iterator connection;
|
|
||||||
for (connection = connection_list.begin(); connection != connection_list.end();) {
|
|
||||||
if (!connection->second) {
|
|
||||||
connection = connection_list.erase(connection);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
EQStream* eqs_data = connection->second;
|
|
||||||
if (eqs_data->IsFree() && (!eqs_data->CheckNetActive())) {
|
|
||||||
safe_delete(eqs_data);
|
|
||||||
connection = connection_list.erase(connection);
|
|
||||||
} else if (!eqs_data->RunLoop) {
|
|
||||||
eqs_data->Process(sock);
|
|
||||||
++connection;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQStreamServer::RecvData(uchar* data, uint32 size, uint32 irIP, uint16 irPort) {
|
|
||||||
/*
|
|
||||||
CHANGE HISTORY
|
|
||||||
|
|
||||||
Version Author Date Comment
|
|
||||||
1 Unknown Unknown Initial Revision
|
|
||||||
2 Joolz 05-Jan-2003 Optimised
|
|
||||||
3 Quagmire 05-Feb-2003 Changed so 2 connection objects wouldnt be created for the same ip/port pair, often happened
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Check for invalid data
|
|
||||||
if (!data || size <= 4) return;
|
|
||||||
//if (CRC32::Generate(data, size-4) != ntohl(*((uint32*) &data[size-4]))) {
|
|
||||||
#if EQN_DEBUG_Error >= 1
|
|
||||||
//cout << "Incomming Packet failed checksum" << endl;
|
|
||||||
#endif
|
|
||||||
//return;
|
|
||||||
//}
|
|
||||||
|
|
||||||
char temp[25];
|
|
||||||
sprintf(temp,"%lu:%u",(unsigned long)irIP,irPort);
|
|
||||||
cout << "Data from " << temp << endl;
|
|
||||||
EQStream* tmp = NULL;
|
|
||||||
std::map <std::string, EQStream*>::iterator connection;
|
|
||||||
if ((connection=connection_list.find(temp))!=connection_list.end())
|
|
||||||
tmp=connection->second;
|
|
||||||
if(tmp != NULL && tmp->GetrPort() == irPort)
|
|
||||||
{
|
|
||||||
tmp->RecvData(data, size);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if(tmp != NULL && tmp->GetrPort() != irPort)
|
|
||||||
{
|
|
||||||
printf("Conflicting IPs & Ports: IP %i and Port %i is conflicting with IP %i and Port %i\n",irIP,irPort,tmp->GetrIP(),tmp->GetrPort());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data[1]==0x01) {
|
|
||||||
cout << "New EQStream Connection." << endl;
|
|
||||||
EQStream* tmp = new EQStream(irIP, irPort);
|
|
||||||
tmp->RecvData(data, size);
|
|
||||||
connection_list[temp]=tmp;
|
|
||||||
if (connection_list.find(temp)==connection_list.end()) {
|
|
||||||
cerr <<"Could not find new connection we just added!" << endl;
|
|
||||||
}
|
|
||||||
MNewQueue.lock();
|
|
||||||
NewQueue.push(tmp);
|
|
||||||
MNewQueue.unlock();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#if EQN_DEBUG >= 4
|
|
||||||
struct in_addr in;
|
|
||||||
in.s_addr = irIP;
|
|
||||||
cout << "WARNING: Stray packet? " << inet_ntoa(in) << ":" << irPort << endl;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
EQStream* EQStreamServer::NewQueuePop() {
|
|
||||||
EQStream* ret = 0;
|
|
||||||
MNewQueue.lock();
|
|
||||||
if (!NewQueue.empty()) {
|
|
||||||
ret = NewQueue.front();
|
|
||||||
NewQueue.pop();
|
|
||||||
}
|
|
||||||
MNewQueue.unlock();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
void EQStreamServerLoop(void* tmp)
|
|
||||||
#else
|
|
||||||
void* EQStreamServerLoop(void* tmp)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
#ifdef WIN32
|
|
||||||
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
|
|
||||||
#endif
|
|
||||||
EQStreamServer* eqns = (EQStreamServer*) tmp;
|
|
||||||
eqns->MLoopRunning.lock();
|
|
||||||
while (eqns->RunLoop) {
|
|
||||||
{
|
|
||||||
_CP(EQStreamServerLoop);
|
|
||||||
eqns->Process();
|
|
||||||
}
|
|
||||||
Sleep(1);
|
|
||||||
}
|
|
||||||
eqns->MLoopRunning.unlock();
|
|
||||||
#ifdef WIN32
|
|
||||||
_endthread();
|
|
||||||
#else
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
void EQStreamInLoop(void* tmp)
|
|
||||||
#else
|
|
||||||
void* EQStreamInLoop(void* tmp)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
EQStream* eqs = (EQStream*) tmp;
|
|
||||||
#ifdef _DEBUG
|
|
||||||
if (eqs->ConnectionType != Outgoing) {
|
|
||||||
ThrowError("EQStreamInLoop: eqs->ConnectionType != Outgoing");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
eqs->MLoopRunning.lock();
|
|
||||||
Timer* tmp_timer = new Timer(100);
|
|
||||||
tmp_timer->Start();
|
|
||||||
while (eqs->RunLoop) {
|
|
||||||
{
|
|
||||||
_CP(EQStreamInLoop);
|
|
||||||
if(tmp_timer->Check())
|
|
||||||
eqs->DoRecvData();
|
|
||||||
}
|
|
||||||
Sleep(1);
|
|
||||||
}
|
|
||||||
safe_delete(tmp_timer);
|
|
||||||
eqs->MLoopRunning.unlock();
|
|
||||||
#ifdef WIN32
|
|
||||||
_endthread();
|
|
||||||
#else
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
void EQStreamOutLoop(void* tmp)
|
|
||||||
#else
|
|
||||||
void* EQStreamOutLoop(void* tmp)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
EQStream* eqs = (EQStream*) tmp;
|
|
||||||
#ifdef _DEBUG
|
|
||||||
if (eqs->ConnectionType != Outgoing) {
|
|
||||||
ThrowError("EQStreamOutLoop: eqs->ConnectionType != Outgoing");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
eqs->MLoopRunning.lock();
|
|
||||||
Timer* tmp_timer = new Timer(100);
|
|
||||||
tmp_timer->Start();
|
|
||||||
while (eqs->RunLoop) {
|
|
||||||
{
|
|
||||||
_CP(EQStreamOutLoop);
|
|
||||||
if(tmp_timer->Check())
|
|
||||||
eqs->Process(eqs->outsock);
|
|
||||||
}
|
|
||||||
Sleep(1);
|
|
||||||
}
|
|
||||||
safe_delete(tmp_timer);
|
|
||||||
eqs->MLoopRunning.unlock();
|
|
||||||
#ifdef WIN32
|
|
||||||
_endthread();
|
|
||||||
#else
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
/* EQEMu: Everquest Server Emulator
|
|
||||||
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
|
||||||
|
|
||||||
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; version 2 of the License.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
||||||
are required to give you total support for your newly bought product;
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
#ifndef EQNETWORK_H
|
|
||||||
#define EQNETWORK_H
|
|
||||||
|
|
||||||
#include "../common/debug.h"
|
|
||||||
|
|
||||||
//uncomment this to enable the packet profiler. Counts the number
|
|
||||||
//of each type of packet sent or received on a connection.
|
|
||||||
#ifdef ZONE
|
|
||||||
//#define PACKET_PROFILER 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <map>
|
|
||||||
#include <list>
|
|
||||||
#include <queue>
|
|
||||||
|
|
||||||
#include "../common/types.h"
|
|
||||||
#include "../common/timer.h"
|
|
||||||
#include "../common/linked_list.h"
|
|
||||||
#include "../common/queue.h"
|
|
||||||
#include "../common/Mutex.h"
|
|
||||||
#include "../common/packet_functions.h"
|
|
||||||
#include "EQStream.h"
|
|
||||||
#ifdef PACKET_PROFILER
|
|
||||||
#include "../common/rdtsc.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define EQNC_TIMEOUT 60000
|
|
||||||
#define NAS_TIMER 100
|
|
||||||
#define KA_TIMER 400 /* keeps the lag bar constant */
|
|
||||||
#define MAX_HEADER_SIZE 39 // Quag: 39 is the max header + opcode + crc32 + unknowns size
|
|
||||||
|
|
||||||
class EQStreamServer;
|
|
||||||
class EQStream;
|
|
||||||
class EQStreamPacket;
|
|
||||||
class EQStreamFragmentGroupList;
|
|
||||||
class EQStreamFragmentGroup;
|
|
||||||
typedef EQStreamServer EQNServer;
|
|
||||||
typedef EQStream EQNConnection;
|
|
||||||
typedef EQStreamPacket EQNPacket;
|
|
||||||
typedef EQStreamFragmentGroupList EQNFragmentGroupList;
|
|
||||||
typedef EQStreamFragmentGroup EQNFragmentGroup;
|
|
||||||
|
|
||||||
#define FLAG_COMPRESSED 0x1000
|
|
||||||
#define FLAG_COMBINED 0x2000
|
|
||||||
#define FLAG_ENCRYPTED 0x4000
|
|
||||||
#define FLAG_IMPLICIT 0x8000
|
|
||||||
#define FLAG_ALL 0xF000
|
|
||||||
#define StripFlags(x) (x & ~FLAG_ALL)
|
|
||||||
|
|
||||||
// Optimistic compression, used for guessing pre-alloc size on debug output
|
|
||||||
#define BEST_COMPR_RATIO 300
|
|
||||||
|
|
||||||
enum eappCompressed { appNormal, appInflated, appDeflated };
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
void EQStreamServerLoop(void* tmp);
|
|
||||||
void EQStreamInLoop(void* tmp);
|
|
||||||
void EQStreamOutLoop(void* tmp);
|
|
||||||
#else
|
|
||||||
void* EQStreamServerLoop(void* tmp);
|
|
||||||
void* EQStreamInLoop(void* tmp);
|
|
||||||
void* EQStreamOutLoop(void* tmp);
|
|
||||||
#endif
|
|
||||||
class EQStreamServer {
|
|
||||||
public:
|
|
||||||
EQStreamServer(uint16 iPort = 0);
|
|
||||||
virtual ~EQStreamServer();
|
|
||||||
|
|
||||||
bool Open(uint16 iPort = 0); // opens the port
|
|
||||||
void Close(); // closes the port
|
|
||||||
void KillAll(); // kills all clients
|
|
||||||
inline uint16 GetPort() { return pPort; }
|
|
||||||
|
|
||||||
EQStream* NewQueuePop();
|
|
||||||
protected:
|
|
||||||
#ifdef WIN32
|
|
||||||
friend void EQStreamServerLoop(void* tmp);
|
|
||||||
#else
|
|
||||||
friend void* EQStreamServerLoop(void* tmp);
|
|
||||||
#endif
|
|
||||||
void Process();
|
|
||||||
bool IsOpen();
|
|
||||||
void SetOpen(bool iOpen);
|
|
||||||
bool RunLoop;
|
|
||||||
Mutex MLoopRunning;
|
|
||||||
private:
|
|
||||||
void RecvData(uchar* data, uint32 size, uint32 irIP, uint16 irPort);
|
|
||||||
#ifdef WIN32
|
|
||||||
SOCKET sock;
|
|
||||||
#else
|
|
||||||
int sock;
|
|
||||||
#endif
|
|
||||||
uint16 pPort;
|
|
||||||
bool pOpen;
|
|
||||||
Mutex MNewQueue;
|
|
||||||
Mutex MOpen;
|
|
||||||
|
|
||||||
std::map<std::string,EQStream*> connection_list;
|
|
||||||
std::queue<EQStream *> NewQueue;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,509 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (C) 2005 Michael S. Finger
|
|
||||||
|
|
||||||
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; version 2 of the License.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
||||||
are required to give you total support for your newly bought product;
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
#include "debug.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <iostream>
|
|
||||||
#include <iomanip>
|
|
||||||
#include "EQPacket.h"
|
|
||||||
#include "misc.h"
|
|
||||||
#include "op_codes.h"
|
|
||||||
#include "CRC16.h"
|
|
||||||
#include "platform.h"
|
|
||||||
#ifndef STATIC_OPCODE
|
|
||||||
#include "opcodemgr.h"
|
|
||||||
#endif
|
|
||||||
#include "packet_dump.h"
|
|
||||||
#include "packet_functions.h"
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
EQPacket::EQPacket(EmuOpcode op, const unsigned char *buf, uint32 len)
|
|
||||||
: BasePacket(buf, len),
|
|
||||||
emu_opcode(op)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQPacket::build_raw_header_dump(char *buffer, uint16 seq) const {
|
|
||||||
BasePacket::build_raw_header_dump(buffer, seq);
|
|
||||||
buffer += strlen(buffer);
|
|
||||||
|
|
||||||
buffer += sprintf(buffer, "[EmuOpCode 0x%04x Size=%u]\n", emu_opcode, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQPacket::DumpRawHeader(uint16 seq, FILE *to) const
|
|
||||||
{
|
|
||||||
char buff[196];
|
|
||||||
build_raw_header_dump(buff, seq);
|
|
||||||
fprintf(to, "%s", buff);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQPacket::build_header_dump(char *buffer) const {
|
|
||||||
sprintf(buffer, "[EmuOpCode 0x%04x Size=%u]", emu_opcode, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQPacket::DumpRawHeaderNoTime(uint16 seq, FILE *to) const
|
|
||||||
{
|
|
||||||
if (src_ip) {
|
|
||||||
std::string sIP,dIP;;
|
|
||||||
sIP=long2ip(src_ip);
|
|
||||||
dIP=long2ip(dst_ip);
|
|
||||||
fprintf(to, "[%s:%d->%s:%d] ",sIP.c_str(),src_port,dIP.c_str(),dst_port);
|
|
||||||
}
|
|
||||||
if (seq != 0xffff)
|
|
||||||
fprintf(to, "[Seq=%u] ",seq);
|
|
||||||
|
|
||||||
fprintf(to, "[EmuOpCode 0x%04x Size=%lu]\n",emu_opcode,(unsigned long)size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQProtocolPacket::build_raw_header_dump(char *buffer, uint16 seq) const
|
|
||||||
{
|
|
||||||
BasePacket::build_raw_header_dump(buffer, seq);
|
|
||||||
buffer += strlen(buffer);
|
|
||||||
|
|
||||||
buffer += sprintf(buffer, "[ProtoOpCode 0x%04x Size=%u]\n",opcode,size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQProtocolPacket::DumpRawHeader(uint16 seq, FILE *to) const
|
|
||||||
{
|
|
||||||
char buff[196];
|
|
||||||
build_raw_header_dump(buff, seq);
|
|
||||||
fprintf(to, "%s", buff);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQProtocolPacket::build_header_dump(char *buffer) const
|
|
||||||
{
|
|
||||||
sprintf(buffer, "[ProtoOpCode 0x%04x Size=%u]",opcode,size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQProtocolPacket::DumpRawHeaderNoTime(uint16 seq, FILE *to) const
|
|
||||||
{
|
|
||||||
if (src_ip) {
|
|
||||||
std::string sIP,dIP;;
|
|
||||||
sIP=long2ip(src_ip);
|
|
||||||
dIP=long2ip(dst_ip);
|
|
||||||
fprintf(to, "[%s:%d->%s:%d] ",sIP.c_str(),src_port,dIP.c_str(),dst_port);
|
|
||||||
}
|
|
||||||
if (seq != 0xffff)
|
|
||||||
fprintf(to, "[Seq=%u] ",seq);
|
|
||||||
|
|
||||||
fprintf(to, "[ProtoOpCode 0x%04x Size=%lu]\n",opcode,(unsigned long)size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQApplicationPacket::build_raw_header_dump(char *buffer, uint16 seq) const
|
|
||||||
{
|
|
||||||
BasePacket::build_raw_header_dump(buffer, seq);
|
|
||||||
buffer += strlen(buffer);
|
|
||||||
|
|
||||||
#ifdef STATIC_OPCODE
|
|
||||||
buffer += sprintf(buffer, "[OpCode 0x%04x Size=%u]\n", emu_opcode,size);
|
|
||||||
#else
|
|
||||||
buffer += sprintf(buffer, "[OpCode %s Size=%u]\n",OpcodeManager::EmuToName(emu_opcode),size);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQApplicationPacket::DumpRawHeader(uint16 seq, FILE *to) const
|
|
||||||
{
|
|
||||||
char buff[196];
|
|
||||||
build_raw_header_dump(buff, seq);
|
|
||||||
fprintf(to, "%s", buff);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQApplicationPacket::build_header_dump(char *buffer) const
|
|
||||||
{
|
|
||||||
#ifdef STATIC_OPCODE
|
|
||||||
sprintf(buffer, "[OpCode 0x%04x Size=%u]\n", emu_opcode,size);
|
|
||||||
#else
|
|
||||||
sprintf(buffer, "[OpCode %s Size=%u]",OpcodeManager::EmuToName(emu_opcode),size);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQApplicationPacket::DumpRawHeaderNoTime(uint16 seq, FILE *to) const
|
|
||||||
{
|
|
||||||
if (src_ip) {
|
|
||||||
std::string sIP,dIP;;
|
|
||||||
sIP=long2ip(src_ip);
|
|
||||||
dIP=long2ip(dst_ip);
|
|
||||||
fprintf(to, "[%s:%d->%s:%d] ",sIP.c_str(),src_port,dIP.c_str(),dst_port);
|
|
||||||
}
|
|
||||||
if (seq != 0xffff)
|
|
||||||
fprintf(to, "[Seq=%u] ",seq);
|
|
||||||
|
|
||||||
#ifdef STATIC_OPCODE
|
|
||||||
fprintf(to, "[OpCode 0x%04x Size=%u]\n", emu_opcode,size);
|
|
||||||
#else
|
|
||||||
fprintf(to, "[OpCode %s Size=%lu]\n",OpcodeManager::EmuToName(emu_opcode),(unsigned long)size);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQRawApplicationPacket::build_raw_header_dump(char *buffer, uint16 seq) const
|
|
||||||
{
|
|
||||||
BasePacket::build_raw_header_dump(buffer, seq);
|
|
||||||
buffer += strlen(buffer);
|
|
||||||
|
|
||||||
#ifdef STATIC_OPCODE
|
|
||||||
buffer += sprintf(buffer, "[OpCode 0x%04x (0x%04x) Size=%u]\n", emu_opcode, opcode,size);
|
|
||||||
#else
|
|
||||||
buffer += sprintf(buffer, "[OpCode %s (0x%04x) Size=%u]\n", OpcodeManager::EmuToName(emu_opcode), opcode,size);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQRawApplicationPacket::DumpRawHeader(uint16 seq, FILE *to) const
|
|
||||||
{
|
|
||||||
char buff[196];
|
|
||||||
build_raw_header_dump(buff, seq);
|
|
||||||
fprintf(to, "%s", buff);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQRawApplicationPacket::build_header_dump(char *buffer) const
|
|
||||||
{
|
|
||||||
#ifdef STATIC_OPCODE
|
|
||||||
sprintf(buffer, "[OpCode 0x%04x (0x%04x) Size=%u]\n", emu_opcode, opcode,size);
|
|
||||||
#else
|
|
||||||
sprintf(buffer, "[OpCode %s (0x%04x) Size=%u]", OpcodeManager::EmuToName(emu_opcode), opcode,size);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQRawApplicationPacket::DumpRawHeaderNoTime(uint16 seq, FILE *to) const
|
|
||||||
{
|
|
||||||
if (src_ip) {
|
|
||||||
std::string sIP,dIP;;
|
|
||||||
sIP=long2ip(src_ip);
|
|
||||||
dIP=long2ip(dst_ip);
|
|
||||||
fprintf(to, "[%s:%d->%s:%d] ",sIP.c_str(),src_port,dIP.c_str(),dst_port);
|
|
||||||
}
|
|
||||||
if (seq != 0xffff)
|
|
||||||
fprintf(to, "[Seq=%u] ",seq);
|
|
||||||
|
|
||||||
#ifdef STATIC_OPCODE
|
|
||||||
fprintf(to, "[OpCode 0x%04x (0x%04x) Size=%u]\n", emu_opcode, opcode,size);
|
|
||||||
#else
|
|
||||||
fprintf(to, "[OpCode %s (0x%04x) Size=%lu]\n", OpcodeManager::EmuToName(emu_opcode), opcode,(unsigned long)size);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 EQProtocolPacket::serialize(unsigned char *dest) const
|
|
||||||
{
|
|
||||||
if (opcode>0xff) {
|
|
||||||
*(uint16 *)dest=opcode;
|
|
||||||
} else {
|
|
||||||
*(dest)=0;
|
|
||||||
*(dest+1)=opcode;
|
|
||||||
}
|
|
||||||
memcpy(dest+2,pBuffer,size);
|
|
||||||
|
|
||||||
return size+2;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 EQApplicationPacket::serialize(uint16 opcode, unsigned char *dest) const
|
|
||||||
{
|
|
||||||
uint8 OpCodeBytes = app_opcode_size;
|
|
||||||
|
|
||||||
if (app_opcode_size==1)
|
|
||||||
*(unsigned char *)dest = opcode;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Application opcodes with a low order byte of 0x00 require an extra 0x00 byte inserting prior to the opcode.
|
|
||||||
if((opcode & 0x00ff) == 0)
|
|
||||||
{
|
|
||||||
*(uint8 *)dest = 0;
|
|
||||||
*(uint16 *)(dest + 1) = opcode;
|
|
||||||
++OpCodeBytes;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
*(uint16 *)dest = opcode;
|
|
||||||
}
|
|
||||||
memcpy(dest+OpCodeBytes,pBuffer,size);
|
|
||||||
|
|
||||||
return size+OpCodeBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*EQProtocolPacket::EQProtocolPacket(uint16 op, const unsigned char *buf, uint32 len)
|
|
||||||
: BasePacket(buf, len),
|
|
||||||
opcode(op)
|
|
||||||
{
|
|
||||||
|
|
||||||
uint32 offset;
|
|
||||||
opcode=ntohs(*(const uint16 *)buf);
|
|
||||||
offset=2;
|
|
||||||
|
|
||||||
if (len-offset) {
|
|
||||||
pBuffer= new unsigned char[len-offset];
|
|
||||||
memcpy(pBuffer,buf+offset,len-offset);
|
|
||||||
size=len-offset;
|
|
||||||
} else {
|
|
||||||
pBuffer=nullptr;
|
|
||||||
size=0;
|
|
||||||
}
|
|
||||||
OpMgr=&RawOpcodeManager;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
bool EQProtocolPacket::combine(const EQProtocolPacket *rhs)
|
|
||||||
{
|
|
||||||
bool result=false;
|
|
||||||
if (opcode==OP_Combined && size+rhs->size+5<256) {
|
|
||||||
unsigned char *tmpbuffer=new unsigned char [size+rhs->size+3];
|
|
||||||
memcpy(tmpbuffer,pBuffer,size);
|
|
||||||
uint32 offset=size;
|
|
||||||
tmpbuffer[offset++]=rhs->Size();
|
|
||||||
offset+=rhs->serialize(tmpbuffer+offset);
|
|
||||||
size=offset;
|
|
||||||
delete[] pBuffer;
|
|
||||||
pBuffer=tmpbuffer;
|
|
||||||
result=true;
|
|
||||||
} else if (size+rhs->size+7<256) {
|
|
||||||
unsigned char *tmpbuffer=new unsigned char [size+rhs->size+6];
|
|
||||||
uint32 offset=0;
|
|
||||||
tmpbuffer[offset++]=Size();
|
|
||||||
offset+=serialize(tmpbuffer+offset);
|
|
||||||
tmpbuffer[offset++]=rhs->Size();
|
|
||||||
offset+=rhs->serialize(tmpbuffer+offset);
|
|
||||||
size=offset;
|
|
||||||
delete[] pBuffer;
|
|
||||||
pBuffer=tmpbuffer;
|
|
||||||
opcode=OP_Combined;
|
|
||||||
result=true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
this is the code to do app-layer combining, instead of protocol layer.
|
|
||||||
this was taken out due to complex interactions with the opcode manager,
|
|
||||||
and will require a bit more thinking (likely moving into EQStream) to
|
|
||||||
get running again... but might be a good thing some day.
|
|
||||||
|
|
||||||
bool EQApplicationPacket::combine(const EQApplicationPacket *rhs)
|
|
||||||
{
|
|
||||||
uint32 newsize=0, offset=0;
|
|
||||||
unsigned char *tmpbuffer=nullptr;
|
|
||||||
|
|
||||||
if (opcode!=OP_AppCombined) {
|
|
||||||
newsize=app_opcode_size+size+(size>254?3:1)+app_opcode_size+rhs->size+(rhs->size>254?3:1);
|
|
||||||
tmpbuffer=new unsigned char [newsize];
|
|
||||||
offset=0;
|
|
||||||
if (size>254) {
|
|
||||||
tmpbuffer[offset++]=0xff;
|
|
||||||
*(uint16 *)(tmpbuffer+offset)=htons(size);
|
|
||||||
offset+=1;
|
|
||||||
} else {
|
|
||||||
tmpbuffer[offset++]=size;
|
|
||||||
}
|
|
||||||
offset+=serialize(tmpbuffer+offset);
|
|
||||||
} else {
|
|
||||||
newsize=size+app_opcode_size+rhs->size+(rhs->size>254?3:1);
|
|
||||||
tmpbuffer=new unsigned char [newsize];
|
|
||||||
memcpy(tmpbuffer,pBuffer,size);
|
|
||||||
offset=size;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rhs->size>254) {
|
|
||||||
tmpbuffer[offset++]=0xff;
|
|
||||||
*(uint16 *)(tmpbuffer+offset)=htons(rhs->size);
|
|
||||||
offset+=1;
|
|
||||||
} else {
|
|
||||||
tmpbuffer[offset++]=rhs->size;
|
|
||||||
}
|
|
||||||
offset+=rhs->serialize(tmpbuffer+offset);
|
|
||||||
|
|
||||||
size=offset;
|
|
||||||
opcode=OP_AppCombined;
|
|
||||||
|
|
||||||
delete[] pBuffer;
|
|
||||||
pBuffer=tmpbuffer;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool EQProtocolPacket::ValidateCRC(const unsigned char *buffer, int length, uint32 Key)
|
|
||||||
{
|
|
||||||
bool valid=false;
|
|
||||||
// OP_SessionRequest, OP_SessionResponse, OP_OutOfSession are not CRC'd
|
|
||||||
if (buffer[0]==0x00 && (buffer[1]==OP_SessionRequest || buffer[1]==OP_SessionResponse || buffer[1]==OP_OutOfSession)) {
|
|
||||||
valid=true;
|
|
||||||
} else {
|
|
||||||
uint16 comp_crc=CRC16(buffer,length-2,Key);
|
|
||||||
uint16 packet_crc=ntohs(*(const uint16 *)(buffer+length-2));
|
|
||||||
#ifdef EQN_DEBUG
|
|
||||||
if (packet_crc && comp_crc != packet_crc) {
|
|
||||||
std::cout << "CRC mismatch: comp=" << std::hex << comp_crc << ", packet=" << packet_crc << std::dec << std::endl;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
valid = (!packet_crc || comp_crc == packet_crc);
|
|
||||||
}
|
|
||||||
return valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 EQProtocolPacket::Decompress(const unsigned char *buffer, const uint32 length, unsigned char *newbuf, uint32 newbufsize)
|
|
||||||
{
|
|
||||||
uint32 newlen=0;
|
|
||||||
uint32 flag_offset=0;
|
|
||||||
newbuf[0]=buffer[0];
|
|
||||||
if (buffer[0]==0x00) {
|
|
||||||
flag_offset=2;
|
|
||||||
newbuf[1]=buffer[1];
|
|
||||||
} else
|
|
||||||
flag_offset=1;
|
|
||||||
|
|
||||||
if (length>2 && buffer[flag_offset]==0x5a) {
|
|
||||||
newlen=InflatePacket(buffer+flag_offset+1,length-(flag_offset+1)-2,newbuf+flag_offset,newbufsize-flag_offset)+2;
|
|
||||||
newbuf[newlen++]=buffer[length-2];
|
|
||||||
newbuf[newlen++]=buffer[length-1];
|
|
||||||
} else if (length>2 && buffer[flag_offset]==0xa5) {
|
|
||||||
memcpy(newbuf+flag_offset,buffer+flag_offset+1,length-(flag_offset+1));
|
|
||||||
newlen=length-1;
|
|
||||||
} else {
|
|
||||||
memcpy(newbuf,buffer,length);
|
|
||||||
newlen=length;
|
|
||||||
}
|
|
||||||
|
|
||||||
return newlen;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 EQProtocolPacket::Compress(const unsigned char *buffer, const uint32 length, unsigned char *newbuf, uint32 newbufsize) {
|
|
||||||
uint32 flag_offset=1,newlength;
|
|
||||||
//dump_message_column(buffer,length,"Before: ");
|
|
||||||
newbuf[0]=buffer[0];
|
|
||||||
if (buffer[0]==0) {
|
|
||||||
flag_offset=2;
|
|
||||||
newbuf[1]=buffer[1];
|
|
||||||
}
|
|
||||||
if (length>30) {
|
|
||||||
newlength=DeflatePacket(buffer+flag_offset,length-flag_offset,newbuf+flag_offset+1,newbufsize);
|
|
||||||
*(newbuf+flag_offset)=0x5a;
|
|
||||||
newlength+=flag_offset+1;
|
|
||||||
} else {
|
|
||||||
memmove(newbuf+flag_offset+1,buffer+flag_offset,length-flag_offset);
|
|
||||||
*(newbuf+flag_offset)=0xa5;
|
|
||||||
newlength=length+1;
|
|
||||||
}
|
|
||||||
//dump_message_column(newbuf,length,"After: ");
|
|
||||||
|
|
||||||
return newlength;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQProtocolPacket::ChatDecode(unsigned char *buffer, int size, int DecodeKey)
|
|
||||||
{
|
|
||||||
if ((size >= 2) && buffer[1]!=0x01 && buffer[0]!=0x02 && buffer[0]!=0x1d) {
|
|
||||||
int Key=DecodeKey;
|
|
||||||
unsigned char *test=(unsigned char *)malloc(size);
|
|
||||||
buffer+=2;
|
|
||||||
size-=2;
|
|
||||||
|
|
||||||
int i;
|
|
||||||
for (i = 0 ; i+4 <= size ; i+=4)
|
|
||||||
{
|
|
||||||
int pt = (*(int*)&buffer[i])^(Key);
|
|
||||||
Key = (*(int*)&buffer[i]);
|
|
||||||
*(int*)&test[i]=pt;
|
|
||||||
}
|
|
||||||
unsigned char KC=Key&0xFF;
|
|
||||||
for ( ; i < size ; i++)
|
|
||||||
{
|
|
||||||
test[i]=buffer[i]^KC;
|
|
||||||
}
|
|
||||||
memcpy(buffer,test,size);
|
|
||||||
free(test);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQProtocolPacket::ChatEncode(unsigned char *buffer, int size, int EncodeKey)
|
|
||||||
{
|
|
||||||
if (buffer[1]!=0x01 && buffer[0]!=0x02 && buffer[0]!=0x1d) {
|
|
||||||
int Key=EncodeKey;
|
|
||||||
char *test=(char*)malloc(size);
|
|
||||||
int i;
|
|
||||||
buffer+=2;
|
|
||||||
size-=2;
|
|
||||||
for ( i = 0 ; i+4 <= size ; i+=4)
|
|
||||||
{
|
|
||||||
int pt = (*(int*)&buffer[i])^(Key);
|
|
||||||
Key = pt;
|
|
||||||
*(int*)&test[i]=pt;
|
|
||||||
}
|
|
||||||
unsigned char KC=Key&0xFF;
|
|
||||||
for ( ; i < size ; i++)
|
|
||||||
{
|
|
||||||
test[i]=buffer[i]^KC;
|
|
||||||
}
|
|
||||||
memcpy(buffer,test,size);
|
|
||||||
free(test);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EQApplicationPacket *EQApplicationPacket::Copy() const {
|
|
||||||
return(new EQApplicationPacket(*this));
|
|
||||||
}
|
|
||||||
|
|
||||||
EQRawApplicationPacket *EQProtocolPacket::MakeAppPacket() const {
|
|
||||||
EQRawApplicationPacket *res = new EQRawApplicationPacket(opcode, pBuffer, size);
|
|
||||||
res->copyInfo(this);
|
|
||||||
return(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
EQRawApplicationPacket::EQRawApplicationPacket(uint16 opcode, const unsigned char *buf, const uint32 len)
|
|
||||||
: EQApplicationPacket(OP_Unknown, buf, len),
|
|
||||||
opcode(opcode)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
EQRawApplicationPacket::EQRawApplicationPacket(const unsigned char *buf, const uint32 len)
|
|
||||||
: EQApplicationPacket(OP_Unknown, buf+sizeof(uint16), len-sizeof(uint16))
|
|
||||||
{
|
|
||||||
if(GetExecutablePlatform() != ExePlatformUCS) {
|
|
||||||
opcode = *((const uint16 *) buf);
|
|
||||||
if(opcode == 0x0000)
|
|
||||||
{
|
|
||||||
if(len >= 3)
|
|
||||||
{
|
|
||||||
opcode = *((const uint16 *) (buf + 1));
|
|
||||||
const unsigned char *packet_start = (buf + 3);
|
|
||||||
const int32 packet_length = len - 3;
|
|
||||||
safe_delete_array(pBuffer);
|
|
||||||
if(len >= 0)
|
|
||||||
{
|
|
||||||
size = packet_length;
|
|
||||||
pBuffer = new unsigned char[size];
|
|
||||||
memcpy(pBuffer, packet_start, size);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
size = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
safe_delete_array(pBuffer);
|
|
||||||
size = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
opcode = *((const uint8 *) buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
DumpPacketHex(app->pBuffer, app->size);
|
|
||||||
// DumpPacketAscii(app->pBuffer, app->size);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,153 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (C) 2005 Michael S. Finger
|
|
||||||
|
|
||||||
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; version 2 of the License.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
||||||
are required to give you total support for your newly bought product;
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
#ifndef _EQPACKET_H
|
|
||||||
#define _EQPACKET_H
|
|
||||||
|
|
||||||
#include "BasePacket.h"
|
|
||||||
#include "EQStreamType.h"
|
|
||||||
#include "op_codes.h"
|
|
||||||
#include "platform.h"
|
|
||||||
|
|
||||||
#ifdef STATIC_OPCODE
|
|
||||||
typedef unsigned short EmuOpcode;
|
|
||||||
static const EmuOpcode OP_Unknown = 0;
|
|
||||||
#else
|
|
||||||
#include "emu_opcodes.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class EQStream;
|
|
||||||
class EQStreamPair;
|
|
||||||
|
|
||||||
class EQPacket : public BasePacket {
|
|
||||||
friend class EQStream;
|
|
||||||
public:
|
|
||||||
virtual ~EQPacket() {}
|
|
||||||
|
|
||||||
uint32 Size() const { return size+2; }
|
|
||||||
|
|
||||||
virtual void build_raw_header_dump(char *buffer, uint16 seq=0xffff) const;
|
|
||||||
virtual void build_header_dump(char *buffer) const;
|
|
||||||
virtual void DumpRawHeader(uint16 seq=0xffff, FILE *to = stdout) const;
|
|
||||||
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;
|
|
||||||
|
|
||||||
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(const EQPacket &p) { }
|
|
||||||
EQPacket() { emu_opcode=OP_Unknown; pBuffer=nullptr; size=0; }
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class EQRawApplicationPacket;
|
|
||||||
|
|
||||||
class EQProtocolPacket : public BasePacket {
|
|
||||||
friend class EQStream;
|
|
||||||
friend class EQStreamPair;
|
|
||||||
public:
|
|
||||||
EQProtocolPacket(uint16 op, const unsigned char *buf, uint32 len) : BasePacket(buf,len), opcode(op) { acked = false; }
|
|
||||||
// EQProtocolPacket(const unsigned char *buf, uint32 len);
|
|
||||||
bool combine(const EQProtocolPacket *rhs);
|
|
||||||
uint32 serialize (unsigned char *dest) const;
|
|
||||||
EQProtocolPacket *Copy() { return new EQProtocolPacket(opcode,pBuffer,size); }
|
|
||||||
EQRawApplicationPacket *MakeAppPacket() const;
|
|
||||||
|
|
||||||
bool acked;
|
|
||||||
|
|
||||||
virtual void build_raw_header_dump(char *buffer, uint16 seq=0xffff) const;
|
|
||||||
virtual void build_header_dump(char *buffer) const;
|
|
||||||
virtual void DumpRawHeader(uint16 seq=0xffff, FILE *to = stdout) const;
|
|
||||||
virtual void DumpRawHeaderNoTime(uint16 seq=0xffff, FILE *to = stdout) const;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
static bool ValidateCRC(const unsigned char *buffer, int length, uint32 Key);
|
|
||||||
static uint32 Decompress(const unsigned char *buffer, const uint32 length, unsigned char *newbuf, uint32 newbufsize);
|
|
||||||
static uint32 Compress(const unsigned char *buffer, const uint32 length, unsigned char *newbuf, uint32 newbufsize);
|
|
||||||
static void ChatDecode(unsigned char *buffer, int size, int DecodeKey);
|
|
||||||
static void ChatEncode(unsigned char *buffer, int size, int EncodeKey);
|
|
||||||
|
|
||||||
uint16 GetRawOpcode() const { return(opcode); }
|
|
||||||
|
|
||||||
uint32 Size() const { return size+2; }
|
|
||||||
|
|
||||||
//the actual raw EQ opcode
|
|
||||||
uint16 opcode;
|
|
||||||
};
|
|
||||||
|
|
||||||
class EQApplicationPacket : public EQPacket {
|
|
||||||
// friend class EQProtocolPacket;
|
|
||||||
friend class EQStream;
|
|
||||||
public:
|
|
||||||
EQApplicationPacket() : EQPacket(OP_Unknown,nullptr,0)
|
|
||||||
{ app_opcode_size = GetExecutablePlatform() == ExePlatformUCS ? 1 : 2; }
|
|
||||||
EQApplicationPacket(const EmuOpcode op) : EQPacket(op,nullptr,0)
|
|
||||||
{ app_opcode_size = GetExecutablePlatform() == ExePlatformUCS ? 1 : 2; }
|
|
||||||
EQApplicationPacket(const EmuOpcode op, const uint32 len) : EQPacket(op,nullptr,len)
|
|
||||||
{ app_opcode_size = GetExecutablePlatform() == ExePlatformUCS ? 1 : 2; }
|
|
||||||
EQApplicationPacket(const EmuOpcode op, const unsigned char *buf, const uint32 len) : EQPacket(op,buf,len)
|
|
||||||
{ 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; }
|
|
||||||
|
|
||||||
virtual EQApplicationPacket *Copy() const;
|
|
||||||
|
|
||||||
virtual void build_raw_header_dump(char *buffer, uint16 seq=0xffff) const;
|
|
||||||
virtual void build_header_dump(char *buffer) const;
|
|
||||||
virtual void DumpRawHeader(uint16 seq=0xffff, FILE *to = stdout) const;
|
|
||||||
virtual void DumpRawHeaderNoTime(uint16 seq=0xffff, FILE *to = stdout) const;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
uint8 app_opcode_size;
|
|
||||||
private:
|
|
||||||
|
|
||||||
EQApplicationPacket(const EQApplicationPacket &p) : EQPacket(p.emu_opcode, p.pBuffer, p.size) { app_opcode_size = p.app_opcode_size; }
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class EQRawApplicationPacket : public EQApplicationPacket {
|
|
||||||
friend class EQStream;
|
|
||||||
public:
|
|
||||||
EQRawApplicationPacket(uint16 opcode, const unsigned char *buf, const uint32 len);
|
|
||||||
uint16 GetRawOpcode() const { return(opcode); }
|
|
||||||
|
|
||||||
virtual void build_raw_header_dump(char *buffer, uint16 seq=0xffff) const;
|
|
||||||
virtual void build_header_dump(char *buffer) const;
|
|
||||||
virtual void DumpRawHeader(uint16 seq=0xffff, FILE *to = stdout) const;
|
|
||||||
virtual void DumpRawHeaderNoTime(uint16 seq=0xffff, FILE *to = stdout) const;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
//the actual raw EQ opcode
|
|
||||||
uint16 opcode;
|
|
||||||
|
|
||||||
EQRawApplicationPacket(const unsigned char *buf, const uint32 len);
|
|
||||||
};
|
|
||||||
|
|
||||||
extern void DumpPacket(const EQApplicationPacket* app, bool iShowInfo = false);
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
-1483
File diff suppressed because it is too large
Load Diff
@@ -1,290 +0,0 @@
|
|||||||
#ifndef _EQSTREAM_H
|
|
||||||
#define _EQSTREAM_H
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <map>
|
|
||||||
#include <queue>
|
|
||||||
#include <deque>
|
|
||||||
#ifndef WIN32
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#endif
|
|
||||||
#include "EQStreamType.h"
|
|
||||||
#include "EQPacket.h"
|
|
||||||
#include "EQStreamIntf.h"
|
|
||||||
#include "Mutex.h"
|
|
||||||
#include "../common/opcodemgr.h"
|
|
||||||
#include "../common/misc.h"
|
|
||||||
#include "../common/Condition.h"
|
|
||||||
#include "../common/timer.h"
|
|
||||||
|
|
||||||
#define FLAG_COMPRESSED 0x01
|
|
||||||
#define FLAG_ENCODED 0x04
|
|
||||||
|
|
||||||
#ifndef RATEBASE
|
|
||||||
#define RATEBASE 1048576
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef DECAYBASE
|
|
||||||
#define DECAYBASE 78642
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef RETRANSMIT_TIMEOUT_MULT
|
|
||||||
#define RETRANSMIT_TIMEOUT_MULT 3.0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef RETRANSMIT_TIMEOUT_MAX
|
|
||||||
#define RETRANSMIT_TIMEOUT_MAX 5000
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef AVERAGE_DELTA_MAX
|
|
||||||
#define AVERAGE_DELTA_MAX 2500
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef RETRANSMIT_ACKED_PACKETS
|
|
||||||
#define RETRANSMIT_ACKED_PACKETS true
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#pragma pack(1)
|
|
||||||
struct SessionRequest {
|
|
||||||
uint32 UnknownA;
|
|
||||||
uint32 Session;
|
|
||||||
uint32 MaxLength;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SessionResponse {
|
|
||||||
uint32 Session;
|
|
||||||
uint32 Key;
|
|
||||||
uint8 UnknownA;
|
|
||||||
uint8 Format;
|
|
||||||
uint8 UnknownB;
|
|
||||||
uint32 MaxLength;
|
|
||||||
uint32 UnknownD;
|
|
||||||
};
|
|
||||||
|
|
||||||
//Deltas are in ms, representing round trip times
|
|
||||||
struct SessionStats {
|
|
||||||
/*000*/ uint16 RequestID;
|
|
||||||
/*002*/ uint32 last_local_delta;
|
|
||||||
/*006*/ uint32 average_delta;
|
|
||||||
/*010*/ uint32 low_delta;
|
|
||||||
/*014*/ uint32 high_delta;
|
|
||||||
/*018*/ uint32 last_remote_delta;
|
|
||||||
/*022*/ uint64 packets_sent;
|
|
||||||
/*030*/ uint64 packets_received;
|
|
||||||
/*038*/
|
|
||||||
};
|
|
||||||
|
|
||||||
#pragma pack()
|
|
||||||
|
|
||||||
class OpcodeManager;
|
|
||||||
class EQStreamPair;
|
|
||||||
class EQRawApplicationPacket;
|
|
||||||
|
|
||||||
class EQStream : public EQStreamInterface {
|
|
||||||
friend class EQStreamPair; //for collector.
|
|
||||||
protected:
|
|
||||||
typedef enum {
|
|
||||||
SeqPast,
|
|
||||||
SeqInOrder,
|
|
||||||
SeqFuture
|
|
||||||
} SeqOrder;
|
|
||||||
|
|
||||||
uint32 remote_ip;
|
|
||||||
uint16 remote_port;
|
|
||||||
uint8 buffer[8192];
|
|
||||||
unsigned char *oversize_buffer;
|
|
||||||
uint32 oversize_offset,oversize_length;
|
|
||||||
uint8 app_opcode_size;
|
|
||||||
EQStreamType StreamType;
|
|
||||||
bool compressed,encoded;
|
|
||||||
uint32 retransmittimer;
|
|
||||||
uint32 retransmittimeout;
|
|
||||||
|
|
||||||
//uint32 buffer_len;
|
|
||||||
|
|
||||||
uint32 Session, Key;
|
|
||||||
uint16 NextInSeq;
|
|
||||||
uint32 MaxLen;
|
|
||||||
uint16 MaxSends;
|
|
||||||
|
|
||||||
uint8 active_users; //how many things are actively using this
|
|
||||||
Mutex MInUse;
|
|
||||||
|
|
||||||
EQStreamState State;
|
|
||||||
Mutex MState;
|
|
||||||
|
|
||||||
uint32 LastPacket;
|
|
||||||
Mutex MVarlock;
|
|
||||||
|
|
||||||
// Ack sequence tracking.
|
|
||||||
long NextAckToSend;
|
|
||||||
long LastAckSent;
|
|
||||||
long GetNextAckToSend();
|
|
||||||
long GetLastAckSent();
|
|
||||||
void AckPackets(uint16 seq);
|
|
||||||
void SetNextAckToSend(uint32);
|
|
||||||
void SetLastAckSent(uint32);
|
|
||||||
|
|
||||||
Mutex MAcks;
|
|
||||||
|
|
||||||
// Packets waiting to be sent (all protected by MOutboundQueue)
|
|
||||||
std::queue<EQProtocolPacket *> NonSequencedQueue;
|
|
||||||
std::deque<EQProtocolPacket *> SequencedQueue;
|
|
||||||
uint16 NextOutSeq;
|
|
||||||
uint16 SequencedBase; //the sequence number of SequencedQueue[0]
|
|
||||||
long NextSequencedSend; //index into SequencedQueue
|
|
||||||
Mutex MOutboundQueue;
|
|
||||||
|
|
||||||
//a buffer we use for compression/decompression
|
|
||||||
unsigned char _tempBuffer[2048];
|
|
||||||
|
|
||||||
// Packets waiting to be processed
|
|
||||||
std::vector<EQRawApplicationPacket *> InboundQueue;
|
|
||||||
std::map<unsigned short,EQProtocolPacket *> PacketQueue; //not mutex protected, only accessed by caller of Process()
|
|
||||||
Mutex MInboundQueue;
|
|
||||||
|
|
||||||
static uint16 MaxWindowSize;
|
|
||||||
|
|
||||||
int32 BytesWritten;
|
|
||||||
|
|
||||||
Mutex MRate;
|
|
||||||
int32 RateThreshold;
|
|
||||||
int32 DecayRate;
|
|
||||||
|
|
||||||
|
|
||||||
OpcodeManager **OpMgr;
|
|
||||||
|
|
||||||
EQRawApplicationPacket *MakeApplicationPacket(EQProtocolPacket *p);
|
|
||||||
EQRawApplicationPacket *MakeApplicationPacket(const unsigned char *buf, uint32 len);
|
|
||||||
EQProtocolPacket *MakeProtocolPacket(const unsigned char *buf, uint32 len);
|
|
||||||
void SendPacket(uint16 opcode, EQApplicationPacket *p);
|
|
||||||
|
|
||||||
void SetState(EQStreamState state);
|
|
||||||
|
|
||||||
void SendSessionResponse();
|
|
||||||
void SendSessionRequest();
|
|
||||||
void SendAck(uint16 seq);
|
|
||||||
void SendOutOfOrderAck(uint16 seq);
|
|
||||||
void QueuePacket(EQProtocolPacket *p);
|
|
||||||
void SendPacket(EQProtocolPacket *p);
|
|
||||||
void NonSequencedPush(EQProtocolPacket *p);
|
|
||||||
void SequencedPush(EQProtocolPacket *p);
|
|
||||||
void WritePacket(int fd,EQProtocolPacket *p);
|
|
||||||
|
|
||||||
|
|
||||||
uint32 GetKey() { return Key; }
|
|
||||||
void SetKey(uint32 k) { Key=k; }
|
|
||||||
void SetSession(uint32 s) { Session=s; }
|
|
||||||
|
|
||||||
void ProcessPacket(EQProtocolPacket *p);
|
|
||||||
|
|
||||||
bool Stale(uint32 now, uint32 timeout=30) { return (LastPacket && (now-LastPacket) > timeout); }
|
|
||||||
|
|
||||||
void InboundQueuePush(EQRawApplicationPacket *p);
|
|
||||||
EQRawApplicationPacket *PeekPacket(); //for collector.
|
|
||||||
EQRawApplicationPacket *PopRawPacket(); //for collector.
|
|
||||||
|
|
||||||
void InboundQueueClear();
|
|
||||||
void OutboundQueueClear();
|
|
||||||
void PacketQueueClear();
|
|
||||||
|
|
||||||
void ProcessQueue();
|
|
||||||
EQProtocolPacket *RemoveQueue(uint16 seq);
|
|
||||||
|
|
||||||
void _SendDisconnect();
|
|
||||||
|
|
||||||
void init();
|
|
||||||
public:
|
|
||||||
EQStream() { init(); remote_ip = 0; remote_port = 0; State=UNESTABLISHED; StreamType=UnknownStream; compressed=true; encoded=false; app_opcode_size=2; bytes_sent=0; bytes_recv=0; create_time=Timer::GetTimeSeconds(); }
|
|
||||||
EQStream(sockaddr_in addr) { init(); remote_ip=addr.sin_addr.s_addr; remote_port=addr.sin_port; State=UNESTABLISHED; StreamType=UnknownStream; compressed=true; encoded=false; app_opcode_size=2; bytes_sent=0; bytes_recv=0; create_time=Timer::GetTimeSeconds(); }
|
|
||||||
virtual ~EQStream() { RemoveData(); SetState(CLOSED); }
|
|
||||||
void SetMaxLen(uint32 length) { MaxLen=length; }
|
|
||||||
|
|
||||||
//interface used by application (EQStreamInterface)
|
|
||||||
virtual void QueuePacket(const EQApplicationPacket *p, bool ack_req=true);
|
|
||||||
virtual void FastQueuePacket(EQApplicationPacket **p, bool ack_req=true);
|
|
||||||
virtual EQApplicationPacket *PopPacket();
|
|
||||||
virtual void Close();
|
|
||||||
virtual uint32 GetRemoteIP() const { return remote_ip; }
|
|
||||||
virtual uint16 GetRemotePort() const { return remote_port; }
|
|
||||||
virtual void ReleaseFromUse() { MInUse.lock(); if(active_users > 0) active_users--; MInUse.unlock(); }
|
|
||||||
virtual void RemoveData() { InboundQueueClear(); OutboundQueueClear(); PacketQueueClear(); /*if (CombinedAppPacket) delete CombinedAppPacket;*/ }
|
|
||||||
virtual bool CheckState(EQStreamState state) { return GetState() == state; }
|
|
||||||
virtual std::string Describe() const { return("Direct EQStream"); }
|
|
||||||
|
|
||||||
void SetOpcodeManager(OpcodeManager **opm) { OpMgr = opm; }
|
|
||||||
|
|
||||||
void CheckTimeout(uint32 now, uint32 timeout=30);
|
|
||||||
bool HasOutgoingData();
|
|
||||||
void Process(const unsigned char *data, const uint32 length);
|
|
||||||
void SetLastPacketTime(uint32 t) {LastPacket=t;}
|
|
||||||
void Write(int eq_fd);
|
|
||||||
|
|
||||||
//
|
|
||||||
inline bool IsInUse() { bool flag; MInUse.lock(); flag=(active_users>0); MInUse.unlock(); return flag; }
|
|
||||||
inline void PutInUse() { MInUse.lock(); active_users++; MInUse.unlock(); }
|
|
||||||
|
|
||||||
inline EQStreamState GetState() { EQStreamState s; MState.lock(); s=State; MState.unlock(); return s; }
|
|
||||||
|
|
||||||
static SeqOrder CompareSequence(uint16 expected_seq , uint16 seq);
|
|
||||||
|
|
||||||
bool CheckActive() { return GetState()==ESTABLISHED; }
|
|
||||||
bool CheckClosed() { return GetState()==CLOSED; }
|
|
||||||
void SetOpcodeSize(uint8 s) { app_opcode_size = s; }
|
|
||||||
void SetStreamType(EQStreamType t);
|
|
||||||
inline const EQStreamType GetStreamType() const { return StreamType; }
|
|
||||||
static const char *StreamTypeString(EQStreamType t);
|
|
||||||
|
|
||||||
void Decay();
|
|
||||||
void AdjustRates(uint32 average_delta);
|
|
||||||
|
|
||||||
uint32 bytes_sent;
|
|
||||||
uint32 bytes_recv;
|
|
||||||
uint32 create_time;
|
|
||||||
|
|
||||||
void AddBytesSent(uint32 bytes)
|
|
||||||
{
|
|
||||||
bytes_sent += bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddBytesRecv(uint32 bytes)
|
|
||||||
{
|
|
||||||
bytes_recv += bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual const uint32 GetBytesSent() const { return bytes_sent; }
|
|
||||||
virtual const uint32 GetBytesRecieved() const { return bytes_recv; }
|
|
||||||
virtual const uint32 GetBytesSentPerSecond() const
|
|
||||||
{
|
|
||||||
if((Timer::GetTimeSeconds() - create_time) == 0)
|
|
||||||
return 0;
|
|
||||||
return bytes_sent / (Timer::GetTimeSeconds() - create_time);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual const uint32 GetBytesRecvPerSecond() const
|
|
||||||
{
|
|
||||||
if((Timer::GetTimeSeconds() - create_time) == 0)
|
|
||||||
return 0;
|
|
||||||
return bytes_recv / (Timer::GetTimeSeconds() - create_time);
|
|
||||||
}
|
|
||||||
|
|
||||||
//used for dynamic stream identification
|
|
||||||
class Signature {
|
|
||||||
public:
|
|
||||||
//this object could get more complicated if needed...
|
|
||||||
uint16 ignore_eq_opcode; //0=dont ignore
|
|
||||||
uint16 first_eq_opcode;
|
|
||||||
uint32 first_length; //0=dont check length
|
|
||||||
};
|
|
||||||
typedef enum {
|
|
||||||
MatchNotReady,
|
|
||||||
MatchSuccessful,
|
|
||||||
MatchFailed
|
|
||||||
} MatchState;
|
|
||||||
MatchState CheckSignature(const Signature *sig);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@@ -1,326 +0,0 @@
|
|||||||
#include "debug.h"
|
|
||||||
#include "EQStreamFactory.h"
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
#include <winsock.h>
|
|
||||||
#include <process.h>
|
|
||||||
#include <io.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#else
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <sys/select.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <netdb.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
#endif
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <iostream>
|
|
||||||
#include "op_codes.h"
|
|
||||||
#include "EQStream.h"
|
|
||||||
#include "logsys.h"
|
|
||||||
|
|
||||||
ThreadReturnType EQStreamFactoryReaderLoop(void *eqfs)
|
|
||||||
{
|
|
||||||
EQStreamFactory *fs=(EQStreamFactory *)eqfs;
|
|
||||||
|
|
||||||
#ifndef WIN32
|
|
||||||
_log(COMMON__THREADS, "Starting EQStreamFactoryReaderLoop with thread ID %d", pthread_self());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
fs->ReaderLoop();
|
|
||||||
|
|
||||||
#ifndef WIN32
|
|
||||||
_log(COMMON__THREADS, "Ending EQStreamFactoryReaderLoop with thread ID %d", pthread_self());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
THREAD_RETURN(nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
ThreadReturnType EQStreamFactoryWriterLoop(void *eqfs)
|
|
||||||
{
|
|
||||||
EQStreamFactory *fs=(EQStreamFactory *)eqfs;
|
|
||||||
|
|
||||||
#ifndef WIN32
|
|
||||||
_log(COMMON__THREADS, "Starting EQStreamFactoryWriterLoop with thread ID %d", pthread_self());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
fs->WriterLoop();
|
|
||||||
|
|
||||||
#ifndef WIN32
|
|
||||||
_log(COMMON__THREADS, "Ending EQStreamFactoryWriterLoop with thread ID %d", pthread_self());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
THREAD_RETURN(nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
EQStreamFactory::EQStreamFactory(EQStreamType type, int port, uint32 timeout)
|
|
||||||
: Timeoutable(5000), stream_timeout(timeout)
|
|
||||||
{
|
|
||||||
StreamType=type;
|
|
||||||
Port=port;
|
|
||||||
sock=-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQStreamFactory::Close()
|
|
||||||
{
|
|
||||||
Stop();
|
|
||||||
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
closesocket(sock);
|
|
||||||
#else
|
|
||||||
close(sock);
|
|
||||||
#endif
|
|
||||||
sock=-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EQStreamFactory::Open()
|
|
||||||
{
|
|
||||||
struct sockaddr_in address;
|
|
||||||
#ifndef WIN32
|
|
||||||
pthread_t t1,t2;
|
|
||||||
#endif
|
|
||||||
/* Setup internet address information.
|
|
||||||
This is used with the bind() call */
|
|
||||||
memset((char *) &address, 0, sizeof(address));
|
|
||||||
address.sin_family = AF_INET;
|
|
||||||
address.sin_port = htons(Port);
|
|
||||||
address.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
||||||
|
|
||||||
/* Setting up UDP port for new clients */
|
|
||||||
sock = socket(AF_INET, SOCK_DGRAM, 0);
|
|
||||||
if (sock < 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bind(sock, (struct sockaddr *) &address, sizeof(address)) < 0) {
|
|
||||||
close(sock);
|
|
||||||
sock=-1;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
unsigned long nonblock = 1;
|
|
||||||
ioctlsocket(sock, FIONBIO, &nonblock);
|
|
||||||
#else
|
|
||||||
fcntl(sock, F_SETFL, O_NONBLOCK);
|
|
||||||
#endif
|
|
||||||
//moved these because on windows the output was delayed and causing the console window to look bad
|
|
||||||
//std::cout << "Starting factory Reader" << std::endl;
|
|
||||||
//std::cout << "Starting factory Writer" << std::endl;
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
_beginthread(EQStreamFactoryReaderLoop,0, this);
|
|
||||||
_beginthread(EQStreamFactoryWriterLoop,0, this);
|
|
||||||
#else
|
|
||||||
pthread_create(&t1,nullptr,EQStreamFactoryReaderLoop,this);
|
|
||||||
pthread_create(&t2,nullptr,EQStreamFactoryWriterLoop,this);
|
|
||||||
#endif
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
EQStream *EQStreamFactory::Pop()
|
|
||||||
{
|
|
||||||
EQStream *s=nullptr;
|
|
||||||
//std::cout << "Pop():Locking MNewStreams" << std::endl;
|
|
||||||
MNewStreams.lock();
|
|
||||||
if (NewStreams.size()) {
|
|
||||||
s=NewStreams.front();
|
|
||||||
NewStreams.pop();
|
|
||||||
s->PutInUse();
|
|
||||||
}
|
|
||||||
MNewStreams.unlock();
|
|
||||||
//std::cout << "Pop(): Unlocking MNewStreams" << std::endl;
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQStreamFactory::Push(EQStream *s)
|
|
||||||
{
|
|
||||||
//std::cout << "Push():Locking MNewStreams" << std::endl;
|
|
||||||
MNewStreams.lock();
|
|
||||||
NewStreams.push(s);
|
|
||||||
MNewStreams.unlock();
|
|
||||||
//std::cout << "Push(): Unlocking MNewStreams" << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQStreamFactory::ReaderLoop()
|
|
||||||
{
|
|
||||||
fd_set readset;
|
|
||||||
std::map<std::pair<uint32, uint16>,EQStream *>::iterator stream_itr;
|
|
||||||
int num;
|
|
||||||
int length;
|
|
||||||
unsigned char buffer[2048];
|
|
||||||
sockaddr_in from;
|
|
||||||
int socklen=sizeof(sockaddr_in);
|
|
||||||
timeval sleep_time;
|
|
||||||
//time_t now;
|
|
||||||
|
|
||||||
ReaderRunning=true;
|
|
||||||
while(sock!=-1) {
|
|
||||||
MReaderRunning.lock();
|
|
||||||
if (!ReaderRunning)
|
|
||||||
break;
|
|
||||||
MReaderRunning.unlock();
|
|
||||||
|
|
||||||
FD_ZERO(&readset);
|
|
||||||
FD_SET(sock,&readset);
|
|
||||||
|
|
||||||
sleep_time.tv_sec=30;
|
|
||||||
sleep_time.tv_usec=0;
|
|
||||||
if ((num=select(sock+1,&readset,nullptr,nullptr,&sleep_time))<0) {
|
|
||||||
// What do we wanna do?
|
|
||||||
continue;
|
|
||||||
} else if (num==0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if(sock == -1)
|
|
||||||
break; //somebody closed us while we were sleeping.
|
|
||||||
|
|
||||||
if (FD_ISSET(sock,&readset)) {
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
if ((length=recvfrom(sock,(char*)buffer,sizeof(buffer),0,(struct sockaddr*)&from,(int *)&socklen)) < 2)
|
|
||||||
#else
|
|
||||||
if ((length=recvfrom(sock,buffer,2048,0,(struct sockaddr *)&from,(socklen_t *)&socklen)) < 2)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
// What do we wanna do?
|
|
||||||
} else {
|
|
||||||
MStreams.lock();
|
|
||||||
stream_itr=Streams.find(std::make_pair(from.sin_addr.s_addr, from.sin_port));
|
|
||||||
if (stream_itr == Streams.end()) {
|
|
||||||
if (buffer[1]==OP_SessionRequest) {
|
|
||||||
EQStream *s = new EQStream(from);
|
|
||||||
s->SetStreamType(StreamType);
|
|
||||||
Streams[std::make_pair(from.sin_addr.s_addr, from.sin_port)]=s;
|
|
||||||
WriterWork.Signal();
|
|
||||||
Push(s);
|
|
||||||
s->AddBytesRecv(length);
|
|
||||||
s->Process(buffer,length);
|
|
||||||
s->SetLastPacketTime(Timer::GetCurrentTime());
|
|
||||||
}
|
|
||||||
MStreams.unlock();
|
|
||||||
} else {
|
|
||||||
EQStream *curstream = stream_itr->second;
|
|
||||||
//dont bother processing incoming packets for closed connections
|
|
||||||
if(curstream->CheckClosed())
|
|
||||||
curstream = nullptr;
|
|
||||||
else
|
|
||||||
curstream->PutInUse();
|
|
||||||
MStreams.unlock(); //the in use flag prevents the stream from being deleted while we are using it.
|
|
||||||
|
|
||||||
if(curstream) {
|
|
||||||
curstream->AddBytesRecv(length);
|
|
||||||
curstream->Process(buffer,length);
|
|
||||||
curstream->SetLastPacketTime(Timer::GetCurrentTime());
|
|
||||||
curstream->ReleaseFromUse();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQStreamFactory::CheckTimeout()
|
|
||||||
{
|
|
||||||
//lock streams the entire time were checking timeouts, it should be fast.
|
|
||||||
MStreams.lock();
|
|
||||||
|
|
||||||
unsigned long now=Timer::GetCurrentTime();
|
|
||||||
std::map<std::pair<uint32, uint16>,EQStream *>::iterator stream_itr;
|
|
||||||
|
|
||||||
for(stream_itr=Streams.begin();stream_itr!=Streams.end();) {
|
|
||||||
EQStream *s = stream_itr->second;
|
|
||||||
|
|
||||||
s->CheckTimeout(now, stream_timeout);
|
|
||||||
|
|
||||||
EQStreamState state = s->GetState();
|
|
||||||
|
|
||||||
//not part of the else so we check it right away on state change
|
|
||||||
if (state==CLOSED) {
|
|
||||||
if (s->IsInUse()) {
|
|
||||||
//give it a little time for everybody to finish with it
|
|
||||||
} else {
|
|
||||||
//everybody is done, we can delete it now
|
|
||||||
//std::cout << "Removing connection" << std::endl;
|
|
||||||
std::map<std::pair<uint32, uint16>,EQStream *>::iterator temp=stream_itr;
|
|
||||||
++stream_itr;
|
|
||||||
//let whoever has the stream outside delete it
|
|
||||||
delete temp->second;
|
|
||||||
Streams.erase(temp);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
++stream_itr;
|
|
||||||
}
|
|
||||||
MStreams.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQStreamFactory::WriterLoop()
|
|
||||||
{
|
|
||||||
std::map<std::pair<uint32, uint16>,EQStream *>::iterator stream_itr;
|
|
||||||
bool havework=true;
|
|
||||||
std::vector<EQStream *> wants_write;
|
|
||||||
std::vector<EQStream *>::iterator cur,end;
|
|
||||||
bool decay=false;
|
|
||||||
uint32 stream_count;
|
|
||||||
|
|
||||||
Timer DecayTimer(20);
|
|
||||||
|
|
||||||
WriterRunning=true;
|
|
||||||
DecayTimer.Enable();
|
|
||||||
while(sock!=-1) {
|
|
||||||
//if (!havework) {
|
|
||||||
//WriterWork.Wait();
|
|
||||||
//}
|
|
||||||
MWriterRunning.lock();
|
|
||||||
if (!WriterRunning)
|
|
||||||
break;
|
|
||||||
MWriterRunning.unlock();
|
|
||||||
|
|
||||||
havework = false;
|
|
||||||
wants_write.clear();
|
|
||||||
|
|
||||||
decay=DecayTimer.Check();
|
|
||||||
|
|
||||||
//copy streams into a seperate list so we dont have to keep
|
|
||||||
//MStreams locked while we are writting
|
|
||||||
MStreams.lock();
|
|
||||||
for(stream_itr=Streams.begin();stream_itr!=Streams.end();++stream_itr) {
|
|
||||||
// If it's time to decay the bytes sent, then let's do it before we try to write
|
|
||||||
if (decay)
|
|
||||||
stream_itr->second->Decay();
|
|
||||||
|
|
||||||
//bullshit checking, to see if this is really happening, GDB seems to think so...
|
|
||||||
if(stream_itr->second == nullptr) {
|
|
||||||
fprintf(stderr, "ERROR: nullptr Stream encountered in EQStreamFactory::WriterLoop for: %i", stream_itr->first.first, stream_itr->first.second);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stream_itr->second->HasOutgoingData()) {
|
|
||||||
havework=true;
|
|
||||||
stream_itr->second->PutInUse();
|
|
||||||
wants_write.push_back(stream_itr->second);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MStreams.unlock();
|
|
||||||
|
|
||||||
//do the actual writes
|
|
||||||
cur = wants_write.begin();
|
|
||||||
end = wants_write.end();
|
|
||||||
for(; cur != end; ++cur) {
|
|
||||||
(*cur)->Write(sock);
|
|
||||||
(*cur)->ReleaseFromUse();
|
|
||||||
}
|
|
||||||
|
|
||||||
Sleep(10);
|
|
||||||
|
|
||||||
MStreams.lock();
|
|
||||||
stream_count=Streams.size();
|
|
||||||
MStreams.unlock();
|
|
||||||
if (!stream_count) {
|
|
||||||
//std::cout << "No streams, waiting on condition" << std::endl;
|
|
||||||
WriterWork.Wait();
|
|
||||||
//std::cout << "Awake from condition, must have a stream now" << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
#ifndef _EQSTREAMFACTORY_H
|
|
||||||
|
|
||||||
#define _EQSTREAMFACTORY_H
|
|
||||||
|
|
||||||
#include <queue>
|
|
||||||
#include <map>
|
|
||||||
#include "../common/EQStream.h"
|
|
||||||
#include "../common/Condition.h"
|
|
||||||
#include "../common/timeoutmgr.h"
|
|
||||||
#include "../common/opcodemgr.h"
|
|
||||||
#include "../common/timer.h"
|
|
||||||
|
|
||||||
class EQStreamFactory : private Timeoutable {
|
|
||||||
private:
|
|
||||||
int sock;
|
|
||||||
int Port;
|
|
||||||
|
|
||||||
bool ReaderRunning;
|
|
||||||
Mutex MReaderRunning;
|
|
||||||
bool WriterRunning;
|
|
||||||
Mutex MWriterRunning;
|
|
||||||
|
|
||||||
Condition WriterWork;
|
|
||||||
|
|
||||||
EQStreamType StreamType;
|
|
||||||
|
|
||||||
std::queue<EQStream *> NewStreams;
|
|
||||||
Mutex MNewStreams;
|
|
||||||
|
|
||||||
std::map<std::pair<uint32, uint16>,EQStream *> Streams;
|
|
||||||
Mutex MStreams;
|
|
||||||
|
|
||||||
virtual void CheckTimeout();
|
|
||||||
|
|
||||||
Timer *DecayTimer;
|
|
||||||
|
|
||||||
uint32 stream_timeout;
|
|
||||||
|
|
||||||
public:
|
|
||||||
EQStreamFactory(EQStreamType type, uint32 timeout = 135000) : Timeoutable(5000), stream_timeout(timeout) { ReaderRunning=false; WriterRunning=false; StreamType=type; sock=-1; }
|
|
||||||
EQStreamFactory(EQStreamType type, int port, uint32 timeout = 135000);
|
|
||||||
|
|
||||||
EQStream *Pop();
|
|
||||||
void Push(EQStream *s);
|
|
||||||
|
|
||||||
bool Open();
|
|
||||||
bool Open(unsigned long port) { Port=port; return Open(); }
|
|
||||||
bool IsOpen() { return sock!=-1; }
|
|
||||||
void Close();
|
|
||||||
void ReaderLoop();
|
|
||||||
void WriterLoop();
|
|
||||||
void Stop() { StopReader(); StopWriter(); }
|
|
||||||
void StopReader() { MReaderRunning.lock(); ReaderRunning=false; MReaderRunning.unlock(); }
|
|
||||||
void StopWriter() { MWriterRunning.lock(); WriterRunning=false; MWriterRunning.unlock(); WriterWork.Signal(); }
|
|
||||||
void SignalWriter() { WriterWork.Signal(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,163 +0,0 @@
|
|||||||
#include "debug.h"
|
|
||||||
#include "EQStreamIdent.h"
|
|
||||||
#include "EQStreamProxy.h"
|
|
||||||
#include "logsys.h"
|
|
||||||
|
|
||||||
EQStreamIdentifier::~EQStreamIdentifier() {
|
|
||||||
while(!m_identified.empty()) {
|
|
||||||
m_identified.front()->ReleaseFromUse();
|
|
||||||
m_identified.pop();
|
|
||||||
}
|
|
||||||
std::vector<Record *>::iterator cur, end;
|
|
||||||
cur = m_streams.begin();
|
|
||||||
end = m_streams.end();
|
|
||||||
for(; cur != end; ++cur) {
|
|
||||||
Record *r = *cur;
|
|
||||||
r->stream->ReleaseFromUse();
|
|
||||||
delete r;
|
|
||||||
}
|
|
||||||
std::vector<Patch *>::iterator curp, endp;
|
|
||||||
curp = m_patches.begin();
|
|
||||||
endp = m_patches.end();
|
|
||||||
for(; curp != endp; ++curp) {
|
|
||||||
delete *curp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQStreamIdentifier::RegisterPatch(const EQStream::Signature &sig, const char *name, OpcodeManager ** opcodes, const StructStrategy *structs) {
|
|
||||||
Patch *p = new Patch;
|
|
||||||
p->signature = sig;
|
|
||||||
p->name = name;
|
|
||||||
p->opcodes = opcodes;
|
|
||||||
p->structs = structs;
|
|
||||||
m_patches.push_back(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQStreamIdentifier::Process() {
|
|
||||||
std::vector<Record *>::iterator cur;
|
|
||||||
std::vector<Patch *>::iterator curp, endp;
|
|
||||||
|
|
||||||
//foreach pending stream.
|
|
||||||
cur = m_streams.begin();
|
|
||||||
while(cur != m_streams.end()) {
|
|
||||||
Record *r = *cur;
|
|
||||||
|
|
||||||
//first see if this stream has expired
|
|
||||||
if(r->expire.Check(false)) {
|
|
||||||
//this stream has failed to match any pattern in our timeframe.
|
|
||||||
_log(NET__IDENTIFY, "Unable to identify stream from %s:%d before timeout.", long2ip(r->stream->GetRemoteIP()).c_str(), ntohs(r->stream->GetRemotePort()));
|
|
||||||
r->stream->ReleaseFromUse();
|
|
||||||
delete r;
|
|
||||||
cur = m_streams.erase(cur);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//then make sure the stream is still active
|
|
||||||
//if stream hasn't finished initializing then continue;
|
|
||||||
if(r->stream->GetState() == UNESTABLISHED)
|
|
||||||
{
|
|
||||||
++cur;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(r->stream->GetState() != ESTABLISHED) {
|
|
||||||
//the stream closed before it was identified.
|
|
||||||
_log(NET__IDENTIFY, "Unable to identify stream from %s:%d before it closed.", long2ip(r->stream->GetRemoteIP()).c_str(), ntohs(r->stream->GetRemotePort()));
|
|
||||||
switch(r->stream->GetState())
|
|
||||||
{
|
|
||||||
case ESTABLISHED:
|
|
||||||
_log(NET__IDENTIFY, "Stream state was Established");
|
|
||||||
break;
|
|
||||||
case CLOSING:
|
|
||||||
_log(NET__IDENTIFY, "Stream state was Closing");
|
|
||||||
break;
|
|
||||||
case DISCONNECTING:
|
|
||||||
_log(NET__IDENTIFY, "Stream state was Disconnecting");
|
|
||||||
break;
|
|
||||||
case CLOSED:
|
|
||||||
_log(NET__IDENTIFY, "Stream state was Closed");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
_log(NET__IDENTIFY, "Stream state was Unestablished or unknown");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
r->stream->ReleaseFromUse();
|
|
||||||
delete r;
|
|
||||||
cur = m_streams.erase(cur);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//not expired, check against all patch signatures
|
|
||||||
|
|
||||||
bool found_one = false; //"we found a matching patch for this stream"
|
|
||||||
bool all_ready = true; //"all signatures were ready to check the stream"
|
|
||||||
|
|
||||||
//foreach possbile patch...
|
|
||||||
curp = m_patches.begin();
|
|
||||||
endp = m_patches.end();
|
|
||||||
for(; !found_one && curp != endp; ++curp) {
|
|
||||||
Patch *p = *curp;
|
|
||||||
|
|
||||||
//ask the stream to see if it matches the supplied signature
|
|
||||||
EQStream::MatchState res = r->stream->CheckSignature(&p->signature);
|
|
||||||
switch(res) {
|
|
||||||
case EQStream::MatchNotReady:
|
|
||||||
//the stream has not received enough packets to compare with this signature
|
|
||||||
// _log(NET__IDENT_TRACE, "%s:%d: Tried patch %s, but stream is not ready for it.", long2ip(r->stream->GetRemoteIP()).c_str(), ntohs(r->stream->GetRemotePort()), p->name.c_str());
|
|
||||||
all_ready = false;
|
|
||||||
break;
|
|
||||||
case EQStream::MatchSuccessful: {
|
|
||||||
//yay, a match.
|
|
||||||
|
|
||||||
_log(NET__IDENTIFY, "Identified stream %s:%d with signature %s", long2ip(r->stream->GetRemoteIP()).c_str(), ntohs(r->stream->GetRemotePort()), p->name.c_str());
|
|
||||||
|
|
||||||
//might want to do something less-specific here... some day..
|
|
||||||
EQStreamInterface *s = new EQStreamProxy(r->stream, p->structs, p->opcodes);
|
|
||||||
m_identified.push(s);
|
|
||||||
|
|
||||||
found_one = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case EQStream::MatchFailed:
|
|
||||||
//do nothing...
|
|
||||||
_log(NET__IDENT_TRACE, "%s:%d: Tried patch %s, and it did not match.", long2ip(r->stream->GetRemoteIP()).c_str(), ntohs(r->stream->GetRemotePort()), p->name.c_str());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//if we checked all patches and did not find a match.
|
|
||||||
if(all_ready && !found_one) {
|
|
||||||
//the stream cannot be identified.
|
|
||||||
_log(NET__IDENTIFY, "Unable to identify stream from %s:%d, no match found.", long2ip(r->stream->GetRemoteIP()).c_str(), ntohs(r->stream->GetRemotePort()));
|
|
||||||
r->stream->ReleaseFromUse();
|
|
||||||
}
|
|
||||||
|
|
||||||
//if we found a match, or were not able to identify it
|
|
||||||
if(found_one || all_ready) {
|
|
||||||
//cannot print ip/port here. r->stream is invalid.
|
|
||||||
delete r;
|
|
||||||
cur = m_streams.erase(cur);
|
|
||||||
} else {
|
|
||||||
++cur;
|
|
||||||
}
|
|
||||||
} //end foreach stream
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQStreamIdentifier::AddStream(EQStream *&eqs) {
|
|
||||||
m_streams.push_back(new Record(eqs));
|
|
||||||
eqs = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
EQStreamInterface *EQStreamIdentifier::PopIdentified() {
|
|
||||||
if(m_identified.empty())
|
|
||||||
return(nullptr);
|
|
||||||
EQStreamInterface *res = m_identified.front();
|
|
||||||
m_identified.pop();
|
|
||||||
return(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
EQStreamIdentifier::Record::Record(EQStream *s)
|
|
||||||
: stream(s),
|
|
||||||
expire(STREAM_IDENT_WAIT_MS)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
#ifndef EQSTREAMIDENT_H_
|
|
||||||
#define EQSTREAMIDENT_H_
|
|
||||||
|
|
||||||
#include "EQStream.h"
|
|
||||||
#include "timer.h"
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include <queue>
|
|
||||||
|
|
||||||
#define STREAM_IDENT_WAIT_MS 10000
|
|
||||||
|
|
||||||
class OpcodeManager;
|
|
||||||
class StructStrategy;
|
|
||||||
|
|
||||||
class EQStreamIdentifier {
|
|
||||||
public:
|
|
||||||
~EQStreamIdentifier();
|
|
||||||
|
|
||||||
//registration interface.
|
|
||||||
void RegisterPatch(const EQStream::Signature &sig, const char *name, OpcodeManager ** opcodes, const StructStrategy *structs);
|
|
||||||
|
|
||||||
//main processing interface
|
|
||||||
void Process();
|
|
||||||
void AddStream(EQStream *& eqs);
|
|
||||||
EQStreamInterface *PopIdentified();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
//registered patches..
|
|
||||||
class Patch {
|
|
||||||
public:
|
|
||||||
std::string name;
|
|
||||||
EQStream::Signature signature;
|
|
||||||
OpcodeManager ** opcodes;
|
|
||||||
const StructStrategy *structs;
|
|
||||||
};
|
|
||||||
std::vector<Patch *> m_patches; //we own these objects.
|
|
||||||
|
|
||||||
//pending streams..
|
|
||||||
class Record {
|
|
||||||
public:
|
|
||||||
Record(EQStream *s);
|
|
||||||
EQStream *stream; //we own this
|
|
||||||
Timer expire;
|
|
||||||
};
|
|
||||||
std::vector<Record *> m_streams; //we own these objects, and the streams contained in them.
|
|
||||||
std::queue<EQStreamInterface *> m_identified; //we own these objects
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /*EQSTREAMIDENT_H_*/
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
#ifndef EQSTREAMINTF_H_
|
|
||||||
#define EQSTREAMINTF_H_
|
|
||||||
|
|
||||||
//this is the only part of an EQStream that is seen by the application.
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include "clientversions.h"
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
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 EQStreamInterface {
|
|
||||||
public:
|
|
||||||
virtual ~EQStreamInterface() {}
|
|
||||||
|
|
||||||
virtual void QueuePacket(const EQApplicationPacket *p, bool ack_req=true) = 0;
|
|
||||||
virtual void FastQueuePacket(EQApplicationPacket **p, bool ack_req=true) = 0;
|
|
||||||
virtual EQApplicationPacket *PopPacket() = 0;
|
|
||||||
virtual void Close() = 0;
|
|
||||||
virtual void ReleaseFromUse() = 0;
|
|
||||||
virtual void RemoveData() = 0;
|
|
||||||
virtual uint32 GetRemoteIP() const = 0;
|
|
||||||
virtual uint16 GetRemotePort() const = 0;
|
|
||||||
virtual bool CheckState(EQStreamState state) = 0;
|
|
||||||
virtual std::string Describe() const = 0;
|
|
||||||
|
|
||||||
virtual const uint32 GetBytesSent() const { return 0; }
|
|
||||||
virtual const uint32 GetBytesRecieved() const { return 0; }
|
|
||||||
virtual const uint32 GetBytesSentPerSecond() const { return 0; }
|
|
||||||
virtual const uint32 GetBytesRecvPerSecond() const { return 0; }
|
|
||||||
virtual const EQClientVersion ClientVersion() const { return EQClientUnknown; }
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /*EQSTREAMINTF_H_*/
|
|
||||||
@@ -1,172 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (C) 2005 EQEmulator 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; version 2 of the License.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
||||||
are required to give you total support for your newly bought product;
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
#ifndef _EQSTREAM_LOCATOR_H
|
|
||||||
#define _EQSTREAM_LOCATOR_H
|
|
||||||
|
|
||||||
/*
|
|
||||||
This did not turn out nearly as nice as I hoped.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
class EQStreamInfo {
|
|
||||||
public:
|
|
||||||
EQStreamInfo() {}
|
|
||||||
EQStreamInfo(uint32 isrc_ip, uint32 idst_ip, uint16 isrc_port, uint16 idst_port) {
|
|
||||||
src_ip = isrc_ip;
|
|
||||||
dst_ip = idst_ip;
|
|
||||||
src_port = isrc_port;
|
|
||||||
dst_port = idst_port;
|
|
||||||
}
|
|
||||||
void invert(EQStreamInfo &r) const {
|
|
||||||
r.src_ip = dst_ip;
|
|
||||||
r.dst_ip = src_ip;
|
|
||||||
r.src_port = dst_port;
|
|
||||||
r.dst_port = src_port;
|
|
||||||
}
|
|
||||||
uint32 src_ip;
|
|
||||||
uint32 dst_ip;
|
|
||||||
uint16 src_port;
|
|
||||||
uint16 dst_port;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline bool operator<(const EQStreamInfo &l, const EQStreamInfo &r) {
|
|
||||||
/*printf("Less than called with:\n");
|
|
||||||
printf("0x%.8x:%d -> 0x%.8x:%d < \n", l.src_ip, l.src_port, l.dst_ip, l.dst_port);
|
|
||||||
printf("0x%.8x:%d -> 0x%.8x:%d ", r.src_ip, r.src_port, r.dst_ip, r.dst_port);
|
|
||||||
|
|
||||||
bool res;
|
|
||||||
if(l.src_ip != r.src_ip)
|
|
||||||
res = (l.src_ip < r.src_ip);
|
|
||||||
else if(l.dst_ip != r.dst_ip)
|
|
||||||
res = (l.dst_ip < r.dst_ip);
|
|
||||||
else if(l.src_port != r.src_port)
|
|
||||||
res = (l.src_port < r.src_port);
|
|
||||||
else
|
|
||||||
res = (l.dst_port < r.dst_port);
|
|
||||||
if(res)
|
|
||||||
printf(": True\n");
|
|
||||||
else
|
|
||||||
printf(": False\n");*/
|
|
||||||
|
|
||||||
|
|
||||||
if(l.src_ip != r.src_ip)
|
|
||||||
return(l.src_ip < r.src_ip);
|
|
||||||
if(l.dst_ip != r.dst_ip)
|
|
||||||
return(l.dst_ip < r.dst_ip);
|
|
||||||
if(l.src_port != r.src_port)
|
|
||||||
return(l.src_port < r.src_port);
|
|
||||||
return(l.dst_port < r.dst_port);
|
|
||||||
|
|
||||||
/* //so, this turned out uglier than I had hoped
|
|
||||||
if(l.src_ip < r.src_ip)
|
|
||||||
return(true);
|
|
||||||
if(l.src_ip > r.src_ip)
|
|
||||||
return(false);
|
|
||||||
if(l.dst_ip < r.dst_ip)
|
|
||||||
return(true);
|
|
||||||
if(l.dst_ip > r.dst_ip)
|
|
||||||
return(false);
|
|
||||||
if(l.src_port < r.src_port)
|
|
||||||
return(true);
|
|
||||||
if(l.src_port > r.src_port)
|
|
||||||
return(false);
|
|
||||||
return(l.dst_port < r.dst_port);*/
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool operator==(const EQStreamInfo &l, const EQStreamInfo &r) {
|
|
||||||
// if(l.src_ip == r.dest_ip) {
|
|
||||||
// //maybe swapped
|
|
||||||
// return(l.src_port == r.dst_port && l.dst_ip == r.src_ip && l.dst_port == r.src_port);
|
|
||||||
// }
|
|
||||||
return(l.src_ip == r.src_ip && l.src_port == r.src_port && l.dst_ip == r.dst_ip && l.dst_port == r.dst_port);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Forces the pointer T thing so we can return nullptr
|
|
||||||
template <class T>
|
|
||||||
class EQStreamLocator {
|
|
||||||
protected:
|
|
||||||
typedef typename std::map<const EQStreamInfo, T *>::iterator iterator;
|
|
||||||
public:
|
|
||||||
|
|
||||||
void Clear() {
|
|
||||||
streams.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddStream(const EQStreamInfo &i, T *o) {
|
|
||||||
//do we care to check if it exists?
|
|
||||||
|
|
||||||
//add this stream, and its inverse
|
|
||||||
streams[i] = o;
|
|
||||||
EQStreamInfo inv;
|
|
||||||
i.invert(inv);
|
|
||||||
streams[inv] = o;
|
|
||||||
}
|
|
||||||
|
|
||||||
//deletes this stream, and its inverse
|
|
||||||
void RemoveStream(const EQStreamInfo &i) {
|
|
||||||
iterator res;
|
|
||||||
res = streams.find(i);
|
|
||||||
if(res != streams.end())
|
|
||||||
streams.erase(res);
|
|
||||||
|
|
||||||
EQStreamInfo inv;
|
|
||||||
i.invert(inv);
|
|
||||||
res = streams.find(inv);
|
|
||||||
if(res != streams.end())
|
|
||||||
streams.erase(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
//removes every occurance of this stream from the list
|
|
||||||
void RemoveStream(T *it) {
|
|
||||||
iterator cur, end;
|
|
||||||
cur = streams.begin();
|
|
||||||
end = streams.end();
|
|
||||||
for(; cur != end; ++cur) {
|
|
||||||
if(cur->second == it) {
|
|
||||||
streams.erase(cur);
|
|
||||||
//lazy recursive delete for now, since we have to redo
|
|
||||||
//our iterators anyways
|
|
||||||
RemoveStream(it);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
T *GetStream(const EQStreamInfo &i) {
|
|
||||||
iterator res;
|
|
||||||
res = streams.find(i);
|
|
||||||
//possibly optimization would be to store streams.end(), since it
|
|
||||||
//may not be a constant time operation in theory, and update our
|
|
||||||
//stored copy only on insert or delete
|
|
||||||
if(res == streams.end())
|
|
||||||
return(nullptr);
|
|
||||||
return(res->second);
|
|
||||||
}
|
|
||||||
|
|
||||||
//allow people to iterate over the const struct
|
|
||||||
// typedef map<const EQStreamInfo, T *>::const_iterator iterator;
|
|
||||||
// inline iterator begin() const { return(streams.begin()); }
|
|
||||||
// inline iterator end() const { return(streams.end()); }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
std::map<const EQStreamInfo, T *> streams;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
|
|
||||||
#include "debug.h"
|
|
||||||
#include "EQStreamProxy.h"
|
|
||||||
#include "EQStream.h"
|
|
||||||
#include "StructStrategy.h"
|
|
||||||
|
|
||||||
|
|
||||||
EQStreamProxy::EQStreamProxy(EQStream *&stream, const StructStrategy *structs, OpcodeManager **opcodes)
|
|
||||||
: m_stream(stream),
|
|
||||||
m_structs(structs),
|
|
||||||
m_opcodes(opcodes)
|
|
||||||
{
|
|
||||||
stream = nullptr; //take the stream.
|
|
||||||
m_stream->SetOpcodeManager(m_opcodes);
|
|
||||||
}
|
|
||||||
|
|
||||||
EQStreamProxy::~EQStreamProxy() {
|
|
||||||
//delete m_stream; //released by the stream factory.
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string EQStreamProxy::Describe() const {
|
|
||||||
return(m_structs->Describe());
|
|
||||||
}
|
|
||||||
|
|
||||||
const EQClientVersion EQStreamProxy::ClientVersion() const
|
|
||||||
{
|
|
||||||
return m_structs->ClientVersion();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQStreamProxy::QueuePacket(const EQApplicationPacket *p, bool ack_req) {
|
|
||||||
if(p == nullptr)
|
|
||||||
return;
|
|
||||||
|
|
||||||
EQApplicationPacket *newp = p->Copy();
|
|
||||||
FastQueuePacket(&newp, ack_req);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQStreamProxy::FastQueuePacket(EQApplicationPacket **p, bool ack_req) {
|
|
||||||
if(p == nullptr || *p == nullptr)
|
|
||||||
return;
|
|
||||||
m_structs->Encode(p, m_stream, ack_req);
|
|
||||||
}
|
|
||||||
|
|
||||||
EQApplicationPacket *EQStreamProxy::PopPacket() {
|
|
||||||
EQApplicationPacket *pack = m_stream->PopPacket();
|
|
||||||
if(pack == nullptr)
|
|
||||||
return(nullptr);
|
|
||||||
|
|
||||||
//pass this packet through the struct strategy.
|
|
||||||
m_structs->Decode(pack);
|
|
||||||
return(pack);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQStreamProxy::Close() {
|
|
||||||
m_stream->Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 EQStreamProxy::GetRemoteIP() const {
|
|
||||||
return(m_stream->GetRemoteIP());
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16 EQStreamProxy::GetRemotePort() const {
|
|
||||||
return(m_stream->GetRemotePort());
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint32 EQStreamProxy::GetBytesSent() const
|
|
||||||
{
|
|
||||||
return(m_stream->GetBytesSent());
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint32 EQStreamProxy::GetBytesRecieved() const
|
|
||||||
{
|
|
||||||
return(m_stream->GetBytesRecieved());
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint32 EQStreamProxy::GetBytesSentPerSecond() const
|
|
||||||
{
|
|
||||||
return(m_stream->GetBytesSentPerSecond());
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint32 EQStreamProxy::GetBytesRecvPerSecond() const
|
|
||||||
{
|
|
||||||
return(m_stream->GetBytesRecvPerSecond());
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQStreamProxy::ReleaseFromUse() {
|
|
||||||
m_stream->ReleaseFromUse();
|
|
||||||
|
|
||||||
//this is so ugly, but I cant think of a better way to deal with
|
|
||||||
//it right now...
|
|
||||||
if(!m_stream->IsInUse()) {
|
|
||||||
delete this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQStreamProxy::RemoveData() {
|
|
||||||
m_stream->RemoveData();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EQStreamProxy::CheckState(EQStreamState state) {
|
|
||||||
if(m_stream)
|
|
||||||
return(m_stream->CheckState(state));
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
#ifndef EQSTREAMPROXY_H_
|
|
||||||
#define EQSTREAMPROXY_H_
|
|
||||||
|
|
||||||
|
|
||||||
#include "types.h"
|
|
||||||
#include "EQStreamIntf.h"
|
|
||||||
|
|
||||||
class EQStream;
|
|
||||||
class StructStrategy;
|
|
||||||
class OpcodeManager;
|
|
||||||
class EQApplicationPacket;
|
|
||||||
|
|
||||||
class EQStreamProxy : public EQStreamInterface {
|
|
||||||
public:
|
|
||||||
//takes ownership of the stream.
|
|
||||||
EQStreamProxy(EQStream *&stream, const StructStrategy *structs, OpcodeManager **opcodes);
|
|
||||||
virtual ~EQStreamProxy();
|
|
||||||
|
|
||||||
//EQStreamInterface:
|
|
||||||
virtual void QueuePacket(const EQApplicationPacket *p, bool ack_req=true);
|
|
||||||
virtual void FastQueuePacket(EQApplicationPacket **p, bool ack_req=true);
|
|
||||||
virtual EQApplicationPacket *PopPacket();
|
|
||||||
virtual void Close();
|
|
||||||
virtual uint32 GetRemoteIP() const;
|
|
||||||
virtual uint16 GetRemotePort() const;
|
|
||||||
virtual void ReleaseFromUse();
|
|
||||||
virtual void RemoveData();
|
|
||||||
virtual bool CheckState(EQStreamState state);
|
|
||||||
virtual std::string Describe() const;
|
|
||||||
virtual const EQClientVersion ClientVersion() const;
|
|
||||||
|
|
||||||
virtual const uint32 GetBytesSent() const;
|
|
||||||
virtual const uint32 GetBytesRecieved() const;
|
|
||||||
virtual const uint32 GetBytesSentPerSecond() const;
|
|
||||||
virtual const uint32 GetBytesRecvPerSecond() const;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
EQStream *const m_stream; //we own this stream object.
|
|
||||||
const StructStrategy *const m_structs; //we do not own this object.
|
|
||||||
//this is a pointer to a pointer to make it less likely that a packet will
|
|
||||||
//reference an invalid opcode manager when they are being reloaded.
|
|
||||||
OpcodeManager **const m_opcodes; //we do not own this object.
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /*EQSTREAMPROXY_H_*/
|
|
||||||
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
#ifndef _EQSTREAMTYPE_H
|
|
||||||
#define _EQSTREAMTYPE_H
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
UnknownStream=0,
|
|
||||||
LoginStream,
|
|
||||||
WorldStream,
|
|
||||||
ZoneStream,
|
|
||||||
ChatOrMailStream,
|
|
||||||
ChatStream,
|
|
||||||
MailStream
|
|
||||||
} EQStreamType;
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,820 +0,0 @@
|
|||||||
/* EQEMu: Everquest Server Emulator
|
|
||||||
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
|
|
||||||
|
|
||||||
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; version 2 of the License.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
||||||
are required to give you total support for your newly bought product;
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
There are really two or three different objects shoe-hored into this
|
|
||||||
connection object. Sombody really needs to factor out the relay link
|
|
||||||
crap into its own subclass of this object, it will clean things up
|
|
||||||
tremendously.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "../common/debug.h"
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <iomanip>
|
|
||||||
|
|
||||||
#include "EmuTCPConnection.h"
|
|
||||||
#include "EmuTCPServer.h"
|
|
||||||
#include "../common/servertalk.h"
|
|
||||||
#include "../common/packet_dump.h"
|
|
||||||
|
|
||||||
#ifdef FREEBSD //Timothy Whitman - January 7, 2003
|
|
||||||
#define MSG_NOSIGNAL 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define TCPN_DEBUG 0
|
|
||||||
#define TCPN_DEBUG_Console 0
|
|
||||||
#define TCPN_DEBUG_Memory 0
|
|
||||||
#define TCPN_LOG_PACKETS 0
|
|
||||||
#define TCPN_LOG_RAW_DATA_OUT 0
|
|
||||||
#define TCPN_LOG_RAW_DATA_IN 0
|
|
||||||
|
|
||||||
|
|
||||||
//server side case
|
|
||||||
EmuTCPConnection::EmuTCPConnection(uint32 ID, EmuTCPServer* iServer, SOCKET in_socket, uint32 irIP, uint16 irPort, bool iOldFormat)
|
|
||||||
: TCPConnection(ID, in_socket, irIP, irPort),
|
|
||||||
keepalive_timer(SERVER_TIMEOUT),
|
|
||||||
timeout_timer(SERVER_TIMEOUT * 2)
|
|
||||||
{
|
|
||||||
id = 0;
|
|
||||||
Server = nullptr;
|
|
||||||
pOldFormat = iOldFormat;
|
|
||||||
#ifdef MINILOGIN
|
|
||||||
TCPMode = modePacket;
|
|
||||||
PacketMode = packetModeLogin;
|
|
||||||
#else
|
|
||||||
if (pOldFormat)
|
|
||||||
TCPMode = modePacket;
|
|
||||||
else
|
|
||||||
TCPMode = modeConsole;
|
|
||||||
PacketMode = packetModeZone;
|
|
||||||
#endif
|
|
||||||
RelayLink = 0;
|
|
||||||
RelayServer = false;
|
|
||||||
RelayCount = 0;
|
|
||||||
RemoteID = 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//client outgoing connection case (and client side relay)
|
|
||||||
EmuTCPConnection::EmuTCPConnection(bool iOldFormat, EmuTCPServer* iRelayServer, eTCPMode iMode)
|
|
||||||
: TCPConnection(),
|
|
||||||
keepalive_timer(SERVER_TIMEOUT),
|
|
||||||
timeout_timer(SERVER_TIMEOUT * 2)
|
|
||||||
{
|
|
||||||
Server = iRelayServer;
|
|
||||||
if (Server)
|
|
||||||
RelayServer = true;
|
|
||||||
else
|
|
||||||
RelayServer = false;
|
|
||||||
RelayLink = 0;
|
|
||||||
RelayCount = 0;
|
|
||||||
RemoteID = 0;
|
|
||||||
pOldFormat = iOldFormat;
|
|
||||||
TCPMode = iMode;
|
|
||||||
PacketMode = packetModeZone;
|
|
||||||
#if TCPN_DEBUG_Memory >= 7
|
|
||||||
std::cout << "Constructor #1 on outgoing TCP# " << GetID() << std::endl;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
//server side relay case
|
|
||||||
EmuTCPConnection::EmuTCPConnection(uint32 ID, EmuTCPServer* iServer, EmuTCPConnection* iRelayLink, uint32 iRemoteID, uint32 irIP, uint16 irPort)
|
|
||||||
: TCPConnection(ID, 0, irIP, irPort),
|
|
||||||
keepalive_timer(SERVER_TIMEOUT),
|
|
||||||
timeout_timer(SERVER_TIMEOUT * 2)
|
|
||||||
{
|
|
||||||
Server = iServer;
|
|
||||||
RelayLink = iRelayLink;
|
|
||||||
RelayServer = true;
|
|
||||||
RelayCount = 0;
|
|
||||||
RemoteID = iRemoteID;
|
|
||||||
pOldFormat = false;
|
|
||||||
ConnectionType = Incomming;
|
|
||||||
TCPMode = modePacket;
|
|
||||||
PacketMode = packetModeZone;
|
|
||||||
#if TCPN_DEBUG_Memory >= 7
|
|
||||||
std::cout << "Constructor #3 on outgoing TCP# " << GetID() << std::endl;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
EmuTCPConnection::~EmuTCPConnection() {
|
|
||||||
//the queues free their content right now I believe.
|
|
||||||
}
|
|
||||||
|
|
||||||
EmuTCPNetPacket_Struct* EmuTCPConnection::MakePacket(ServerPacket* pack, uint32 iDestination) {
|
|
||||||
int32 size = sizeof(EmuTCPNetPacket_Struct) + pack->size;
|
|
||||||
if (pack->compressed) {
|
|
||||||
size += 4;
|
|
||||||
}
|
|
||||||
if (iDestination) {
|
|
||||||
size += 4;
|
|
||||||
}
|
|
||||||
EmuTCPNetPacket_Struct* tnps = (EmuTCPNetPacket_Struct*) new uchar[size];
|
|
||||||
tnps->size = size;
|
|
||||||
tnps->opcode = pack->opcode;
|
|
||||||
*((uint8*) &tnps->flags) = 0;
|
|
||||||
uchar* buffer = tnps->buffer;
|
|
||||||
if (pack->compressed) {
|
|
||||||
tnps->flags.compressed = 1;
|
|
||||||
*((int32*) buffer) = pack->InflatedSize;
|
|
||||||
buffer += 4;
|
|
||||||
}
|
|
||||||
if (iDestination) {
|
|
||||||
tnps->flags.destination = 1;
|
|
||||||
*((int32*) buffer) = iDestination;
|
|
||||||
buffer += 4;
|
|
||||||
}
|
|
||||||
memcpy(buffer, pack->pBuffer, pack->size);
|
|
||||||
return tnps;
|
|
||||||
}
|
|
||||||
|
|
||||||
SPackSendQueue* EmuTCPConnection::MakeOldPacket(ServerPacket* pack) {
|
|
||||||
SPackSendQueue* spsq = (SPackSendQueue*) new uchar[sizeof(SPackSendQueue) + pack->size + 4];
|
|
||||||
if (pack->pBuffer != 0 && pack->size != 0)
|
|
||||||
memcpy((char *) &spsq->buffer[4], (char *) pack->pBuffer, pack->size);
|
|
||||||
memcpy((char *) &spsq->buffer[0], (char *) &pack->opcode, 2);
|
|
||||||
spsq->size = pack->size+4;
|
|
||||||
memcpy((char *) &spsq->buffer[2], (char *) &spsq->size, 2);
|
|
||||||
return spsq;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EmuTCPConnection::SendPacket(ServerPacket* pack, uint32 iDestination) {
|
|
||||||
if (!Connected())
|
|
||||||
return false;
|
|
||||||
eTCPMode tmp = GetMode();
|
|
||||||
if (tmp != modePacket && tmp != modeTransition)
|
|
||||||
return false;
|
|
||||||
LockMutex lock(&MState);
|
|
||||||
if (RemoteID)
|
|
||||||
return RelayLink->SendPacket(pack, RemoteID);
|
|
||||||
else if (pOldFormat) {
|
|
||||||
#if TCPN_LOG_PACKETS >= 1
|
|
||||||
if (pack && pack->opcode != 0) {
|
|
||||||
struct in_addr in;
|
|
||||||
in.s_addr = GetrIP();
|
|
||||||
CoutTimestamp(true);
|
|
||||||
std::cout << ": Logging outgoing TCP OldPacket. OPCode: 0x" << std::hex << std::setw(4) << std::setfill('0') << pack->opcode << std::dec << ", size: " << std::setw(5) << std::setfill(' ') << pack->size << " " << inet_ntoa(in) << ":" << GetrPort() << std::endl;
|
|
||||||
#if TCPN_LOG_PACKETS == 2
|
|
||||||
if (pack->size >= 32)
|
|
||||||
DumpPacket(pack->pBuffer, 32);
|
|
||||||
else
|
|
||||||
DumpPacket(pack);
|
|
||||||
#endif
|
|
||||||
#if TCPN_LOG_PACKETS >= 3
|
|
||||||
DumpPacket(pack);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
SPackSendQueue* spsq = MakeOldPacket(pack);
|
|
||||||
ServerSendQueuePushEnd(spsq->buffer, spsq->size);
|
|
||||||
safe_delete_array(spsq);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
EmuTCPNetPacket_Struct* tnps = MakePacket(pack, iDestination);
|
|
||||||
if (tmp == modeTransition) {
|
|
||||||
InModeQueuePush(tnps);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
#if TCPN_LOG_PACKETS >= 1
|
|
||||||
if (pack && pack->opcode != 0) {
|
|
||||||
struct in_addr in;
|
|
||||||
in.s_addr = GetrIP();
|
|
||||||
CoutTimestamp(true);
|
|
||||||
std::cout << ": Logging outgoing TCP packet. OPCode: 0x" << std::hex << std::setw(4) << std::setfill('0') << pack->opcode << std::dec << ", size: " << std::setw(5) << std::setfill(' ') << pack->size << " " << inet_ntoa(in) << ":" << GetrPort() << std::endl;
|
|
||||||
#if TCPN_LOG_PACKETS == 2
|
|
||||||
if (pack->size >= 32)
|
|
||||||
DumpPacket(pack->pBuffer, 32);
|
|
||||||
else
|
|
||||||
DumpPacket(pack);
|
|
||||||
#endif
|
|
||||||
#if TCPN_LOG_PACKETS >= 3
|
|
||||||
DumpPacket(pack);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
ServerSendQueuePushEnd((uchar**) &tnps, tnps->size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EmuTCPConnection::SendPacket(EmuTCPNetPacket_Struct* tnps) {
|
|
||||||
if (RemoteID)
|
|
||||||
return false;
|
|
||||||
if (!Connected())
|
|
||||||
return false;
|
|
||||||
if (GetMode() != modePacket)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
LockMutex lock(&MState);
|
|
||||||
eTCPMode tmp = GetMode();
|
|
||||||
if (tmp == modeTransition) {
|
|
||||||
EmuTCPNetPacket_Struct* tnps2 = (EmuTCPNetPacket_Struct*) new uchar[tnps->size];
|
|
||||||
memcpy(tnps2, tnps, tnps->size);
|
|
||||||
InModeQueuePush(tnps2);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#if TCPN_LOG_PACKETS >= 1
|
|
||||||
if (tnps && tnps->opcode != 0) {
|
|
||||||
struct in_addr in;
|
|
||||||
in.s_addr = GetrIP();
|
|
||||||
CoutTimestamp(true);
|
|
||||||
std::cout << ": Logging outgoing TCP NetPacket. OPCode: 0x" << std::hex << std::setw(4) << std::setfill('0') << tnps->opcode << std::dec << ", size: " << std::setw(5) << std::setfill(' ') << tnps->size << " " << inet_ntoa(in) << ":" << GetrPort();
|
|
||||||
if (pOldFormat)
|
|
||||||
std::cout << " (OldFormat)";
|
|
||||||
std::cout << std::endl;
|
|
||||||
#if TCPN_LOG_PACKETS == 2
|
|
||||||
if (tnps->size >= 32)
|
|
||||||
DumpPacket((uchar*) tnps, 32);
|
|
||||||
else
|
|
||||||
DumpPacket((uchar*) tnps, tnps->size);
|
|
||||||
#endif
|
|
||||||
#if TCPN_LOG_PACKETS >= 3
|
|
||||||
DumpPacket((uchar*) tnps, tnps->size);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
ServerSendQueuePushEnd((const uchar*) tnps, tnps->size);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ServerPacket* EmuTCPConnection::PopPacket() {
|
|
||||||
ServerPacket* ret;
|
|
||||||
if (!MOutQueueLock.trylock())
|
|
||||||
return nullptr;
|
|
||||||
ret = OutQueue.pop();
|
|
||||||
MOutQueueLock.unlock();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmuTCPConnection::InModeQueuePush(EmuTCPNetPacket_Struct* tnps) {
|
|
||||||
MSendQueue.lock();
|
|
||||||
InModeQueue.push(tnps);
|
|
||||||
MSendQueue.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmuTCPConnection::OutQueuePush(ServerPacket* pack) {
|
|
||||||
MOutQueueLock.lock();
|
|
||||||
OutQueue.push(pack);
|
|
||||||
MOutQueueLock.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool EmuTCPConnection::LineOutQueuePush(char* line) {
|
|
||||||
#if defined(GOTFRAGS) && 0
|
|
||||||
if (strcmp(line, "**CRASHME**") == 0) {
|
|
||||||
int i = 0;
|
|
||||||
std::cout << (5 / i) << std::endl;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if(line[0] == '*') {
|
|
||||||
if (strcmp(line, "**PACKETMODE**") == 0) {
|
|
||||||
MSendQueue.lock();
|
|
||||||
safe_delete_array(sendbuf);
|
|
||||||
if (TCPMode == modeConsole)
|
|
||||||
Send((const uchar*) "\0**PACKETMODE**\r", 16);
|
|
||||||
TCPMode = modePacket;
|
|
||||||
PacketMode = packetModeLogin;
|
|
||||||
EmuTCPNetPacket_Struct* tnps = 0;
|
|
||||||
while ((tnps = InModeQueue.pop())) {
|
|
||||||
SendPacket(tnps);
|
|
||||||
safe_delete_array(tnps);
|
|
||||||
}
|
|
||||||
MSendQueue.unlock();
|
|
||||||
safe_delete_array(line);
|
|
||||||
return(true);
|
|
||||||
}
|
|
||||||
if (strcmp(line, "**PACKETMODEZONE**") == 0) {
|
|
||||||
MSendQueue.lock();
|
|
||||||
safe_delete_array(sendbuf);
|
|
||||||
if (TCPMode == modeConsole)
|
|
||||||
Send((const uchar*) "\0**PACKETMODEZONE**\r", 20);
|
|
||||||
TCPMode = modePacket;
|
|
||||||
PacketMode = packetModeZone;
|
|
||||||
EmuTCPNetPacket_Struct* tnps = 0;
|
|
||||||
while ((tnps = InModeQueue.pop())) {
|
|
||||||
SendPacket(tnps);
|
|
||||||
safe_delete_array(tnps);
|
|
||||||
}
|
|
||||||
MSendQueue.unlock();
|
|
||||||
safe_delete_array(line);
|
|
||||||
return(true);
|
|
||||||
}
|
|
||||||
if (strcmp(line, "**PACKETMODELAUNCHER**") == 0) {
|
|
||||||
MSendQueue.lock();
|
|
||||||
safe_delete_array(sendbuf);
|
|
||||||
if (TCPMode == modeConsole)
|
|
||||||
Send((const uchar*) "\0**PACKETMODELAUNCHER**\r", 24);
|
|
||||||
TCPMode = modePacket;
|
|
||||||
PacketMode = packetModeLauncher;
|
|
||||||
EmuTCPNetPacket_Struct* tnps = 0;
|
|
||||||
while ((tnps = InModeQueue.pop())) {
|
|
||||||
SendPacket(tnps);
|
|
||||||
safe_delete_array(tnps);
|
|
||||||
}
|
|
||||||
MSendQueue.unlock();
|
|
||||||
safe_delete_array(line);
|
|
||||||
return(true);
|
|
||||||
}
|
|
||||||
if (strcmp(line, "**PACKETMODEUCS**") == 0) {
|
|
||||||
MSendQueue.lock();
|
|
||||||
safe_delete_array(sendbuf);
|
|
||||||
if (TCPMode == modeConsole)
|
|
||||||
Send((const uchar*) "\0**PACKETMODEUCS**\r", 19);
|
|
||||||
TCPMode = modePacket;
|
|
||||||
PacketMode = packetModeUCS;
|
|
||||||
EmuTCPNetPacket_Struct* tnps = 0;
|
|
||||||
while ((tnps = InModeQueue.pop())) {
|
|
||||||
SendPacket(tnps);
|
|
||||||
safe_delete_array(tnps);
|
|
||||||
}
|
|
||||||
MSendQueue.unlock();
|
|
||||||
safe_delete_array(line);
|
|
||||||
return(true);
|
|
||||||
}
|
|
||||||
if (strcmp(line, "**PACKETMODEQS**") == 0) {
|
|
||||||
MSendQueue.lock();
|
|
||||||
safe_delete_array(sendbuf);
|
|
||||||
if (TCPMode == modeConsole)
|
|
||||||
Send((const uchar*) "\0**PACKETMODEQS**\r", 18);
|
|
||||||
TCPMode = modePacket;
|
|
||||||
PacketMode = packetModeQueryServ;
|
|
||||||
EmuTCPNetPacket_Struct* tnps = 0;
|
|
||||||
while ((tnps = InModeQueue.pop())) {
|
|
||||||
SendPacket(tnps);
|
|
||||||
safe_delete_array(tnps);
|
|
||||||
}
|
|
||||||
MSendQueue.unlock();
|
|
||||||
safe_delete_array(line);
|
|
||||||
return(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return(TCPConnection::LineOutQueuePush(line));
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmuTCPConnection::Disconnect(bool iSendRelayDisconnect) {
|
|
||||||
TCPConnection::Disconnect();
|
|
||||||
|
|
||||||
if (RelayLink) {
|
|
||||||
RelayLink->RemoveRelay(this, iSendRelayDisconnect);
|
|
||||||
RelayLink = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EmuTCPConnection::ConnectIP(uint32 irIP, uint16 irPort, char* errbuf) {
|
|
||||||
if(!TCPConnection::ConnectIP(irIP, irPort, errbuf))
|
|
||||||
return(false);
|
|
||||||
|
|
||||||
MSendQueue.lock();
|
|
||||||
#ifdef MINILOGIN
|
|
||||||
TCPMode = modePacket;
|
|
||||||
#else
|
|
||||||
if (pOldFormat) {
|
|
||||||
TCPMode = modePacket;
|
|
||||||
}
|
|
||||||
else if (TCPMode == modePacket || TCPMode == modeTransition) {
|
|
||||||
TCPMode = modeTransition;
|
|
||||||
if(PacketMode == packetModeLauncher) {
|
|
||||||
safe_delete_array(sendbuf);
|
|
||||||
sendbuf_size = 24;
|
|
||||||
sendbuf_used = sendbuf_size;
|
|
||||||
sendbuf = new uchar[sendbuf_size];
|
|
||||||
memcpy(sendbuf, "\0**PACKETMODELAUNCHER**\r", sendbuf_size);
|
|
||||||
} else if(PacketMode == packetModeLogin) {
|
|
||||||
safe_delete_array(sendbuf);
|
|
||||||
sendbuf_size = 16;
|
|
||||||
sendbuf_used = sendbuf_size;
|
|
||||||
sendbuf = new uchar[sendbuf_size];
|
|
||||||
memcpy(sendbuf, "\0**PACKETMODE**\r", sendbuf_size);
|
|
||||||
} else if(PacketMode == packetModeUCS) {
|
|
||||||
safe_delete_array(sendbuf);
|
|
||||||
sendbuf_size = 19;
|
|
||||||
sendbuf_used = sendbuf_size;
|
|
||||||
sendbuf = new uchar[sendbuf_size];
|
|
||||||
memcpy(sendbuf, "\0**PACKETMODEUCS**\r", sendbuf_size);
|
|
||||||
}
|
|
||||||
else if(PacketMode == packetModeQueryServ) {
|
|
||||||
safe_delete_array(sendbuf);
|
|
||||||
sendbuf_size = 18;
|
|
||||||
sendbuf_used = sendbuf_size;
|
|
||||||
sendbuf = new uchar[sendbuf_size];
|
|
||||||
memcpy(sendbuf, "\0**PACKETMODEQS**\r", sendbuf_size);
|
|
||||||
} else {
|
|
||||||
//default: packetModeZone
|
|
||||||
safe_delete_array(sendbuf);
|
|
||||||
sendbuf_size = 20;
|
|
||||||
sendbuf_used = sendbuf_size;
|
|
||||||
sendbuf = new uchar[sendbuf_size];
|
|
||||||
memcpy(sendbuf, "\0**PACKETMODEZONE**\r", sendbuf_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
MSendQueue.unlock();
|
|
||||||
|
|
||||||
return(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmuTCPConnection::ClearBuffers() {
|
|
||||||
TCPConnection::ClearBuffers();
|
|
||||||
|
|
||||||
LockMutex lock2(&MOutQueueLock);
|
|
||||||
ServerPacket* pack = 0;
|
|
||||||
while ((pack = OutQueue.pop()))
|
|
||||||
safe_delete(pack);
|
|
||||||
|
|
||||||
EmuTCPNetPacket_Struct* tnps = 0;
|
|
||||||
while ((tnps = InModeQueue.pop()))
|
|
||||||
safe_delete(tnps);
|
|
||||||
|
|
||||||
keepalive_timer.Start();
|
|
||||||
timeout_timer.Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmuTCPConnection::SendNetErrorPacket(const char* reason) {
|
|
||||||
#if TCPC_DEBUG >= 1
|
|
||||||
struct in_addr in;
|
|
||||||
in.s_addr = GetrIP();
|
|
||||||
std::cout "NetError: '";
|
|
||||||
if (reason)
|
|
||||||
std::cout << reason;
|
|
||||||
std::cout << "': " << inet_ntoa(in) << ":" << GetPort() << std::endl;
|
|
||||||
#endif
|
|
||||||
ServerPacket* pack = new ServerPacket(0);
|
|
||||||
pack->size = 1;
|
|
||||||
if (reason)
|
|
||||||
pack->size += strlen(reason) + 1;
|
|
||||||
pack->pBuffer = new uchar[pack->size];
|
|
||||||
memset(pack->pBuffer, 0, pack->size);
|
|
||||||
pack->pBuffer[0] = 255;
|
|
||||||
strcpy((char*) &pack->pBuffer[1], reason);
|
|
||||||
SendPacket(pack);
|
|
||||||
safe_delete(pack);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmuTCPConnection::RemoveRelay(EmuTCPConnection* relay, bool iSendRelayDisconnect) {
|
|
||||||
if (iSendRelayDisconnect) {
|
|
||||||
ServerPacket* pack = new ServerPacket(0, 5);
|
|
||||||
pack->pBuffer[0] = 3;
|
|
||||||
*((uint32*) &pack->pBuffer[1]) = relay->GetRemoteID();
|
|
||||||
SendPacket(pack);
|
|
||||||
safe_delete(pack);
|
|
||||||
}
|
|
||||||
RelayCount--;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool EmuTCPConnection::ProcessReceivedData(char* errbuf) {
|
|
||||||
if (errbuf)
|
|
||||||
errbuf[0] = 0;
|
|
||||||
timeout_timer.Start();
|
|
||||||
if (!recvbuf)
|
|
||||||
return true;
|
|
||||||
if (TCPMode == modePacket) {
|
|
||||||
if (pOldFormat)
|
|
||||||
return ProcessReceivedDataAsOldPackets(errbuf);
|
|
||||||
else
|
|
||||||
return ProcessReceivedDataAsPackets(errbuf);
|
|
||||||
}
|
|
||||||
//else, use the base class's text processing.
|
|
||||||
bool ret = TCPConnection::ProcessReceivedData(errbuf);
|
|
||||||
//see if we made the transition to packet mode...
|
|
||||||
if(ret && TCPMode == modePacket) {
|
|
||||||
return ProcessReceivedDataAsPackets(errbuf);
|
|
||||||
}
|
|
||||||
return(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool EmuTCPConnection::ProcessReceivedDataAsPackets(char* errbuf) {
|
|
||||||
if (errbuf)
|
|
||||||
errbuf[0] = 0;
|
|
||||||
int32 base = 0;
|
|
||||||
int32 size = 7;
|
|
||||||
uchar* buffer;
|
|
||||||
ServerPacket* pack = 0;
|
|
||||||
while ((recvbuf_used - base) >= size) {
|
|
||||||
EmuTCPNetPacket_Struct* tnps = (EmuTCPNetPacket_Struct*) &recvbuf[base];
|
|
||||||
buffer = tnps->buffer;
|
|
||||||
size = tnps->size;
|
|
||||||
if (size >= MaxTCPReceiveBuffferSize) {
|
|
||||||
#if TCPN_DEBUG_Memory >= 1
|
|
||||||
std::cout << "TCPConnection[" << GetID() << "]::ProcessReceivedDataAsPackets(): size[" << size << "] >= MaxTCPReceiveBuffferSize" << std::endl;
|
|
||||||
DumpPacket(&recvbuf[base], 16);
|
|
||||||
#endif
|
|
||||||
if (errbuf)
|
|
||||||
snprintf(errbuf, TCPConnection_ErrorBufferSize, "EmuTCPConnection::ProcessReceivedDataAsPackets(): size >= MaxTCPReceiveBuffferSize");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if ((recvbuf_used - base) >= size) {
|
|
||||||
// ok, we got enough data to make this packet!
|
|
||||||
pack = new ServerPacket;
|
|
||||||
pack->size = size - sizeof(EmuTCPNetPacket_Struct);
|
|
||||||
// read headers
|
|
||||||
pack->opcode = tnps->opcode;
|
|
||||||
if (tnps->flags.compressed) {
|
|
||||||
pack->compressed = true;
|
|
||||||
pack->InflatedSize = *((int32*)buffer);
|
|
||||||
pack->size -= 4;
|
|
||||||
buffer += 4;
|
|
||||||
}
|
|
||||||
if (tnps->flags.destination) {
|
|
||||||
pack->destination = *((int32*)buffer);
|
|
||||||
pack->size -= 4;
|
|
||||||
buffer += 4;
|
|
||||||
}
|
|
||||||
// end read headers
|
|
||||||
if (pack->size > 0) {
|
|
||||||
if (tnps->flags.compressed) {
|
|
||||||
// Lets decompress the packet here
|
|
||||||
pack->compressed = false;
|
|
||||||
pack->pBuffer = new uchar[pack->InflatedSize];
|
|
||||||
pack->size = InflatePacket(buffer, pack->size, pack->pBuffer, pack->InflatedSize);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
pack->pBuffer = new uchar[pack->size];
|
|
||||||
memcpy(pack->pBuffer, buffer, pack->size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (pack->opcode == 0) {
|
|
||||||
if (pack->size) {
|
|
||||||
#if TCPN_DEBUG >= 2
|
|
||||||
std::cout << "Received TCP Network layer packet" << std::endl;
|
|
||||||
#endif
|
|
||||||
ProcessNetworkLayerPacket(pack);
|
|
||||||
}
|
|
||||||
#if TCPN_DEBUG >= 5
|
|
||||||
else {
|
|
||||||
std::cout << "Received TCP keepalive packet. (opcode=0)" << std::endl;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
// keepalive, no need to process
|
|
||||||
safe_delete(pack);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
#if TCPN_LOG_PACKETS >= 1
|
|
||||||
if (pack && pack->opcode != 0) {
|
|
||||||
struct in_addr in;
|
|
||||||
in.s_addr = GetrIP();
|
|
||||||
CoutTimestamp(true);
|
|
||||||
std::cout << ": Logging incoming TCP packet. OPCode: 0x" << std::hex << std::setw(4) << std::setfill('0') << pack->opcode << std::dec << ", size: " << std::setw(5) << std::setfill(' ') << pack->size << " " << inet_ntoa(in) << ":" << GetrPort() << std::endl;
|
|
||||||
#if TCPN_LOG_PACKETS == 2
|
|
||||||
if (pack->size >= 32)
|
|
||||||
DumpPacket(pack->pBuffer, 32);
|
|
||||||
else
|
|
||||||
DumpPacket(pack);
|
|
||||||
#endif
|
|
||||||
#if TCPN_LOG_PACKETS >= 3
|
|
||||||
DumpPacket(pack);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (RelayServer && Server && pack->destination) {
|
|
||||||
EmuTCPConnection* con = Server->FindConnection(pack->destination);
|
|
||||||
if (!con) {
|
|
||||||
#if TCPN_DEBUG >= 1
|
|
||||||
std::cout << "Error relaying packet: con = 0" << std::endl;
|
|
||||||
#endif
|
|
||||||
safe_delete(pack);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
con->OutQueuePush(pack);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
OutQueuePush(pack);
|
|
||||||
}
|
|
||||||
base += size;
|
|
||||||
size = 7;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (base != 0) {
|
|
||||||
if (base >= recvbuf_used) {
|
|
||||||
safe_delete_array(recvbuf);
|
|
||||||
} else {
|
|
||||||
uchar* tmpbuf = new uchar[recvbuf_size - base];
|
|
||||||
memcpy(tmpbuf, &recvbuf[base], recvbuf_used - base);
|
|
||||||
safe_delete_array(recvbuf);
|
|
||||||
recvbuf = tmpbuf;
|
|
||||||
recvbuf_used -= base;
|
|
||||||
recvbuf_size -= base;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EmuTCPConnection::ProcessReceivedDataAsOldPackets(char* errbuf) {
|
|
||||||
int32 base = 0;
|
|
||||||
int32 size = 4;
|
|
||||||
uchar* buffer;
|
|
||||||
ServerPacket* pack = 0;
|
|
||||||
while ((recvbuf_used - base) >= size) {
|
|
||||||
buffer = &recvbuf[base];
|
|
||||||
memcpy(&size, &buffer[2], 2);
|
|
||||||
if (size >= MaxTCPReceiveBuffferSize) {
|
|
||||||
#if TCPN_DEBUG_Memory >= 1
|
|
||||||
std::cout << "TCPConnection[" << GetID() << "]::ProcessReceivedDataAsPackets(): size[" << size << "] >= MaxTCPReceiveBuffferSize" << std::endl;
|
|
||||||
#endif
|
|
||||||
if (errbuf)
|
|
||||||
snprintf(errbuf, TCPConnection_ErrorBufferSize, "EmuTCPConnection::ProcessReceivedDataAsPackets(): size >= MaxTCPReceiveBuffferSize");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if ((recvbuf_used - base) >= size) {
|
|
||||||
// ok, we got enough data to make this packet!
|
|
||||||
pack = new ServerPacket;
|
|
||||||
memcpy(&pack->opcode, &buffer[0], 2);
|
|
||||||
pack->size = size - 4;
|
|
||||||
/* if () { // TODO: Checksum or size check or something similar
|
|
||||||
// Datastream corruption, get the hell outta here!
|
|
||||||
delete pack;
|
|
||||||
return false;
|
|
||||||
}*/
|
|
||||||
if (pack->size > 0) {
|
|
||||||
pack->pBuffer = new uchar[pack->size];
|
|
||||||
memcpy(pack->pBuffer, &buffer[4], pack->size);
|
|
||||||
}
|
|
||||||
if (pack->opcode == 0) {
|
|
||||||
// keepalive, no need to process
|
|
||||||
safe_delete(pack);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
#if TCPN_LOG_PACKETS >= 1
|
|
||||||
if (pack && pack->opcode != 0) {
|
|
||||||
struct in_addr in;
|
|
||||||
in.s_addr = GetrIP();
|
|
||||||
CoutTimestamp(true);
|
|
||||||
std::cout << ": Logging incoming TCP OldPacket. OPCode: 0x" << std::hex << std::setw(4) << std::setfill('0') << pack->opcode << std::dec << ", size: " << std::setw(5) << std::setfill(' ') << pack->size << " " << inet_ntoa(in) << ":" << GetrPort() << std::endl;
|
|
||||||
#if TCPN_LOG_PACKETS == 2
|
|
||||||
if (pack->size >= 32)
|
|
||||||
DumpPacket(pack->pBuffer, 32);
|
|
||||||
else
|
|
||||||
DumpPacket(pack);
|
|
||||||
#endif
|
|
||||||
#if TCPN_LOG_PACKETS >= 3
|
|
||||||
DumpPacket(pack);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
OutQueuePush(pack);
|
|
||||||
}
|
|
||||||
base += size;
|
|
||||||
size = 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (base != 0) {
|
|
||||||
if (base >= recvbuf_used) {
|
|
||||||
safe_delete_array(recvbuf);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
uchar* tmpbuf = new uchar[recvbuf_size - base];
|
|
||||||
memcpy(tmpbuf, &recvbuf[base], recvbuf_used - base);
|
|
||||||
safe_delete_array(recvbuf);
|
|
||||||
recvbuf = tmpbuf;
|
|
||||||
recvbuf_used -= base;
|
|
||||||
recvbuf_size -= base;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmuTCPConnection::ProcessNetworkLayerPacket(ServerPacket* pack) {
|
|
||||||
uint8 opcode = pack->pBuffer[0];
|
|
||||||
uint8* data = &pack->pBuffer[1];
|
|
||||||
switch (opcode) {
|
|
||||||
case 0: {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 1: { // Switch to RelayServer mode
|
|
||||||
if (pack->size != 1) {
|
|
||||||
SendNetErrorPacket("New RelayClient: wrong size, expected 1");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (RelayServer) {
|
|
||||||
SendNetErrorPacket("Switch to RelayServer mode when already in RelayServer mode");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (RemoteID) {
|
|
||||||
SendNetErrorPacket("Switch to RelayServer mode by a Relay Client");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (ConnectionType != Incomming) {
|
|
||||||
SendNetErrorPacket("Switch to RelayServer mode on outgoing connection");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#if TCPC_DEBUG >= 3
|
|
||||||
struct in_addr in;
|
|
||||||
in.s_addr = GetrIP();
|
|
||||||
std::cout << "Switching to RelayServer mode: " << inet_ntoa(in) << ":" << GetPort() << std::endl;
|
|
||||||
#endif
|
|
||||||
RelayServer = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 2: { // New Relay Client
|
|
||||||
if (!RelayServer) {
|
|
||||||
SendNetErrorPacket("New RelayClient when not in RelayServer mode");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (pack->size != 11) {
|
|
||||||
SendNetErrorPacket("New RelayClient: wrong size, expected 11");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (ConnectionType != Incomming) {
|
|
||||||
SendNetErrorPacket("New RelayClient: illegal on outgoing connection");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
EmuTCPConnection* con = new EmuTCPConnection(Server->GetNextID(), Server, this, *((uint32*) data), *((uint32*) &data[4]), *((uint16*) &data[8]));
|
|
||||||
Server->AddConnection(con);
|
|
||||||
RelayCount++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 3: { // Delete Relay Client
|
|
||||||
if (!RelayServer) {
|
|
||||||
SendNetErrorPacket("Delete RelayClient when not in RelayServer mode");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (pack->size != 5) {
|
|
||||||
SendNetErrorPacket("Delete RelayClient: wrong size, expected 5");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
EmuTCPConnection* con = Server->FindConnection(*((uint32*)data));
|
|
||||||
if (con) {
|
|
||||||
if (ConnectionType == Incomming) {
|
|
||||||
if (con->GetRelayLink() != this) {
|
|
||||||
SendNetErrorPacket("Delete RelayClient: RelayLink != this");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
con->Disconnect(false);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 255: {
|
|
||||||
#if TCPC_DEBUG >= 1
|
|
||||||
struct in_addr in;
|
|
||||||
in.s_addr = GetrIP();
|
|
||||||
std::cout "Received NetError: '";
|
|
||||||
if (pack->size > 1)
|
|
||||||
std::cout << (char*) data;
|
|
||||||
std::cout << "': " << inet_ntoa(in) << ":" << GetPort() << std::endl;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EmuTCPConnection::SendData(bool &sent_something, char* errbuf) {
|
|
||||||
sent_something = false;
|
|
||||||
if(!TCPConnection::SendData(sent_something, errbuf))
|
|
||||||
return(false);
|
|
||||||
|
|
||||||
if(sent_something)
|
|
||||||
keepalive_timer.Start();
|
|
||||||
else if (TCPMode == modePacket && keepalive_timer.Check()) {
|
|
||||||
ServerPacket* pack = new ServerPacket(0, 0);
|
|
||||||
SendPacket(pack);
|
|
||||||
safe_delete(pack);
|
|
||||||
#if TCPN_DEBUG >= 5
|
|
||||||
std::cout << "Sending TCP keepalive packet. (timeout=" << timeout_timer.GetRemainingTime() << " remaining)" << std::endl;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
return(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EmuTCPConnection::RecvData(char* errbuf) {
|
|
||||||
if(!TCPConnection::RecvData(errbuf)) {
|
|
||||||
if (OutQueue.count())
|
|
||||||
return(true);
|
|
||||||
else
|
|
||||||
return(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((TCPMode == modePacket || TCPMode == modeTransition) && timeout_timer.Check()) {
|
|
||||||
if (errbuf)
|
|
||||||
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::RecvData(): Connection timeout");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
#ifndef EmuTCPCONNECTION_H_
|
|
||||||
#define EmuTCPCONNECTION_H_
|
|
||||||
|
|
||||||
#include "TCPConnection.h"
|
|
||||||
#include "timer.h"
|
|
||||||
|
|
||||||
//moved out of TCPConnection:: to be more exportable
|
|
||||||
#pragma pack(1)
|
|
||||||
struct EmuTCPNetPacket_Struct {
|
|
||||||
uint32 size;
|
|
||||||
struct {
|
|
||||||
uint8
|
|
||||||
compressed : 1,
|
|
||||||
destination : 1,
|
|
||||||
flag3 : 1,
|
|
||||||
flag4 : 1,
|
|
||||||
flag5 : 1,
|
|
||||||
flag6 : 1,
|
|
||||||
flag7 : 1,
|
|
||||||
flag8 : 1;
|
|
||||||
} flags;
|
|
||||||
uint16 opcode;
|
|
||||||
uchar buffer[0];
|
|
||||||
};
|
|
||||||
#pragma pack()
|
|
||||||
|
|
||||||
struct SPackSendQueue;
|
|
||||||
class EmuTCPServer;
|
|
||||||
|
|
||||||
class EmuTCPConnection : public TCPConnection {
|
|
||||||
public:
|
|
||||||
enum eTCPMode { modeConsole, modeTransition, modePacket };
|
|
||||||
enum ePacketMode { packetModeZone, packetModeLauncher, packetModeLogin, packetModeUCS, packetModeQueryServ };
|
|
||||||
|
|
||||||
EmuTCPConnection(uint32 ID, EmuTCPServer* iServer, SOCKET iSock, uint32 irIP, uint16 irPort, bool iOldFormat = false);
|
|
||||||
EmuTCPConnection(bool iOldFormat = false, EmuTCPServer* iRelayServer = 0, eTCPMode iMode = modePacket); // for outgoing connections
|
|
||||||
EmuTCPConnection(uint32 ID, EmuTCPServer* iServer, EmuTCPConnection* iRelayLink, uint32 iRemoteID, uint32 irIP, uint16 irPort); // for relay connections
|
|
||||||
virtual ~EmuTCPConnection();
|
|
||||||
|
|
||||||
virtual bool ConnectIP(uint32 irIP, uint16 irPort, char* errbuf = 0);
|
|
||||||
virtual void Disconnect(bool iSendRelayDisconnect = true);
|
|
||||||
|
|
||||||
static EmuTCPNetPacket_Struct* MakePacket(ServerPacket* pack, uint32 iDestination = 0);
|
|
||||||
static SPackSendQueue* MakeOldPacket(ServerPacket* pack);
|
|
||||||
|
|
||||||
virtual bool SendPacket(ServerPacket* pack, uint32 iDestination = 0);
|
|
||||||
virtual bool SendPacket(EmuTCPNetPacket_Struct* tnps);
|
|
||||||
ServerPacket* PopPacket(); // OutQueuePop()
|
|
||||||
void SetPacketMode(ePacketMode mode) { PacketMode = mode; }
|
|
||||||
|
|
||||||
eTCPMode GetMode() const { return TCPMode; }
|
|
||||||
ePacketMode GetPacketMode() const { return(PacketMode); }
|
|
||||||
|
|
||||||
//relay crap:
|
|
||||||
inline bool IsRelayServer() const { return RelayServer; }
|
|
||||||
inline TCPConnection* GetRelayLink() const { return RelayLink; }
|
|
||||||
inline uint32 GetRemoteID() const { return RemoteID; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void OutQueuePush(ServerPacket* pack);
|
|
||||||
void RemoveRelay(EmuTCPConnection* relay, bool iSendRelayDisconnect);
|
|
||||||
|
|
||||||
void SendNetErrorPacket(const char* reason = 0);
|
|
||||||
|
|
||||||
virtual bool SendData(bool &sent_something, char* errbuf = 0);
|
|
||||||
virtual bool RecvData(char* errbuf = 0);
|
|
||||||
|
|
||||||
virtual bool ProcessReceivedData(char* errbuf = 0);
|
|
||||||
bool ProcessReceivedDataAsPackets(char* errbuf = 0);
|
|
||||||
bool ProcessReceivedDataAsOldPackets(char* errbuf = 0);
|
|
||||||
void ProcessNetworkLayerPacket(ServerPacket* pack);
|
|
||||||
|
|
||||||
virtual bool LineOutQueuePush(char* line);
|
|
||||||
virtual void ClearBuffers();
|
|
||||||
|
|
||||||
EmuTCPServer* Server;
|
|
||||||
|
|
||||||
eTCPMode TCPMode;
|
|
||||||
ePacketMode PacketMode;
|
|
||||||
bool pOldFormat;
|
|
||||||
|
|
||||||
Timer keepalive_timer;
|
|
||||||
Timer timeout_timer;
|
|
||||||
|
|
||||||
//relay crap:
|
|
||||||
EmuTCPConnection* RelayLink;
|
|
||||||
int32 RelayCount;
|
|
||||||
bool RelayServer;
|
|
||||||
uint32 RemoteID;
|
|
||||||
|
|
||||||
//input queue...
|
|
||||||
void InModeQueuePush(EmuTCPNetPacket_Struct* tnps);
|
|
||||||
MyQueue<EmuTCPNetPacket_Struct> InModeQueue;
|
|
||||||
|
|
||||||
//output queue...
|
|
||||||
MyQueue<ServerPacket> OutQueue;
|
|
||||||
Mutex MOutQueueLock;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /*EmuTCPCONNECTION_H_*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
#include "debug.h"
|
|
||||||
#include "EmuTCPServer.h"
|
|
||||||
#include "EmuTCPConnection.h"
|
|
||||||
|
|
||||||
EmuTCPServer::EmuTCPServer(uint16 iPort, bool iOldFormat)
|
|
||||||
: TCPServer<EmuTCPConnection>(iPort),
|
|
||||||
pOldFormat(iOldFormat)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
EmuTCPServer::~EmuTCPServer() {
|
|
||||||
MInQueue.lock();
|
|
||||||
while(!m_InQueue.empty()) {
|
|
||||||
delete m_InQueue.front();
|
|
||||||
m_InQueue.pop();
|
|
||||||
}
|
|
||||||
MInQueue.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmuTCPServer::Process() {
|
|
||||||
CheckInQueue();
|
|
||||||
TCPServer<EmuTCPConnection>::Process();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmuTCPServer::CreateNewConnection(uint32 ID, SOCKET in_socket, uint32 irIP, uint16 irPort)
|
|
||||||
{
|
|
||||||
EmuTCPConnection *conn = new EmuTCPConnection(ID, this, in_socket, irIP, irPort, pOldFormat);
|
|
||||||
AddConnection(conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void EmuTCPServer::SendPacket(ServerPacket* pack) {
|
|
||||||
EmuTCPNetPacket_Struct* tnps = EmuTCPConnection::MakePacket(pack);
|
|
||||||
SendPacket(&tnps);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmuTCPServer::SendPacket(EmuTCPNetPacket_Struct** tnps) {
|
|
||||||
MInQueue.lock();
|
|
||||||
m_InQueue.push(*tnps);
|
|
||||||
MInQueue.unlock();
|
|
||||||
tnps = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmuTCPServer::CheckInQueue() {
|
|
||||||
EmuTCPNetPacket_Struct* tnps = 0;
|
|
||||||
|
|
||||||
while (( tnps = InQueuePop() )) {
|
|
||||||
vitr cur, end;
|
|
||||||
cur = m_list.begin();
|
|
||||||
end = m_list.end();
|
|
||||||
for(; cur != end; cur++) {
|
|
||||||
if ((*cur)->GetMode() != EmuTCPConnection::modeConsole && (*cur)->GetRemoteID() == 0)
|
|
||||||
(*cur)->SendPacket(tnps);
|
|
||||||
}
|
|
||||||
safe_delete(tnps);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EmuTCPNetPacket_Struct* EmuTCPServer::InQueuePop() {
|
|
||||||
EmuTCPNetPacket_Struct* ret = nullptr;
|
|
||||||
MInQueue.lock();
|
|
||||||
if(!m_InQueue.empty()) {
|
|
||||||
ret = m_InQueue.front();
|
|
||||||
m_InQueue.pop();
|
|
||||||
}
|
|
||||||
MInQueue.unlock();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
EmuTCPConnection *EmuTCPServer::FindConnection(uint32 iID) {
|
|
||||||
vitr cur, end;
|
|
||||||
cur = m_list.begin();
|
|
||||||
end = m_list.end();
|
|
||||||
for(; cur != end; cur++) {
|
|
||||||
if ((*cur)->GetID() == iID)
|
|
||||||
return *cur;
|
|
||||||
}
|
|
||||||
return(nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
#ifndef EmuTCPSERVER_H_
|
|
||||||
#define EmuTCPSERVER_H_
|
|
||||||
|
|
||||||
#include "TCPServer.h"
|
|
||||||
|
|
||||||
class EmuTCPConnection;
|
|
||||||
struct EmuTCPNetPacket_Struct;
|
|
||||||
class ServerPacket;
|
|
||||||
|
|
||||||
class EmuTCPServer : public TCPServer<EmuTCPConnection> {
|
|
||||||
public:
|
|
||||||
EmuTCPServer(uint16 iPort = 0, bool iOldFormat = false);
|
|
||||||
virtual ~EmuTCPServer();
|
|
||||||
|
|
||||||
//packet broadcast routines.
|
|
||||||
void SendPacket(ServerPacket* pack);
|
|
||||||
void SendPacket(EmuTCPNetPacket_Struct** tnps);
|
|
||||||
|
|
||||||
//special crap for relay management
|
|
||||||
EmuTCPConnection *FindConnection(uint32 iID);
|
|
||||||
|
|
||||||
//exposed for some crap we pull. Do not call from outside this object.
|
|
||||||
using TCPServer<EmuTCPConnection>::AddConnection;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void Process();
|
|
||||||
|
|
||||||
virtual void CreateNewConnection(uint32 ID, SOCKET in_socket, uint32 irIP, uint16 irPort);
|
|
||||||
|
|
||||||
bool pOldFormat;
|
|
||||||
|
|
||||||
//broadcast packet queue..
|
|
||||||
void CheckInQueue();
|
|
||||||
Mutex MInQueue;
|
|
||||||
EmuTCPNetPacket_Struct* InQueuePop(); //returns ownership
|
|
||||||
std::queue<EmuTCPNetPacket_Struct *> m_InQueue;
|
|
||||||
};
|
|
||||||
#endif /*EmuTCPSERVER_H_*/
|
|
||||||
-1987
File diff suppressed because it is too large
Load Diff
-450
@@ -1,450 +0,0 @@
|
|||||||
/* EQEMu: Everquest Server Emulator
|
|
||||||
Copyright (C) 2001-2003 EQEMu Development Team (http://eqemulator.net)
|
|
||||||
|
|
||||||
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; version 2 of the License.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
||||||
are required to give you total support for your newly bought product;
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
// @merth notes:
|
|
||||||
// These classes could be optimized with database reads/writes by storing
|
|
||||||
// a status flag indicating how object needs to interact with database
|
|
||||||
|
|
||||||
#ifndef __ITEM_H
|
|
||||||
#define __ITEM_H
|
|
||||||
|
|
||||||
class ItemInst; // Item belonging to a client (contains info on item, dye, augments, charges, etc)
|
|
||||||
class ItemInstQueue; // Queue of ItemInst objects (i.e., cursor)
|
|
||||||
class Inventory; // Character inventory
|
|
||||||
class ItemParse; // Parses item packets
|
|
||||||
class EvolveInfo; // Stores information about an evolving item family
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <map>
|
|
||||||
#include <list>
|
|
||||||
#include "../common/eq_packet_structs.h"
|
|
||||||
#include "../common/eq_constants.h"
|
|
||||||
#include "../common/item_struct.h"
|
|
||||||
#include "../common/timer.h"
|
|
||||||
|
|
||||||
// Helper typedefs
|
|
||||||
typedef std::list<ItemInst*>::const_iterator iter_queue;
|
|
||||||
typedef std::map<int16, ItemInst*>::const_iterator iter_inst;
|
|
||||||
typedef std::map<uint8, ItemInst*>::const_iterator iter_contents;
|
|
||||||
|
|
||||||
namespace ItemField
|
|
||||||
{
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
source = 0,
|
|
||||||
#define F(x) x,
|
|
||||||
#include "item_fieldlist.h"
|
|
||||||
#undef F
|
|
||||||
updated
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// Indexing positions to the beginning slot_id's for a bucket of slots
|
|
||||||
#define IDX_EQUIP 0
|
|
||||||
#define IDX_CURSOR_BAG 331
|
|
||||||
#define IDX_INV 22
|
|
||||||
#define IDX_INV_BAG 251
|
|
||||||
#define IDX_TRIBUTE 400
|
|
||||||
#define IDX_BANK 2000
|
|
||||||
#define IDX_BANK_BAG 2031
|
|
||||||
#define IDX_SHBANK 2500
|
|
||||||
#define IDX_SHBANK_BAG 2531
|
|
||||||
#define IDX_TRADE 3000
|
|
||||||
#define IDX_TRADE_BAG 3031
|
|
||||||
#define IDX_TRADESKILL 4000
|
|
||||||
#define MAX_ITEMS_PER_BAG 10
|
|
||||||
|
|
||||||
// Specifies usage type for item inside ItemInst
|
|
||||||
enum ItemInstTypes
|
|
||||||
{
|
|
||||||
ItemInstNormal = 0,
|
|
||||||
ItemInstWorldContainer
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
byFlagIgnore, //do not consider this flag
|
|
||||||
byFlagSet, //apply action if the flag is set
|
|
||||||
byFlagNotSet //apply action if the flag is NOT set
|
|
||||||
} byFlagSetting;
|
|
||||||
|
|
||||||
|
|
||||||
//FatherNitwit: location bits for searching specific
|
|
||||||
//places with HasItem() and HasItemByUse()
|
|
||||||
enum {
|
|
||||||
invWhereWorn = 0x01,
|
|
||||||
invWherePersonal = 0x02, //in the character's inventory
|
|
||||||
invWhereBank = 0x04,
|
|
||||||
invWhereSharedBank = 0x08,
|
|
||||||
invWhereTrading = 0x10,
|
|
||||||
invWhereCursor = 0x20
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// ########################################
|
|
||||||
// Class: Queue
|
|
||||||
// Queue that allows a read-only iterator
|
|
||||||
class ItemInstQueue
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
~ItemInstQueue();
|
|
||||||
/////////////////////////
|
|
||||||
// Public Methods
|
|
||||||
/////////////////////////
|
|
||||||
|
|
||||||
inline iter_queue begin() { return m_list.begin(); }
|
|
||||||
inline iter_queue end() { return m_list.end(); }
|
|
||||||
|
|
||||||
void push(ItemInst* inst);
|
|
||||||
void push_front(ItemInst* inst);
|
|
||||||
ItemInst* pop();
|
|
||||||
ItemInst* peek_front() const;
|
|
||||||
inline int size() { return static_cast<int>(m_list.size()); }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
/////////////////////////
|
|
||||||
// Protected Members
|
|
||||||
/////////////////////////
|
|
||||||
|
|
||||||
std::list<ItemInst*> m_list;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
// ########################################
|
|
||||||
// Class: Inventory
|
|
||||||
// Character inventory
|
|
||||||
class Inventory
|
|
||||||
{
|
|
||||||
friend class ItemInst;
|
|
||||||
public:
|
|
||||||
///////////////////////////////
|
|
||||||
// Public Methods
|
|
||||||
///////////////////////////////
|
|
||||||
|
|
||||||
~Inventory();
|
|
||||||
|
|
||||||
static void CleanDirty();
|
|
||||||
static void MarkDirty(ItemInst *inst);
|
|
||||||
|
|
||||||
// Retrieve a writeable item at specified slot
|
|
||||||
ItemInst* GetItem(int16 slot_id) const;
|
|
||||||
ItemInst* GetItem(int16 slot_id, uint8 bagidx) const;
|
|
||||||
|
|
||||||
inline iter_queue cursor_begin() { return m_cursor.begin(); }
|
|
||||||
inline iter_queue cursor_end() { return m_cursor.end(); }
|
|
||||||
inline bool CursorEmpty() { return (m_cursor.size() == 0); }
|
|
||||||
|
|
||||||
// Retrieve a read-only item from inventory
|
|
||||||
inline const ItemInst* operator[](int16 slot_id) const { return GetItem(slot_id); }
|
|
||||||
|
|
||||||
// Add item to inventory
|
|
||||||
int16 PutItem(int16 slot_id, const ItemInst& inst);
|
|
||||||
|
|
||||||
// Add item to cursor queue
|
|
||||||
int16 PushCursor(const ItemInst& inst);
|
|
||||||
|
|
||||||
// Swap items in inventory
|
|
||||||
bool SwapItem(int16 slot_a, int16 slot_b);
|
|
||||||
|
|
||||||
// Remove item from inventory
|
|
||||||
bool DeleteItem(int16 slot_id, uint8 quantity=0);
|
|
||||||
|
|
||||||
// Checks All items in a bag for No Drop
|
|
||||||
bool CheckNoDrop(int16 slot_id);
|
|
||||||
|
|
||||||
// Remove item from inventory (and take control of memory)
|
|
||||||
ItemInst* PopItem(int16 slot_id);
|
|
||||||
|
|
||||||
// Check whether there is space for the specified number of the specified item.
|
|
||||||
bool HasSpaceForItem(const Item_Struct *ItemToTry, int16 Quantity);
|
|
||||||
|
|
||||||
// Check whether item exists in inventory
|
|
||||||
// where argument specifies OR'd list of invWhere constants to look
|
|
||||||
int16 HasItem(uint32 item_id, uint8 quantity = 0, uint8 where = 0xFF);
|
|
||||||
|
|
||||||
// Check whether item exists in inventory
|
|
||||||
// where argument specifies OR'd list of invWhere constants to look
|
|
||||||
int16 HasItemByUse(uint8 use, uint8 quantity=0, uint8 where=0xFF);
|
|
||||||
|
|
||||||
// Check whether item exists in inventory
|
|
||||||
// where argument specifies OR'd list of invWhere constants to look
|
|
||||||
int16 HasItemByLoreGroup(uint32 loregroup, uint8 where=0xFF);
|
|
||||||
|
|
||||||
// Locate an available inventory slot
|
|
||||||
int16 FindFreeSlot(bool for_bag, bool try_cursor, uint8 min_size = 0, bool is_arrow = false);
|
|
||||||
|
|
||||||
// Calculate slot_id for an item within a bag
|
|
||||||
static int16 CalcSlotId(int16 slot_id); // Calc parent bag's slot_id
|
|
||||||
static int16 CalcSlotId(int16 bagslot_id, uint8 bagidx); // Calc slot_id for item inside bag
|
|
||||||
static uint8 CalcBagIdx(int16 slot_id); // Calc bagidx for slot_id
|
|
||||||
static int16 CalcSlotFromMaterial(uint8 material);
|
|
||||||
static uint8 CalcMaterialFromSlot(int16 equipslot);
|
|
||||||
|
|
||||||
static bool CanItemFitInContainer(const Item_Struct *ItemToTry, const Item_Struct *Container);
|
|
||||||
|
|
||||||
// Test whether a given slot can support a container item
|
|
||||||
static bool SupportsContainers(int16 slot_id);
|
|
||||||
|
|
||||||
int GetSlotByItemInst(ItemInst *inst);
|
|
||||||
|
|
||||||
void dumpEntireInventory();
|
|
||||||
void dumpWornItems();
|
|
||||||
void dumpInventory();
|
|
||||||
void dumpBankItems();
|
|
||||||
void dumpSharedBankItems();
|
|
||||||
|
|
||||||
void SetCustomItemData(uint32 character_id, int16 slot_id, std::string identifier, std::string value);
|
|
||||||
void SetCustomItemData(uint32 character_id, int16 slot_id, std::string identifier, int value);
|
|
||||||
void SetCustomItemData(uint32 character_id, int16 slot_id, std::string identifier, float value);
|
|
||||||
void SetCustomItemData(uint32 character_id, int16 slot_id, std::string identifier, bool value);
|
|
||||||
std::string GetCustomItemData(int16 slot_id, std::string identifier);
|
|
||||||
protected:
|
|
||||||
///////////////////////////////
|
|
||||||
// Protected Methods
|
|
||||||
///////////////////////////////
|
|
||||||
|
|
||||||
int GetSlotByItemInstCollection(const std::map<int16, ItemInst*> &collection, ItemInst *inst);
|
|
||||||
void dumpItemCollection(const std::map<int16, ItemInst*> &collection);
|
|
||||||
void dumpBagContents(ItemInst *inst, iter_inst *it);
|
|
||||||
|
|
||||||
// Retrieves item within an inventory bucket
|
|
||||||
ItemInst* _GetItem(const std::map<int16, ItemInst*>& bucket, int16 slot_id) const;
|
|
||||||
|
|
||||||
// Private "put" item into bucket, without regard for what is currently in bucket
|
|
||||||
int16 _PutItem(int16 slot_id, ItemInst* inst);
|
|
||||||
|
|
||||||
// Checks an inventory bucket for a particular item
|
|
||||||
int16 _HasItem(std::map<int16, ItemInst*>& bucket, uint32 item_id, uint8 quantity);
|
|
||||||
int16 _HasItem(ItemInstQueue& iqueue, uint32 item_id, uint8 quantity);
|
|
||||||
int16 _HasItemByUse(std::map<int16, ItemInst*>& bucket, uint8 use, uint8 quantity);
|
|
||||||
int16 _HasItemByUse(ItemInstQueue& iqueue, uint8 use, uint8 quantity);
|
|
||||||
int16 _HasItemByLoreGroup(std::map<int16, ItemInst*>& bucket, uint32 loregroup);
|
|
||||||
int16 _HasItemByLoreGroup(ItemInstQueue& iqueue, uint32 loregroup);
|
|
||||||
|
|
||||||
|
|
||||||
// Player inventory
|
|
||||||
std::map<int16, ItemInst*> m_worn; // Items worn by character
|
|
||||||
std::map<int16, ItemInst*> m_inv; // Items in character personal inventory
|
|
||||||
std::map<int16, ItemInst*> m_bank; // Items in character bank
|
|
||||||
std::map<int16, ItemInst*> m_shbank; // Items in character shared bank
|
|
||||||
std::map<int16, ItemInst*> m_trade; // Items in a trade session
|
|
||||||
ItemInstQueue m_cursor; // Items on cursor: FIFO
|
|
||||||
};
|
|
||||||
|
|
||||||
class SharedDatabase;
|
|
||||||
|
|
||||||
// ########################################
|
|
||||||
// Class: ItemInst
|
|
||||||
// Base class for an instance of an item
|
|
||||||
// An item instance encapsulates item data + data specific
|
|
||||||
// to an item instance (includes dye, augments, charges, etc)
|
|
||||||
class ItemInst
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/////////////////////////
|
|
||||||
// Methods
|
|
||||||
/////////////////////////
|
|
||||||
|
|
||||||
// Constructors/Destructor
|
|
||||||
ItemInst(const Item_Struct* item = nullptr, int16 charges = 0);
|
|
||||||
|
|
||||||
ItemInst(SharedDatabase *db, uint32 item_id, int16 charges = 0);
|
|
||||||
|
|
||||||
ItemInst(ItemInstTypes use_type);
|
|
||||||
|
|
||||||
ItemInst(const ItemInst& copy);
|
|
||||||
|
|
||||||
~ItemInst();
|
|
||||||
|
|
||||||
// Query item type
|
|
||||||
bool IsType(ItemClassTypes item_class) const;
|
|
||||||
|
|
||||||
// Can item be stacked?
|
|
||||||
bool IsStackable() const;
|
|
||||||
bool IsCharged() const;
|
|
||||||
|
|
||||||
// Can item be equipped by/at?
|
|
||||||
bool IsEquipable(uint16 race, uint16 class_) const;
|
|
||||||
bool IsEquipable(int16 slot_id) const;
|
|
||||||
|
|
||||||
//
|
|
||||||
// Augements
|
|
||||||
//
|
|
||||||
inline bool IsAugmentable() const { return m_item->AugSlotType[0]!=0 || m_item->AugSlotType[1]!=0 || m_item->AugSlotType[2]!=0 || m_item->AugSlotType[3]!=0 || m_item->AugSlotType[4]!=0; }
|
|
||||||
bool AvailableWearSlot(uint32 aug_wear_slots) const;
|
|
||||||
int8 AvailableAugmentSlot(int32 augtype) const;
|
|
||||||
inline int32 GetAugmentType() const { return m_item->AugType; }
|
|
||||||
|
|
||||||
inline bool IsExpendable() const { return ((m_item->Click.Type == ET_Expendable ) || (m_item->ItemType == ItemTypePotion)); }
|
|
||||||
|
|
||||||
//
|
|
||||||
// Contents
|
|
||||||
//
|
|
||||||
ItemInst* GetItem(uint8 slot) const;
|
|
||||||
uint32 GetItemID(uint8 slot) const;
|
|
||||||
inline const ItemInst* operator[](uint8 slot) const { return GetItem(slot); }
|
|
||||||
void PutItem(uint8 slot, const ItemInst& inst);
|
|
||||||
void PutItem(SharedDatabase *db, uint8 slot, uint32 item_id) { return; } // not defined anywhere...
|
|
||||||
void DeleteItem(uint8 slot);
|
|
||||||
ItemInst* PopItem(uint8 index);
|
|
||||||
void Clear();
|
|
||||||
void ClearByFlags(byFlagSetting is_nodrop, byFlagSetting is_norent);
|
|
||||||
uint8 FirstOpenSlot() const;
|
|
||||||
uint8 GetTotalItemCount() const;
|
|
||||||
bool IsNoneEmptyContainer();
|
|
||||||
std::map<uint8, ItemInst*>* GetContents() { return &m_contents; }
|
|
||||||
|
|
||||||
//
|
|
||||||
// Augments
|
|
||||||
//
|
|
||||||
ItemInst* GetAugment(uint8 slot) const;
|
|
||||||
uint32 GetAugmentItemID(uint8 slot) const;
|
|
||||||
void PutAugment(uint8 slot, const ItemInst& inst);
|
|
||||||
void PutAugment(SharedDatabase *db, uint8 slot, uint32 item_id);
|
|
||||||
void DeleteAugment(uint8 slot);
|
|
||||||
ItemInst* RemoveAugment(uint8 index);
|
|
||||||
bool IsAugmented();
|
|
||||||
|
|
||||||
// Has attack/delay?
|
|
||||||
bool IsWeapon() const;
|
|
||||||
bool IsAmmo() const;
|
|
||||||
|
|
||||||
// Accessors
|
|
||||||
const uint32 GetID() const { return m_item->ID; }
|
|
||||||
const uint32 GetItemScriptID() const { return m_item->ScriptFileID; }
|
|
||||||
const Item_Struct* GetItem() const;
|
|
||||||
const Item_Struct* GetUnscaledItem() const;
|
|
||||||
|
|
||||||
int16 GetCharges() const { return m_charges; }
|
|
||||||
void SetCharges(int16 charges) { m_charges = charges; }
|
|
||||||
|
|
||||||
uint32 GetPrice() const { return m_price; }
|
|
||||||
void SetPrice(uint32 price) { m_price = price; }
|
|
||||||
|
|
||||||
void SetColor(uint32 color) { m_color = color; }
|
|
||||||
uint32 GetColor() const { return m_color; }
|
|
||||||
|
|
||||||
uint32 GetMerchantSlot() const { return m_merchantslot; }
|
|
||||||
void SetMerchantSlot(uint32 slot) { m_merchantslot = slot; }
|
|
||||||
|
|
||||||
int32 GetMerchantCount() const { return m_merchantcount; }
|
|
||||||
void SetMerchantCount(int32 count) { m_merchantcount = count; }
|
|
||||||
|
|
||||||
int16 GetCurrentSlot() const { return m_currentslot; }
|
|
||||||
void SetCurrentSlot(int16 curr_slot) { m_currentslot = curr_slot; }
|
|
||||||
|
|
||||||
// Is this item already attuned?
|
|
||||||
bool IsInstNoDrop() const { return m_instnodrop; }
|
|
||||||
void SetInstNoDrop(bool flag) { m_instnodrop=flag; }
|
|
||||||
|
|
||||||
std::string GetCustomDataString() const;
|
|
||||||
std::string GetCustomData(std::string identifier);
|
|
||||||
void SetCustomData(std::string identifier, std::string value);
|
|
||||||
void SetCustomData(std::string identifier, int value);
|
|
||||||
void SetCustomData(std::string identifier, float value);
|
|
||||||
void SetCustomData(std::string identifier, bool value);
|
|
||||||
void DeleteCustomData(std::string identifier);
|
|
||||||
|
|
||||||
// Allows treatment of this object as though it were a pointer to m_item
|
|
||||||
operator bool() const { return (m_item != nullptr); }
|
|
||||||
|
|
||||||
// Compare inner Item_Struct of two ItemInst objects
|
|
||||||
bool operator==(const ItemInst& right) const { return (this->m_item == right.m_item); }
|
|
||||||
bool operator!=(const ItemInst& right) const { return (this->m_item != right.m_item); }
|
|
||||||
|
|
||||||
// Clone current item
|
|
||||||
ItemInst* Clone() const;
|
|
||||||
|
|
||||||
bool IsSlotAllowed(int16 slot_id) const;
|
|
||||||
|
|
||||||
bool IsScaling() const { return m_scaling; }
|
|
||||||
bool IsEvolving() const { return (m_evolveLvl >= 1); }
|
|
||||||
uint32 GetExp() const { return m_exp; }
|
|
||||||
void SetExp(uint32 exp) { m_exp = exp; }
|
|
||||||
void AddExp(uint32 exp) { m_exp += exp; }
|
|
||||||
bool IsActivated() { return m_activated; }
|
|
||||||
void SetActivated(bool activated) { m_activated = activated; }
|
|
||||||
int8 GetEvolveLvl() const { return m_evolveLvl; }
|
|
||||||
void SetScaling(bool v) { m_scaling = v; }
|
|
||||||
|
|
||||||
void Initialize(SharedDatabase *db = nullptr);
|
|
||||||
void ScaleItem();
|
|
||||||
bool EvolveOnAllKills() const;
|
|
||||||
int8 GetMaxEvolveLvl() const;
|
|
||||||
uint32 GetKillsNeeded(uint8 currentlevel);
|
|
||||||
|
|
||||||
std::string Serialize(int16 slot_id) const { InternalSerializedItem_Struct s; s.slot_id=slot_id; s.inst=(const void *)this; std::string ser; ser.assign((char *)&s,sizeof(InternalSerializedItem_Struct)); return ser; }
|
|
||||||
inline int32 GetSerialNumber() const { return m_SerialNumber; }
|
|
||||||
inline void SetSerialNumber(int32 id) { m_SerialNumber = id; }
|
|
||||||
|
|
||||||
std::map<std::string, Timer>& GetTimers() { return m_timers; }
|
|
||||||
void SetTimer(std::string name, uint32 time);
|
|
||||||
void StopTimer(std::string name);
|
|
||||||
void ClearTimers();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
//////////////////////////
|
|
||||||
// Protected Members
|
|
||||||
//////////////////////////
|
|
||||||
iter_contents _begin() { return m_contents.begin(); }
|
|
||||||
iter_contents _end() { return m_contents.end(); }
|
|
||||||
|
|
||||||
friend class Inventory;
|
|
||||||
|
|
||||||
|
|
||||||
void _PutItem(uint8 index, ItemInst* inst) { m_contents[index] = inst; }
|
|
||||||
|
|
||||||
ItemInstTypes m_use_type; // Usage type for item
|
|
||||||
const Item_Struct* m_item; // Ptr to item data
|
|
||||||
int16 m_charges; // # of charges for chargeable items
|
|
||||||
uint32 m_price; // Bazaar /trader price
|
|
||||||
uint32 m_color;
|
|
||||||
uint32 m_merchantslot;
|
|
||||||
int16 m_currentslot;
|
|
||||||
bool m_instnodrop;
|
|
||||||
int32 m_merchantcount; //number avaliable on the merchant, -1=unlimited
|
|
||||||
int32 m_SerialNumber; // Unique identifier for this instance of an item. Needed for Bazaar.
|
|
||||||
uint32 m_exp;
|
|
||||||
int8 m_evolveLvl;
|
|
||||||
bool m_activated;
|
|
||||||
Item_Struct* m_scaledItem;
|
|
||||||
EvolveInfo* m_evolveInfo;
|
|
||||||
bool m_scaling;
|
|
||||||
|
|
||||||
//
|
|
||||||
// Items inside of this item (augs or contents);
|
|
||||||
std::map<uint8, ItemInst*> m_contents; // Zero-based index: min=0, max=9
|
|
||||||
std::map<std::string, std::string> m_custom_data;
|
|
||||||
std::map<std::string, Timer> m_timers;
|
|
||||||
};
|
|
||||||
|
|
||||||
class EvolveInfo {
|
|
||||||
public:
|
|
||||||
friend class ItemInst;
|
|
||||||
//temporary
|
|
||||||
uint16 LvlKills[9];
|
|
||||||
uint32 FirstItem;
|
|
||||||
uint8 MaxLvl;
|
|
||||||
bool AllKills;
|
|
||||||
|
|
||||||
EvolveInfo();
|
|
||||||
EvolveInfo(uint32 first, uint8 max, bool allkills, uint32 L2, uint32 L3, uint32 L4, uint32 L5, uint32 L6, uint32 L7, uint32 L8, uint32 L9, uint32 L10);
|
|
||||||
~EvolveInfo();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // #define __ITEM_H
|
|
||||||
-1900
File diff suppressed because it is too large
Load Diff
@@ -1,389 +0,0 @@
|
|||||||
/* EQEMu: Everquest Server Emulator
|
|
||||||
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
|
||||||
|
|
||||||
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; version 2 of the License.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
||||||
are required to give you total support for your newly bought product;
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
#include "../common/debug.h"
|
|
||||||
#include "MiscFunctions.h"
|
|
||||||
#include <string.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <math.h>
|
|
||||||
#ifndef WIN32
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#endif
|
|
||||||
#include <iostream>
|
|
||||||
#include <iomanip>
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
#include <io.h>
|
|
||||||
#endif
|
|
||||||
#include "../common/timer.h"
|
|
||||||
#include "../common/seperator.h"
|
|
||||||
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
#define snprintf _snprintf
|
|
||||||
#define strncasecmp _strnicmp
|
|
||||||
#define strcasecmp _stricmp
|
|
||||||
#else
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#ifdef FREEBSD //Timothy Whitman - January 7, 2003
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#endif
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <netdb.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static bool WELLRNG_init = false;
|
|
||||||
static int state_i = 0;
|
|
||||||
static unsigned int STATE[R];
|
|
||||||
static unsigned int z0, z1, z2;
|
|
||||||
unsigned int (*WELLRNG19937)(void);
|
|
||||||
static unsigned int case_1 (void);
|
|
||||||
static unsigned int case_2 (void);
|
|
||||||
static unsigned int case_3 (void);
|
|
||||||
static unsigned int case_4 (void);
|
|
||||||
static unsigned int case_5 (void);
|
|
||||||
static unsigned int case_6 (void);
|
|
||||||
uint32 rnd_hash(time_t t, clock_t c);
|
|
||||||
void oneseed(const uint32 seed);
|
|
||||||
|
|
||||||
void CoutTimestamp(bool ms) {
|
|
||||||
time_t rawtime;
|
|
||||||
struct tm* gmt_t;
|
|
||||||
time(&rawtime);
|
|
||||||
gmt_t = gmtime(&rawtime);
|
|
||||||
|
|
||||||
struct timeval read_time;
|
|
||||||
gettimeofday(&read_time,0);
|
|
||||||
|
|
||||||
std::cout << (gmt_t->tm_year + 1900) << "/" << std::setw(2) << std::setfill('0') << (gmt_t->tm_mon + 1) << "/" << std::setw(2) << std::setfill('0') << gmt_t->tm_mday << " " << std::setw(2) << std::setfill('0') << gmt_t->tm_hour << ":" << std::setw(2) << std::setfill('0') << gmt_t->tm_min << ":" << std::setw(2) << std::setfill('0') << gmt_t->tm_sec;
|
|
||||||
if (ms)
|
|
||||||
std::cout << "." << std::setw(3) << std::setfill('0') << (read_time.tv_usec / 1000);
|
|
||||||
std::cout << " GMT";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int32 filesize(FILE* fp) {
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
return _filelength(_fileno(fp));
|
|
||||||
#else
|
|
||||||
struct stat file_stat;
|
|
||||||
fstat(fileno(fp), &file_stat);
|
|
||||||
return (int32) file_stat.st_size;
|
|
||||||
/* uint32 tmp = 0;
|
|
||||||
while (!feof(fp)) {
|
|
||||||
fseek(fp, tmp++, SEEK_SET);
|
|
||||||
}
|
|
||||||
return tmp;*/
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 ResolveIP(const char* hostname, char* errbuf) {
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
static InitWinsock ws;
|
|
||||||
#endif
|
|
||||||
if (errbuf)
|
|
||||||
errbuf[0] = 0;
|
|
||||||
if (hostname == 0) {
|
|
||||||
if (errbuf)
|
|
||||||
snprintf(errbuf, ERRBUF_SIZE, "ResolveIP(): hostname == 0");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
struct sockaddr_in server_sin;
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
PHOSTENT phostent = nullptr;
|
|
||||||
#else
|
|
||||||
struct hostent *phostent = nullptr;
|
|
||||||
#endif
|
|
||||||
server_sin.sin_family = AF_INET;
|
|
||||||
if ((phostent = gethostbyname(hostname)) == nullptr) {
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
if (errbuf)
|
|
||||||
snprintf(errbuf, ERRBUF_SIZE, "Unable to get the host name. Error: %i", WSAGetLastError());
|
|
||||||
#else
|
|
||||||
if (errbuf)
|
|
||||||
snprintf(errbuf, ERRBUF_SIZE, "Unable to get the host name. Error: %s", strerror(errno));
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
memcpy ((char FAR *)&(server_sin.sin_addr), phostent->h_addr, phostent->h_length);
|
|
||||||
#else
|
|
||||||
memcpy ((char*)&(server_sin.sin_addr), phostent->h_addr, phostent->h_length);
|
|
||||||
#endif
|
|
||||||
return server_sin.sin_addr.s_addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ParseAddress(const char* iAddress, uint32* oIP, uint16* oPort, char* errbuf) {
|
|
||||||
Seperator sep(iAddress, ':', 2, 250, false, 0, 0);
|
|
||||||
if (sep.argnum == 1 && sep.IsNumber(1)) {
|
|
||||||
*oIP = ResolveIP(sep.arg[0], errbuf);
|
|
||||||
if (*oIP == 0)
|
|
||||||
return false;
|
|
||||||
if (oPort)
|
|
||||||
*oPort = atoi(sep.arg[1]);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
InitWinsock::InitWinsock() {
|
|
||||||
WORD version = MAKEWORD (1,1);
|
|
||||||
WSADATA wsadata;
|
|
||||||
WSAStartup (version, &wsadata);
|
|
||||||
}
|
|
||||||
|
|
||||||
InitWinsock::~InitWinsock() {
|
|
||||||
WSACleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
const char * itoa(int num) {
|
|
||||||
static char temp[_ITOA_BUFLEN];
|
|
||||||
memset(temp,0,_ITOA_BUFLEN);
|
|
||||||
snprintf(temp,_ITOA_BUFLEN,"%d",num);
|
|
||||||
return temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef WIN32
|
|
||||||
const char * itoa(int num, char* a,int b) {
|
|
||||||
static char temp[_ITOA_BUFLEN];
|
|
||||||
memset(temp,0,_ITOA_BUFLEN);
|
|
||||||
snprintf(temp,_ITOA_BUFLEN,"%d",num);
|
|
||||||
return temp;
|
|
||||||
return temp;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* generate a random integer in the range low-high this
|
|
||||||
* should be used instead of the rand()%limit method
|
|
||||||
*/
|
|
||||||
int MakeRandomInt(int low, int high)
|
|
||||||
{
|
|
||||||
if(low >= high)
|
|
||||||
return(low);
|
|
||||||
|
|
||||||
//return (rand()%(high-low+1) + (low));
|
|
||||||
if(!WELLRNG_init) {
|
|
||||||
WELLRNG_init = true;
|
|
||||||
oneseed( rnd_hash( time(nullptr), clock() ) );
|
|
||||||
WELLRNG19937 = case_1;
|
|
||||||
}
|
|
||||||
unsigned int randomnum = ((WELLRNG19937)());
|
|
||||||
if(randomnum == 0xffffffffUL)
|
|
||||||
return high;
|
|
||||||
return int ((randomnum / (double)0xffffffffUL) * (high - low + 1) + low);
|
|
||||||
}
|
|
||||||
|
|
||||||
double MakeRandomFloat(double low, double high)
|
|
||||||
{
|
|
||||||
if(low >= high)
|
|
||||||
return(low);
|
|
||||||
|
|
||||||
//return (rand() / (double)RAND_MAX * (high - low) + low);
|
|
||||||
if(!WELLRNG_init) {
|
|
||||||
WELLRNG_init = true;
|
|
||||||
oneseed( rnd_hash( time(nullptr), clock() ) );
|
|
||||||
WELLRNG19937 = case_1;
|
|
||||||
}
|
|
||||||
return ((WELLRNG19937)() / (double)0xffffffffUL * (high - low) + low);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 rnd_hash( time_t t, clock_t c )
|
|
||||||
{
|
|
||||||
// Get a uint32 from t and c
|
|
||||||
// Better than uint32(x) in case x is floating point in [0,1]
|
|
||||||
// Based on code by Lawrence Kirby (fred@genesis.demon.co.uk)
|
|
||||||
|
|
||||||
static uint32 differ = 0; // guarantee time-based seeds will change
|
|
||||||
|
|
||||||
uint32 h1 = 0;
|
|
||||||
unsigned char *p = (unsigned char *) &t;
|
|
||||||
for( size_t i = 0; i < sizeof(t); ++i )
|
|
||||||
{
|
|
||||||
h1 *= 255 + 2U;
|
|
||||||
h1 += p[i];
|
|
||||||
}
|
|
||||||
uint32 h2 = 0;
|
|
||||||
p = (unsigned char *) &c;
|
|
||||||
for( size_t j = 0; j < sizeof(c); ++j )
|
|
||||||
{
|
|
||||||
h2 *= 255 + 2U;
|
|
||||||
h2 += p[j];
|
|
||||||
}
|
|
||||||
return ( h1 + differ++ ) ^ h2;
|
|
||||||
}
|
|
||||||
|
|
||||||
void oneseed( const uint32 seed )
|
|
||||||
{
|
|
||||||
// Initialize generator state with seed
|
|
||||||
// See Knuth TAOCP Vol 2, 3rd Ed, p.106 for multiplier.
|
|
||||||
// In previous versions, most significant bits (MSBs) of the seed affect
|
|
||||||
// only MSBs of the state array. Modified 9 Jan 2002 by Makoto Matsumoto.
|
|
||||||
register int j = 0;
|
|
||||||
STATE[j] = seed & 0xffffffffUL;
|
|
||||||
for (j = 1; j < R; j++)
|
|
||||||
{
|
|
||||||
STATE[j] = ( 1812433253UL * ( STATE[j-1] ^ (STATE[j-1] >> 30) ) + j ) & 0xffffffffUL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WELL RNG code
|
|
||||||
|
|
||||||
/* ***************************************************************************** */
|
|
||||||
/* Copyright: Francois Panneton and Pierre L'Ecuyer, University of Montreal */
|
|
||||||
/* Makoto Matsumoto, Hiroshima University */
|
|
||||||
/* Notice: This code can be used freely for personal, academic, */
|
|
||||||
/* or non-commercial purposes. For commercial purposes, */
|
|
||||||
/* please contact P. L'Ecuyer at: lecuyer@iro.UMontreal.ca */
|
|
||||||
/* A modified "maximally equidistributed" implementation */
|
|
||||||
/* by Shin Harase, Hiroshima University. */
|
|
||||||
/* ***************************************************************************** */
|
|
||||||
|
|
||||||
unsigned int case_1 (void){
|
|
||||||
// state_i == 0
|
|
||||||
z0 = (VRm1Under & MASKL) | (VRm2Under & MASKU);
|
|
||||||
z1 = MAT0NEG (-25, V0) ^ MAT0POS (27, VM1);
|
|
||||||
z2 = MAT3POS (9, VM2) ^ MAT0POS (1, VM3);
|
|
||||||
newV1 = z1 ^ z2;
|
|
||||||
newV0Under = MAT1 (z0) ^ MAT0NEG (-9, z1) ^ MAT0NEG (-21, z2) ^ MAT0POS (21, newV1);
|
|
||||||
state_i = R - 1;
|
|
||||||
WELLRNG19937 = case_3;
|
|
||||||
return (STATE[state_i] ^ (newVM2Over & BITMASK));
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned int case_2 (void){
|
|
||||||
// state_i == 1
|
|
||||||
z0 = (VRm1 & MASKL) | (VRm2Under & MASKU);
|
|
||||||
z1 = MAT0NEG (-25, V0) ^ MAT0POS (27, VM1);
|
|
||||||
z2 = MAT3POS (9, VM2) ^ MAT0POS (1, VM3);
|
|
||||||
newV1 = z1 ^ z2;
|
|
||||||
newV0 = MAT1 (z0) ^ MAT0NEG (-9, z1) ^ MAT0NEG (-21, z2) ^ MAT0POS (21, newV1);
|
|
||||||
state_i = 0;
|
|
||||||
WELLRNG19937 = case_1;
|
|
||||||
return (STATE[state_i] ^ (newVM2 & BITMASK));
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned int case_3 (void){
|
|
||||||
// state_i+M1 >= R
|
|
||||||
z0 = (VRm1 & MASKL) | (VRm2 & MASKU);
|
|
||||||
z1 = MAT0NEG (-25, V0) ^ MAT0POS (27, VM1Over);
|
|
||||||
z2 = MAT3POS (9, VM2Over) ^ MAT0POS (1, VM3Over);
|
|
||||||
newV1 = z1 ^ z2;
|
|
||||||
newV0 = MAT1 (z0) ^ MAT0NEG (-9, z1) ^ MAT0NEG (-21, z2) ^ MAT0POS (21, newV1);
|
|
||||||
state_i--;
|
|
||||||
if (state_i + M1 < R)
|
|
||||||
WELLRNG19937 = case_5;
|
|
||||||
return (STATE[state_i] ^ (newVM2Over & BITMASK));
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned int case_4 (void){
|
|
||||||
// state_i+M3 >= R
|
|
||||||
z0 = (VRm1 & MASKL) | (VRm2 & MASKU);
|
|
||||||
z1 = MAT0NEG (-25, V0) ^ MAT0POS (27, VM1);
|
|
||||||
z2 = MAT3POS (9, VM2) ^ MAT0POS (1, VM3Over);
|
|
||||||
newV1 = z1 ^ z2;
|
|
||||||
newV0 = MAT1 (z0) ^ MAT0NEG (-9, z1) ^ MAT0NEG (-21, z2) ^ MAT0POS (21, newV1);
|
|
||||||
state_i--;
|
|
||||||
if (state_i + M3 < R)
|
|
||||||
WELLRNG19937 = case_6;
|
|
||||||
return (STATE[state_i] ^ (newVM2 & BITMASK));
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned int case_5 (void){
|
|
||||||
// state_i+M2 >= R
|
|
||||||
z0 = (VRm1 & MASKL) | (VRm2 & MASKU);
|
|
||||||
z1 = MAT0NEG (-25, V0) ^ MAT0POS (27, VM1);
|
|
||||||
z2 = MAT3POS (9, VM2Over) ^ MAT0POS (1, VM3Over);
|
|
||||||
newV1 = z1 ^ z2;
|
|
||||||
newV0 = MAT1 (z0) ^ MAT0NEG (-9, z1) ^ MAT0NEG (-21, z2) ^ MAT0POS (21, newV1);
|
|
||||||
state_i--;
|
|
||||||
if (state_i + M2 < R)
|
|
||||||
WELLRNG19937 = case_4;
|
|
||||||
return (STATE[state_i] ^ (newVM2Over & BITMASK));
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned int case_6 (void){
|
|
||||||
// 2 <= state_i <= (R - M3 - 1)
|
|
||||||
z0 = (VRm1 & MASKL) | (VRm2 & MASKU);
|
|
||||||
z1 = MAT0NEG (-25, V0) ^ MAT0POS (27, VM1);
|
|
||||||
z2 = MAT3POS (9, VM2) ^ MAT0POS (1, VM3);
|
|
||||||
newV1 = z1 ^ z2;
|
|
||||||
newV0 = MAT1 (z0) ^ MAT0NEG (-9, z1) ^ MAT0NEG (-21, z2) ^ MAT0POS (21, newV1);
|
|
||||||
state_i--;
|
|
||||||
if (state_i == 1)
|
|
||||||
WELLRNG19937 = case_2;
|
|
||||||
return (STATE[state_i] ^ (newVM2 & BITMASK));
|
|
||||||
}
|
|
||||||
|
|
||||||
// end WELL RNG code
|
|
||||||
|
|
||||||
|
|
||||||
float EQ13toFloat(int d)
|
|
||||||
{
|
|
||||||
return ( float(d)/float(1<<2));
|
|
||||||
}
|
|
||||||
|
|
||||||
float NewEQ13toFloat(int d)
|
|
||||||
{
|
|
||||||
return ( float(d)/float(1<<6));
|
|
||||||
}
|
|
||||||
|
|
||||||
float EQ19toFloat(int d)
|
|
||||||
{
|
|
||||||
return ( float(d)/float(1<<3));
|
|
||||||
}
|
|
||||||
|
|
||||||
int FloatToEQ13(float d)
|
|
||||||
{
|
|
||||||
return int(d*float(1<<2));
|
|
||||||
}
|
|
||||||
|
|
||||||
int NewFloatToEQ13(float d)
|
|
||||||
{
|
|
||||||
return int(d*float(1<<6));
|
|
||||||
}
|
|
||||||
|
|
||||||
int FloatToEQ19(float d)
|
|
||||||
{
|
|
||||||
return int(d*float(1<<3));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Heading of 0 points in the pure positive Y direction
|
|
||||||
|
|
||||||
*/
|
|
||||||
int FloatToEQH(float d)
|
|
||||||
{
|
|
||||||
return(int((360.0f - d) * float(1<<11)) / 360);
|
|
||||||
}
|
|
||||||
|
|
||||||
float EQHtoFloat(int d)
|
|
||||||
{
|
|
||||||
return(360.0f - float((d * 360) >> 11));
|
|
||||||
}
|
|
||||||
@@ -1,144 +0,0 @@
|
|||||||
/* EQEMu: Everquest Server Emulator
|
|
||||||
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
|
||||||
|
|
||||||
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; version 2 of the License.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
||||||
are required to give you total support for your newly bought product;
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
#ifndef MISCFUNCTIONS_H
|
|
||||||
#define MISCFUNCTIONS_H
|
|
||||||
|
|
||||||
#include "types.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <string>
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef ERRBUF_SIZE
|
|
||||||
#define ERRBUF_SIZE 1024
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// These are helper macros for dealing with packets of variable length, typically those that contain
|
|
||||||
// variable length strings where it is not convenient to use a fixed length struct.
|
|
||||||
//
|
|
||||||
#define VARSTRUCT_DECODE_TYPE(Type, Buffer) *(Type *)Buffer; Buffer += sizeof(Type);
|
|
||||||
#define VARSTRUCT_DECODE_STRING(String, Buffer) strcpy(String, Buffer); Buffer += strlen(String)+1;
|
|
||||||
#define VARSTRUCT_ENCODE_STRING(Buffer, String) { sprintf(Buffer, "%s", String); Buffer += strlen(String) + 1; }
|
|
||||||
#define VARSTRUCT_ENCODE_INTSTRING(Buffer, Number) { sprintf(Buffer, "%i", Number); Buffer += strlen(Buffer) + 1; }
|
|
||||||
#define VARSTRUCT_ENCODE_TYPE(Type, Buffer, Value) { *(Type *)Buffer = Value; Buffer += sizeof(Type); }
|
|
||||||
#define VARSTRUCT_SKIP_TYPE(Type, Buffer) Buffer += sizeof(Type);
|
|
||||||
|
|
||||||
#define VERIFY_PACKET_LENGTH(OPCode, Packet, StructName) \
|
|
||||||
if(Packet->size != sizeof(StructName)) \
|
|
||||||
{ \
|
|
||||||
_log(NET__ERROR, "Size mismatch in " #OPCode " expected %i got %i", sizeof(StructName), Packet->size); \
|
|
||||||
DumpPacket(Packet); \
|
|
||||||
return; \
|
|
||||||
}
|
|
||||||
|
|
||||||
// Definitions for WELLRNG
|
|
||||||
//
|
|
||||||
#define W 32
|
|
||||||
#define R 624
|
|
||||||
#define DISCARD 31
|
|
||||||
#define MASKU (0xffffffffU>>(W-DISCARD))
|
|
||||||
#define MASKL (~MASKU)
|
|
||||||
#define M1 70
|
|
||||||
#define M2 179
|
|
||||||
#define M3 449
|
|
||||||
|
|
||||||
#define MAT0POS(t,v) (v^(v>>t))
|
|
||||||
#define MAT0NEG(t,v) (v^(v<<(-(t))))
|
|
||||||
#define MAT1(v) v
|
|
||||||
#define MAT3POS(t,v) (v>>t)
|
|
||||||
|
|
||||||
#define V0 STATE[state_i]
|
|
||||||
#define VM1Over STATE[state_i+M1-R]
|
|
||||||
#define VM1 STATE[state_i+M1]
|
|
||||||
#define VM2Over STATE[state_i+M2-R]
|
|
||||||
#define VM2 STATE[state_i+M2]
|
|
||||||
#define VM3Over STATE[state_i+M3-R]
|
|
||||||
#define VM3 STATE[state_i+M3]
|
|
||||||
#define VRm1 STATE[state_i-1]
|
|
||||||
#define VRm1Under STATE[state_i+R-1]
|
|
||||||
#define VRm2 STATE[state_i-2]
|
|
||||||
#define VRm2Under STATE[state_i+R-2]
|
|
||||||
|
|
||||||
#define newV0 STATE[state_i-1]
|
|
||||||
#define newV0Under STATE[state_i-1+R]
|
|
||||||
#define newV1 STATE[state_i]
|
|
||||||
#define newVRm1 STATE[state_i-2]
|
|
||||||
#define newVRm1Under STATE[state_i-2+R]
|
|
||||||
|
|
||||||
#define newVM2Over STATE[state_i+M2-R+1]
|
|
||||||
#define newVM2 STATE[state_i+M2+1]
|
|
||||||
|
|
||||||
#define BITMASK 0x41180000
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int32 filesize(FILE* fp);
|
|
||||||
uint32 ResolveIP(const char* hostname, char* errbuf = 0);
|
|
||||||
bool ParseAddress(const char* iAddress, uint32* oIP, uint16* oPort, char* errbuf = 0);
|
|
||||||
void CoutTimestamp(bool ms = true);
|
|
||||||
int MakeRandomInt(int low, int high);
|
|
||||||
double MakeRandomFloat(double low, double high);
|
|
||||||
float EQ13toFloat(int d);
|
|
||||||
float NewEQ13toFloat(int d);
|
|
||||||
float EQ19toFloat(int d);
|
|
||||||
float EQHtoFloat(int d);
|
|
||||||
int FloatToEQ13(float d);
|
|
||||||
int NewFloatToEQ13(float d);
|
|
||||||
int FloatToEQ19(float d);
|
|
||||||
int FloatToEQH(float d);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define _ITOA_BUFLEN 25
|
|
||||||
const char *itoa(int num); //not thread safe
|
|
||||||
#ifndef _WINDOWS
|
|
||||||
const char *itoa(int num, char* a,int b);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class InitWinsock {
|
|
||||||
public:
|
|
||||||
InitWinsock();
|
|
||||||
~InitWinsock();
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class T> class AutoDelete {
|
|
||||||
public:
|
|
||||||
AutoDelete(T** iVar, T* iSetTo = 0) {
|
|
||||||
init(iVar, iSetTo);
|
|
||||||
}
|
|
||||||
AutoDelete() { pVar = nullptr; }
|
|
||||||
void init(T** iVar, T* iSetTo = 0)
|
|
||||||
{
|
|
||||||
pVar = iVar;
|
|
||||||
if (iSetTo)
|
|
||||||
*pVar = iSetTo;
|
|
||||||
}
|
|
||||||
~AutoDelete() {
|
|
||||||
if(pVar != nullptr)
|
|
||||||
safe_delete(*pVar);
|
|
||||||
}
|
|
||||||
void ReallyClearIt() {
|
|
||||||
pVar = nullptr;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
T** pVar;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@@ -1,261 +0,0 @@
|
|||||||
/* EQEMu: Everquest Server Emulator
|
|
||||||
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
|
||||||
|
|
||||||
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; version 2 of the License.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
||||||
are required to give you total support for your newly bought product;
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
#include "../common/debug.h"
|
|
||||||
#include "../common/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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
MRMutex::MRMutex() {
|
|
||||||
rl = 0;
|
|
||||||
wr = 0;
|
|
||||||
rl = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
MRMutex::~MRMutex() {
|
|
||||||
#ifdef _EQDEBUG
|
|
||||||
if (wl || rl) {
|
|
||||||
std::cout << "MRMutex::~MRMutex: poor cleanup detected: rl=" << rl << ", wl=" << wl << std::endl;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void MRMutex::ReadLock() {
|
|
||||||
while (!TryReadLock()) {
|
|
||||||
Sleep(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MRMutex::TryReadLock() {
|
|
||||||
MCounters.lock();
|
|
||||||
if (!wr && !wl) {
|
|
||||||
rl++;
|
|
||||||
MCounters.unlock();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
MCounters.unlock();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MRMutex::UnReadLock() {
|
|
||||||
MCounters.lock();
|
|
||||||
rl--;
|
|
||||||
MCounters.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MRMutex::WriteLock() {
|
|
||||||
MCounters.lock();
|
|
||||||
if (!rl && !wl) {
|
|
||||||
wl++;
|
|
||||||
MCounters.unlock();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
wr++;
|
|
||||||
MCounters.unlock();
|
|
||||||
while (1) {
|
|
||||||
Sleep(1);
|
|
||||||
MCounters.lock();
|
|
||||||
if (!rl && !wl) {
|
|
||||||
wr--;
|
|
||||||
MCounters.unlock();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
MCounters.lock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MRMutex::TryWriteLock() {
|
|
||||||
MCounters.lock();
|
|
||||||
if (!rl && !wl) {
|
|
||||||
wl++;
|
|
||||||
MCounters.unlock();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
MCounters.unlock();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MRMutex::UnWriteLock() {
|
|
||||||
MCounters.lock();
|
|
||||||
wl--;
|
|
||||||
MCounters.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
int32 MRMutex::ReadLockCount() {
|
|
||||||
MCounters.lock();
|
|
||||||
int32 ret = rl;
|
|
||||||
MCounters.unlock();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32 MRMutex::WriteLockCount() {
|
|
||||||
MCounters.lock();
|
|
||||||
int32 ret = wl;
|
|
||||||
MCounters.unlock();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
/* EQEMu: Everquest Server Emulator
|
|
||||||
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
|
||||||
|
|
||||||
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; version 2 of the License.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
||||||
are required to give you total support for your newly bought product;
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
#ifndef MYMUTEX_H
|
|
||||||
#define MYMUTEX_H
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
#include <winsock.h>
|
|
||||||
#include <windows.h>
|
|
||||||
#else
|
|
||||||
#include <pthread.h>
|
|
||||||
#include "../common/unix.h"
|
|
||||||
#endif
|
|
||||||
#include "../common/types.h"
|
|
||||||
|
|
||||||
class Mutex {
|
|
||||||
public:
|
|
||||||
Mutex();
|
|
||||||
~Mutex();
|
|
||||||
|
|
||||||
void lock();
|
|
||||||
void unlock();
|
|
||||||
bool trylock();
|
|
||||||
protected:
|
|
||||||
private:
|
|
||||||
#if defined WIN32 || defined WIN64
|
|
||||||
CRITICAL_SECTION CSMutex;
|
|
||||||
#else
|
|
||||||
pthread_mutex_t CSMutex;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
class LockMutex {
|
|
||||||
public:
|
|
||||||
LockMutex(Mutex* in_mut, bool iLock = true);
|
|
||||||
~LockMutex();
|
|
||||||
void unlock();
|
|
||||||
void lock();
|
|
||||||
private:
|
|
||||||
bool locked;
|
|
||||||
Mutex* mut;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Somewhat untested...
|
|
||||||
// Multi-read, single write mutex -Quagmire
|
|
||||||
class MRMutex {
|
|
||||||
public:
|
|
||||||
MRMutex();
|
|
||||||
~MRMutex();
|
|
||||||
|
|
||||||
void ReadLock();
|
|
||||||
bool TryReadLock();
|
|
||||||
void UnReadLock();
|
|
||||||
|
|
||||||
void WriteLock();
|
|
||||||
bool TryWriteLock();
|
|
||||||
void UnWriteLock();
|
|
||||||
|
|
||||||
int32 ReadLockCount();
|
|
||||||
int32 WriteLockCount();
|
|
||||||
private:
|
|
||||||
int32 rl; // read locks in effect
|
|
||||||
int32 wr; // write lock requests pending
|
|
||||||
int32 wl; // write locks in effect (should never be more than 1)
|
|
||||||
Mutex MCounters;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@@ -1,355 +0,0 @@
|
|||||||
/* EQEMu: Everquest Server Emulator
|
|
||||||
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
|
|
||||||
|
|
||||||
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; version 2 of the License.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
||||||
are required to give you total support for your newly bought product;
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "debug.h"
|
|
||||||
#include "ProcLauncher.h"
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
#include <windows.h>
|
|
||||||
#else
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ProcLauncher ProcLauncher::s_launcher;
|
|
||||||
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
const ProcLauncher::ProcRef ProcLauncher::ProcError = 0xFFFFFFFF;
|
|
||||||
#else
|
|
||||||
const ProcLauncher::ProcRef ProcLauncher::ProcError = -1;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ProcLauncher::ProcLauncher()
|
|
||||||
{
|
|
||||||
#ifndef WIN32
|
|
||||||
if(signal(SIGCHLD, ProcLauncher::HandleSigChild) == SIG_ERR)
|
|
||||||
fprintf(stderr, "Unable to register child signal handler. Thats bad.");
|
|
||||||
m_signalCount = 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProcLauncher::Process() {
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
std::map<ProcRef, Spec *>::iterator cur, end, tmp;
|
|
||||||
cur = m_running.begin();
|
|
||||||
end = m_running.end();
|
|
||||||
while(cur != end) {
|
|
||||||
DWORD res;
|
|
||||||
if(GetExitCodeProcess(cur->second->proc_info.hProcess, &res)) {
|
|
||||||
//got exit code, see if its still running...
|
|
||||||
if(res == STILL_ACTIVE) {
|
|
||||||
cur++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
//else, it died, handle properly
|
|
||||||
} else {
|
|
||||||
//not sure the right thing to do here... why would this fail?
|
|
||||||
//GetLastError();
|
|
||||||
TerminateProcess(cur->second->proc_info.hProcess, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
//if we get here, the current process died.
|
|
||||||
tmp = cur;
|
|
||||||
tmp++;
|
|
||||||
ProcessTerminated(cur);
|
|
||||||
cur = tmp;
|
|
||||||
}
|
|
||||||
#else //!WIN32
|
|
||||||
while(m_signalCount > 0) {
|
|
||||||
m_signalCount--;
|
|
||||||
int status;
|
|
||||||
ProcRef died = waitpid(-1, &status, WNOHANG);
|
|
||||||
if(died == -1) {
|
|
||||||
//error waiting... shouldent really happen...
|
|
||||||
|
|
||||||
} else if(died == 0) {
|
|
||||||
//nothing pending...
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
//one died...
|
|
||||||
std::map<ProcRef, Spec *>::iterator ref;
|
|
||||||
ref = m_running.find(died);
|
|
||||||
if(ref == m_running.end()) {
|
|
||||||
//unable to find this process in our list...
|
|
||||||
} else {
|
|
||||||
//found... hooray
|
|
||||||
ProcessTerminated(ref);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif //!WIN32
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProcLauncher::ProcessTerminated(std::map<ProcRef, Spec *>::iterator &it) {
|
|
||||||
|
|
||||||
if(it->second->handler != nullptr)
|
|
||||||
it->second->handler->OnTerminate(it->first, it->second);
|
|
||||||
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
CloseHandle(it->second->proc_info.hProcess);
|
|
||||||
#else //!WIN32
|
|
||||||
#endif //!WIN32
|
|
||||||
delete it->second;
|
|
||||||
m_running.erase(it);
|
|
||||||
}
|
|
||||||
|
|
||||||
ProcLauncher::ProcRef ProcLauncher::Launch(Spec *&to_launch) {
|
|
||||||
//consume the pointer
|
|
||||||
Spec *it = to_launch;
|
|
||||||
to_launch = nullptr;
|
|
||||||
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
STARTUPINFO siStartInfo;
|
|
||||||
BOOL bFuncRetn = FALSE;
|
|
||||||
|
|
||||||
// Set up members of the PROCESS_INFORMATION structure.
|
|
||||||
|
|
||||||
ZeroMemory( &it->proc_info, sizeof(PROCESS_INFORMATION) );
|
|
||||||
|
|
||||||
// Set up members of the STARTUPINFO structure.
|
|
||||||
|
|
||||||
ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
|
|
||||||
siStartInfo.cb = sizeof(STARTUPINFO);
|
|
||||||
siStartInfo.dwFlags = 0;
|
|
||||||
|
|
||||||
//handle output redirection.
|
|
||||||
HANDLE logOut = nullptr;
|
|
||||||
BOOL inherit_handles = FALSE;
|
|
||||||
if(it->logFile.length() > 0) {
|
|
||||||
inherit_handles = TRUE;
|
|
||||||
// Set up our log file to redirect output into.
|
|
||||||
SECURITY_ATTRIBUTES saAttr;
|
|
||||||
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
||||||
saAttr.bInheritHandle = TRUE; //we want this handle to be inherited by the child.
|
|
||||||
saAttr.lpSecurityDescriptor = nullptr;
|
|
||||||
logOut = CreateFile(
|
|
||||||
it->logFile.c_str(), //lpFileName
|
|
||||||
FILE_WRITE_DATA, //dwDesiredAccess
|
|
||||||
FILE_SHARE_READ, //dwShareMode
|
|
||||||
&saAttr, //lpSecurityAttributes
|
|
||||||
CREATE_ALWAYS, //dwCreationDisposition
|
|
||||||
FILE_FLAG_NO_BUFFERING, //dwFlagsAndAttributes
|
|
||||||
nullptr ); //hTemplateFile
|
|
||||||
|
|
||||||
//configure the startup info to redirect output appropriately.
|
|
||||||
siStartInfo.hStdError = logOut;
|
|
||||||
siStartInfo.hStdOutput = logOut;
|
|
||||||
siStartInfo.hStdInput = nullptr;
|
|
||||||
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
|
|
||||||
}
|
|
||||||
|
|
||||||
siStartInfo.dwFlags |= CREATE_NEW_CONSOLE;
|
|
||||||
|
|
||||||
// Create the child process.
|
|
||||||
|
|
||||||
//glue together all the nice command line arguments
|
|
||||||
std::string args(it->program);
|
|
||||||
std::vector<std::string>::iterator cur, end;
|
|
||||||
cur = it->args.begin();
|
|
||||||
end = it->args.end();
|
|
||||||
for(; cur != end; cur++) {
|
|
||||||
args += " ";
|
|
||||||
args += *cur;
|
|
||||||
}
|
|
||||||
|
|
||||||
bFuncRetn = CreateProcess(it->program.c_str(),
|
|
||||||
const_cast<char *>(args.c_str()), // command line
|
|
||||||
nullptr, // process security attributes
|
|
||||||
nullptr, // primary thread security attributes
|
|
||||||
inherit_handles, // handles are not inherited
|
|
||||||
0, // creation flags (CREATE_NEW_PROCESS_GROUP maybe)
|
|
||||||
nullptr, // use parent's environment
|
|
||||||
nullptr, // use parent's current directory
|
|
||||||
&siStartInfo, // STARTUPINFO pointer
|
|
||||||
&it->proc_info); // receives PROCESS_INFORMATION
|
|
||||||
|
|
||||||
if (bFuncRetn == 0) {
|
|
||||||
safe_delete(it);
|
|
||||||
//GetLastError()
|
|
||||||
return(ProcError);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//keep process handle open to get exit code
|
|
||||||
CloseHandle(it->proc_info.hThread); //we dont need their thread handle
|
|
||||||
if(logOut != nullptr)
|
|
||||||
CloseHandle(logOut); //we dont want their output handle either.
|
|
||||||
|
|
||||||
ProcRef res = it->proc_info.dwProcessId;
|
|
||||||
|
|
||||||
//record this entry..
|
|
||||||
m_running[res] = it;
|
|
||||||
|
|
||||||
return(res);
|
|
||||||
|
|
||||||
#else //!WIN32
|
|
||||||
|
|
||||||
//build argv
|
|
||||||
char **argv = new char *[it->args.size()+2];
|
|
||||||
unsigned int r;
|
|
||||||
argv[0] = const_cast<char *>(it->program.c_str());
|
|
||||||
for(r = 1; r <= it->args.size(); r++) {
|
|
||||||
argv[r] = const_cast<char *>(it->args[r-1].c_str());
|
|
||||||
}
|
|
||||||
argv[r] = nullptr;
|
|
||||||
|
|
||||||
ProcRef res = fork(); //cant use vfork since we are opening the log file.
|
|
||||||
if(res == -1) {
|
|
||||||
//error forking... errno
|
|
||||||
safe_delete(it);
|
|
||||||
safe_delete_array(argv);
|
|
||||||
return(ProcError);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(res == 0) {
|
|
||||||
//child... exec this bitch
|
|
||||||
|
|
||||||
//handle output redirection if requested.
|
|
||||||
if(it->logFile.length() > 0) {
|
|
||||||
//we will put their output directly into a file.
|
|
||||||
int outfd = creat(it->logFile.c_str(), S_IRUSR | S_IWUSR | S_IRGRP); // S_I + R/W/X + USR/GRP/OTH
|
|
||||||
if(outfd == -1) {
|
|
||||||
fprintf(stderr, "Unable to open log file %s: %s.\n", it->logFile.c_str(), strerror(errno));
|
|
||||||
close(STDOUT_FILENO);
|
|
||||||
close(STDERR_FILENO);
|
|
||||||
close(STDIN_FILENO);
|
|
||||||
} else {
|
|
||||||
close(STDOUT_FILENO);
|
|
||||||
if(dup2(outfd, STDOUT_FILENO) == -1) {
|
|
||||||
fprintf(stderr, "Unable to duplicate FD %d to %d. Log file will be empty: %s\n", outfd, STDOUT_FILENO, strerror(errno));
|
|
||||||
const char *err = "Unable to redirect stdout into this file. That sucks.";
|
|
||||||
write(outfd, err, strlen(err));
|
|
||||||
}
|
|
||||||
close(STDERR_FILENO);
|
|
||||||
if(dup2(outfd, STDERR_FILENO) == -1) {
|
|
||||||
//can no longer print to screen..
|
|
||||||
const char *err = "Unable to redirect stderr into this file. You might miss some error info in this log.";
|
|
||||||
write(outfd, err, strlen(err));
|
|
||||||
}
|
|
||||||
close(STDIN_FILENO);
|
|
||||||
|
|
||||||
close(outfd); //dont need this one, we have two more copies...
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//call it...
|
|
||||||
execv(argv[0], argv);
|
|
||||||
_exit(1);
|
|
||||||
}
|
|
||||||
safe_delete_array(argv);
|
|
||||||
|
|
||||||
//record this entry..
|
|
||||||
m_running[res] = it;
|
|
||||||
|
|
||||||
return(res);
|
|
||||||
#endif //!WIN32
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//if graceful is true, we try to be nice about it if possible
|
|
||||||
bool ProcLauncher::Terminate(const ProcRef &proc, bool graceful) {
|
|
||||||
//we are only willing to kill things we started...
|
|
||||||
std::map<ProcRef, Spec *>::iterator res = m_running.find(proc);
|
|
||||||
if(res == m_running.end())
|
|
||||||
return(false);
|
|
||||||
|
|
||||||
//we do not remove it from the list until we have been notified
|
|
||||||
//that they have been terminated.
|
|
||||||
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
if(!TerminateProcess(res->second->proc_info.hProcess, 0)) {
|
|
||||||
return(false);
|
|
||||||
}
|
|
||||||
#else //!WIN32
|
|
||||||
int sig;
|
|
||||||
if(graceful)
|
|
||||||
sig = SIGTERM;
|
|
||||||
else
|
|
||||||
sig = SIGKILL;
|
|
||||||
if(kill(proc, sig) == -1) {
|
|
||||||
return(false);
|
|
||||||
}
|
|
||||||
#endif //!WIN32
|
|
||||||
return(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProcLauncher::TerminateAll(bool final) {
|
|
||||||
if(!final) {
|
|
||||||
//send a nice terminate to each process, with intention of waiting for them
|
|
||||||
std::map<ProcRef, Spec *>::iterator cur, end;
|
|
||||||
cur = m_running.begin();
|
|
||||||
end = m_running.end();
|
|
||||||
for(; cur != end; cur++) {
|
|
||||||
Terminate(cur->first, true);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//kill each process and remove it from the list
|
|
||||||
std::map<ProcRef, Spec *> running(m_running);
|
|
||||||
m_running.clear();
|
|
||||||
|
|
||||||
std::map<ProcRef, Spec *>::iterator cur, end;
|
|
||||||
cur = running.begin();
|
|
||||||
end = running.end();
|
|
||||||
for(; cur != end; cur++) {
|
|
||||||
Terminate(cur->first, true);
|
|
||||||
safe_delete(cur->second);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef WIN32
|
|
||||||
void ProcLauncher::HandleSigChild(int signum) {
|
|
||||||
if(signum == SIGCHLD) {
|
|
||||||
ProcLauncher::get()->m_signalCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ProcLauncher::Spec::Spec() {
|
|
||||||
handler = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
ProcLauncher::Spec::Spec(const Spec &other) {
|
|
||||||
program = other.program;
|
|
||||||
args = other.args;
|
|
||||||
handler = other.handler;
|
|
||||||
logFile = other.logFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
ProcLauncher::Spec &ProcLauncher::Spec::operator=(const Spec &other) {
|
|
||||||
program = other.program;
|
|
||||||
args = other.args;
|
|
||||||
handler = other.handler;
|
|
||||||
logFile = other.logFile;
|
|
||||||
return(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
/* EQEMu: Everquest Server Emulator
|
|
||||||
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
|
|
||||||
|
|
||||||
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; version 2 of the License.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
||||||
are required to give you total support for your newly bought product;
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
#ifndef PROCLAUNCHER_H_
|
|
||||||
#define PROCLAUNCHER_H_
|
|
||||||
|
|
||||||
#include "debug.h"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
//I forced this object to become a singleton because it registers its
|
|
||||||
//signal handler for UNIX
|
|
||||||
class ProcLauncher {
|
|
||||||
ProcLauncher();
|
|
||||||
public:
|
|
||||||
//Singleton method
|
|
||||||
static ProcLauncher *get() { return(&s_launcher); }
|
|
||||||
static void ProcessInThisThread();
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
typedef DWORD ProcRef;
|
|
||||||
static const ProcRef ProcError;
|
|
||||||
#else
|
|
||||||
typedef pid_t ProcRef;
|
|
||||||
static const ProcRef ProcError;
|
|
||||||
#endif
|
|
||||||
class EventHandler;
|
|
||||||
class Spec {
|
|
||||||
friend class ProcLauncher; //for visual c++
|
|
||||||
public:
|
|
||||||
Spec();
|
|
||||||
Spec(const Spec &other);
|
|
||||||
Spec &operator=(const Spec &other);
|
|
||||||
|
|
||||||
std::string program;
|
|
||||||
std::vector<std::string> args;
|
|
||||||
//std::map<std::string,std::string> environment;
|
|
||||||
EventHandler *handler; //optional, we do not own this pointer
|
|
||||||
std::string logFile; //empty = do not redirect output.
|
|
||||||
protected:
|
|
||||||
//None of these fields get copied around
|
|
||||||
#ifdef WIN32
|
|
||||||
PROCESS_INFORMATION proc_info;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
class EventHandler {
|
|
||||||
public:
|
|
||||||
virtual ~EventHandler() {}
|
|
||||||
virtual void OnTerminate(const ProcRef &ref, const Spec *spec) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* The main launch method, call to start a new background process. */
|
|
||||||
ProcRef Launch(Spec *&to_launch); //takes ownership of the pointer
|
|
||||||
|
|
||||||
/* The terminate method */
|
|
||||||
bool Terminate(const ProcRef &proc, bool graceful = true);
|
|
||||||
void TerminateAll(bool final = true);
|
|
||||||
|
|
||||||
/* The main processing method. Call regularly to check for terminated background processes. */
|
|
||||||
void Process();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
//std::vector<Spec *> m_specs;
|
|
||||||
std::map<ProcRef, Spec *> m_running; //we own the pointers in this map
|
|
||||||
|
|
||||||
void ProcessTerminated(std::map<ProcRef, Spec *>::iterator &it);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static ProcLauncher s_launcher;
|
|
||||||
#ifndef WIN32
|
|
||||||
uint32 m_signalCount;
|
|
||||||
static void HandleSigChild(int signum);
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /*PROCLAUNCHER_H_*/
|
|
||||||
|
|
||||||
@@ -1,266 +0,0 @@
|
|||||||
/** \file Base64.cpp
|
|
||||||
** \date 2004-02-13
|
|
||||||
** \author grymse@alhem.net
|
|
||||||
**/
|
|
||||||
/*
|
|
||||||
Copyright (C) 2004,2005 Anders Hedstrom
|
|
||||||
|
|
||||||
This library is made available under the terms of the GNU GPL.
|
|
||||||
|
|
||||||
If you would like to use this library in a closed-source application,
|
|
||||||
a separate license agreement is available. For information about
|
|
||||||
the closed-source license agreement for the C++ sockets library,
|
|
||||||
please visit http://www.alhem.net/Sockets/license.html and/or
|
|
||||||
email license@alhem.net.
|
|
||||||
|
|
||||||
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 2
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
#include "Base64.h"
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
namespace SOCKETS_NAMESPACE {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
const char *Base64::bstr =
|
|
||||||
"ABCDEFGHIJKLMNOPQ"
|
|
||||||
"RSTUVWXYZabcdefgh"
|
|
||||||
"ijklmnopqrstuvwxy"
|
|
||||||
"z0123456789+/";
|
|
||||||
|
|
||||||
const char Base64::rstr[] = {
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 63,
|
|
||||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
|
||||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0,
|
|
||||||
0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
|
|
||||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0};
|
|
||||||
|
|
||||||
|
|
||||||
void Base64::encode(FILE *fil, std::string& output, bool add_crlf)
|
|
||||||
{
|
|
||||||
size_t remain;
|
|
||||||
size_t i = 0;
|
|
||||||
size_t o = 0;
|
|
||||||
char input[4];
|
|
||||||
|
|
||||||
output = "";
|
|
||||||
remain = fread(input,1,3,fil);
|
|
||||||
while (remain > 0)
|
|
||||||
{
|
|
||||||
if (add_crlf && o && o % 76 == 0)
|
|
||||||
output += "\n";
|
|
||||||
switch (remain)
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
output += bstr[ ((input[i] >> 2) & 0x3f) ];
|
|
||||||
output += bstr[ ((input[i] << 4) & 0x30) ];
|
|
||||||
output += "==";
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
output += bstr[ ((input[i] >> 2) & 0x3f) ];
|
|
||||||
output += bstr[ ((input[i] << 4) & 0x30) + ((input[i + 1] >> 4) & 0x0f) ];
|
|
||||||
output += bstr[ ((input[i + 1] << 2) & 0x3c) ];
|
|
||||||
output += "=";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
output += bstr[ ((input[i] >> 2) & 0x3f) ];
|
|
||||||
output += bstr[ ((input[i] << 4) & 0x30) + ((input[i + 1] >> 4) & 0x0f) ];
|
|
||||||
output += bstr[ ((input[i + 1] << 2) & 0x3c) + ((input[i + 2] >> 6) & 0x03) ];
|
|
||||||
output += bstr[ (input[i + 2] & 0x3f) ];
|
|
||||||
}
|
|
||||||
o += 4;
|
|
||||||
//
|
|
||||||
remain = fread(input,1,3,fil);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Base64::encode(const std::string& str_in, std::string& str_out, bool add_crlf)
|
|
||||||
{
|
|
||||||
encode(str_in.c_str(), str_in.size(), str_out, add_crlf);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Base64::encode(const char* input,size_t l,std::string& output, bool add_crlf)
|
|
||||||
{
|
|
||||||
size_t i = 0;
|
|
||||||
size_t o = 0;
|
|
||||||
|
|
||||||
output = "";
|
|
||||||
while (i < l)
|
|
||||||
{
|
|
||||||
size_t remain = l - i;
|
|
||||||
if (add_crlf && o && o % 76 == 0)
|
|
||||||
output += "\n";
|
|
||||||
switch (remain)
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
output += bstr[ ((input[i] >> 2) & 0x3f) ];
|
|
||||||
output += bstr[ ((input[i] << 4) & 0x30) ];
|
|
||||||
output += "==";
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
output += bstr[ ((input[i] >> 2) & 0x3f) ];
|
|
||||||
output += bstr[ ((input[i] << 4) & 0x30) + ((input[i + 1] >> 4) & 0x0f) ];
|
|
||||||
output += bstr[ ((input[i + 1] << 2) & 0x3c) ];
|
|
||||||
output += "=";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
output += bstr[ ((input[i] >> 2) & 0x3f) ];
|
|
||||||
output += bstr[ ((input[i] << 4) & 0x30) + ((input[i + 1] >> 4) & 0x0f) ];
|
|
||||||
output += bstr[ ((input[i + 1] << 2) & 0x3c) + ((input[i + 2] >> 6) & 0x03) ];
|
|
||||||
output += bstr[ (input[i + 2] & 0x3f) ];
|
|
||||||
}
|
|
||||||
o += 4;
|
|
||||||
i += 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Base64::encode(unsigned char* input,size_t l,std::string& output,bool add_crlf)
|
|
||||||
{
|
|
||||||
size_t i = 0;
|
|
||||||
size_t o = 0;
|
|
||||||
|
|
||||||
output = "";
|
|
||||||
while (i < l)
|
|
||||||
{
|
|
||||||
size_t remain = l - i;
|
|
||||||
if (add_crlf && o && o % 76 == 0)
|
|
||||||
output += "\n";
|
|
||||||
switch (remain)
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
output += bstr[ ((input[i] >> 2) & 0x3f) ];
|
|
||||||
output += bstr[ ((input[i] << 4) & 0x30) ];
|
|
||||||
output += "==";
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
output += bstr[ ((input[i] >> 2) & 0x3f) ];
|
|
||||||
output += bstr[ ((input[i] << 4) & 0x30) + ((input[i + 1] >> 4) & 0x0f) ];
|
|
||||||
output += bstr[ ((input[i + 1] << 2) & 0x3c) ];
|
|
||||||
output += "=";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
output += bstr[ ((input[i] >> 2) & 0x3f) ];
|
|
||||||
output += bstr[ ((input[i] << 4) & 0x30) + ((input[i + 1] >> 4) & 0x0f) ];
|
|
||||||
output += bstr[ ((input[i + 1] << 2) & 0x3c) + ((input[i + 2] >> 6) & 0x03) ];
|
|
||||||
output += bstr[ (input[i + 2] & 0x3f) ];
|
|
||||||
}
|
|
||||||
o += 4;
|
|
||||||
i += 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Base64::decode(const std::string& input,std::string& output)
|
|
||||||
{
|
|
||||||
size_t i = 0;
|
|
||||||
size_t l = input.size();
|
|
||||||
|
|
||||||
output = "";
|
|
||||||
while (i < l)
|
|
||||||
{
|
|
||||||
while (i < l && (input[i] == 13 || input[i] == 10))
|
|
||||||
i++;
|
|
||||||
if (i < l)
|
|
||||||
{
|
|
||||||
char b1 = (char)((rstr[(int)input[i]] << 2 & 0xfc) +
|
|
||||||
(rstr[(int)input[i + 1]] >> 4 & 0x03));
|
|
||||||
output += b1;
|
|
||||||
if (input[i + 2] != '=')
|
|
||||||
{
|
|
||||||
char b2 = (char)((rstr[(int)input[i + 1]] << 4 & 0xf0) +
|
|
||||||
(rstr[(int)input[i + 2]] >> 2 & 0x0f));
|
|
||||||
output += b2;
|
|
||||||
}
|
|
||||||
if (input[i + 3] != '=')
|
|
||||||
{
|
|
||||||
char b3 = (char)((rstr[(int)input[i + 2]] << 6 & 0xc0) +
|
|
||||||
rstr[(int)input[i + 3]]);
|
|
||||||
output += b3;
|
|
||||||
}
|
|
||||||
i += 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Base64::decode(const std::string& input, unsigned char *output, size_t& sz)
|
|
||||||
{
|
|
||||||
size_t i = 0;
|
|
||||||
size_t l = input.size();
|
|
||||||
size_t j = 0;
|
|
||||||
|
|
||||||
while (i < l)
|
|
||||||
{
|
|
||||||
while (i < l && (input[i] == 13 || input[i] == 10))
|
|
||||||
i++;
|
|
||||||
if (i < l)
|
|
||||||
{
|
|
||||||
unsigned char b1 = (unsigned char)((rstr[(int)input[i]] << 2 & 0xfc) +
|
|
||||||
(rstr[(int)input[i + 1]] >> 4 & 0x03));
|
|
||||||
if (output)
|
|
||||||
{
|
|
||||||
output[j] = b1;
|
|
||||||
}
|
|
||||||
j++;
|
|
||||||
if (input[i + 2] != '=')
|
|
||||||
{
|
|
||||||
unsigned char b2 = (unsigned char)((rstr[(int)input[i + 1]] << 4 & 0xf0) +
|
|
||||||
(rstr[(int)input[i + 2]] >> 2 & 0x0f));
|
|
||||||
if (output)
|
|
||||||
{
|
|
||||||
output[j] = b2;
|
|
||||||
}
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
if (input[i + 3] != '=')
|
|
||||||
{
|
|
||||||
unsigned char b3 = (unsigned char)((rstr[(int)input[i + 2]] << 6 & 0xc0) +
|
|
||||||
rstr[(int)input[i + 3]]);
|
|
||||||
if (output)
|
|
||||||
{
|
|
||||||
output[j] = b3;
|
|
||||||
}
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
i += 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sz = j;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
size_t Base64::decode_length(const std::string& str64)
|
|
||||||
{
|
|
||||||
if (!str64.size() || str64.size() % 4)
|
|
||||||
return 0;
|
|
||||||
size_t l = 3 * (str64.size() / 4 - 1) + 1;
|
|
||||||
if (str64[str64.size() - 2] != '=')
|
|
||||||
l++;
|
|
||||||
if (str64[str64.size() - 1] != '=')
|
|
||||||
l++;
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
/** \file Base64.h
|
|
||||||
** \date 2004-02-13
|
|
||||||
** \author grymse@alhem.net
|
|
||||||
**/
|
|
||||||
/*
|
|
||||||
Copyright (C) 2004,2005 Anders Hedstrom
|
|
||||||
|
|
||||||
This library is made available under the terms of the GNU GPL.
|
|
||||||
|
|
||||||
If you would like to use this library in a closed-source application,
|
|
||||||
a separate license agreement is available. For information about
|
|
||||||
the closed-source license agreement for the C++ sockets library,
|
|
||||||
please visit http://www.alhem.net/Sockets/license.html and/or
|
|
||||||
email license@alhem.net.
|
|
||||||
|
|
||||||
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 2
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
#ifndef _BASE64_H
|
|
||||||
#define _BASE64_H
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
namespace SOCKETS_NAMESPACE {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** \defgroup util Utilities */
|
|
||||||
|
|
||||||
/** Base64 encode/decode.
|
|
||||||
\ingroup util */
|
|
||||||
class Base64 {
|
|
||||||
public:
|
|
||||||
|
|
||||||
static void encode(FILE *, std::string& , bool add_crlf = true);
|
|
||||||
static void encode(const std::string&, std::string& , bool add_crlf = true);
|
|
||||||
static void encode(const char *, size_t, std::string& , bool add_crlf = true);
|
|
||||||
static void encode(unsigned char *, size_t, std::string& , bool add_crlf = true);
|
|
||||||
|
|
||||||
static void decode(const std::string&, std::string& );
|
|
||||||
static void decode(const std::string& in, unsigned char *out, size_t&);
|
|
||||||
|
|
||||||
static size_t decode_length(const std::string& );
|
|
||||||
|
|
||||||
private:
|
|
||||||
static const char *bstr;
|
|
||||||
static const char rstr[128];
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // _BASE64_H
|
|
||||||
@@ -1,126 +0,0 @@
|
|||||||
/** \file File.cpp
|
|
||||||
** \date 2005-04-25
|
|
||||||
** \author grymse@alhem.net
|
|
||||||
**/
|
|
||||||
/*
|
|
||||||
Copyright (C) 2004,2005 Anders Hedstrom
|
|
||||||
|
|
||||||
This library is made available under the terms of the GNU GPL.
|
|
||||||
|
|
||||||
If you would like to use this library in a closed-source application,
|
|
||||||
a separate license agreement is available. For information about
|
|
||||||
the closed-source license agreement for the C++ sockets library,
|
|
||||||
please visit http://www.alhem.net/Sockets/license.html and/or
|
|
||||||
email license@alhem.net.
|
|
||||||
|
|
||||||
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 2
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#ifndef _WIN32
|
|
||||||
#include <unistd.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "File.h"
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
namespace SOCKETS_NAMESPACE {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
File::File()
|
|
||||||
:m_fil(nullptr)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
File::~File()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool File::fopen(const std::string& path, const std::string& mode)
|
|
||||||
{
|
|
||||||
m_path = path;
|
|
||||||
m_mode = mode;
|
|
||||||
m_fil = ::fopen(path.c_str(), mode.c_str());
|
|
||||||
return m_fil ? true : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void File::fclose()
|
|
||||||
{
|
|
||||||
if (m_fil)
|
|
||||||
::fclose(m_fil);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
size_t File::fread(char *ptr, size_t size, size_t nmemb)
|
|
||||||
{
|
|
||||||
return m_fil ? ::fread(ptr, size, nmemb, m_fil) : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
size_t File::fwrite(const char *ptr, size_t size, size_t nmemb)
|
|
||||||
{
|
|
||||||
return m_fil ? ::fwrite(ptr, size, nmemb, m_fil) : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
char *File::fgets(char *s, int size)
|
|
||||||
{
|
|
||||||
return m_fil ? ::fgets(s, size, m_fil) : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void File::fprintf(char *format, ...)
|
|
||||||
{
|
|
||||||
va_list ap;
|
|
||||||
va_start(ap, format);
|
|
||||||
vfprintf(m_fil, format, ap);
|
|
||||||
va_end(ap);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
off_t File::size()
|
|
||||||
{
|
|
||||||
struct stat st;
|
|
||||||
if (stat(m_path.c_str(), &st) == -1)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return st.st_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool File::eof()
|
|
||||||
{
|
|
||||||
if (m_fil)
|
|
||||||
{
|
|
||||||
if (feof(m_fil))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
/** \file File.h
|
|
||||||
** \date 2005-04-25
|
|
||||||
** \author grymse@alhem.net
|
|
||||||
**/
|
|
||||||
/*
|
|
||||||
Copyright (C) 2004,2005 Anders Hedstrom
|
|
||||||
|
|
||||||
This library is made available under the terms of the GNU GPL.
|
|
||||||
|
|
||||||
If you would like to use this library in a closed-source application,
|
|
||||||
a separate license agreement is available. For information about
|
|
||||||
the closed-source license agreement for the C++ sockets library,
|
|
||||||
please visit http://www.alhem.net/Sockets/license.html and/or
|
|
||||||
email license@alhem.net.
|
|
||||||
|
|
||||||
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 2
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
#ifndef _FILE_H
|
|
||||||
#define _FILE_H
|
|
||||||
|
|
||||||
#include "IFile.h"
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
namespace SOCKETS_NAMESPACE {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/** IFile implementation of a disk file.
|
|
||||||
\ingroup file */
|
|
||||||
class File : public IFile
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
File();
|
|
||||||
~File();
|
|
||||||
|
|
||||||
bool fopen(const std::string&, const std::string&);
|
|
||||||
void fclose();
|
|
||||||
|
|
||||||
size_t fread(char *, size_t, size_t);
|
|
||||||
size_t fwrite(const char *, size_t, size_t);
|
|
||||||
|
|
||||||
char *fgets(char *, int);
|
|
||||||
void fprintf(char *format, ...);
|
|
||||||
|
|
||||||
off_t size();
|
|
||||||
bool eof();
|
|
||||||
|
|
||||||
private:
|
|
||||||
File(const File& ) {} // copy constructor
|
|
||||||
File& operator=(const File& ) { return *this; } // assignment operator
|
|
||||||
|
|
||||||
std::string m_path;
|
|
||||||
std::string m_mode;
|
|
||||||
FILE *m_fil;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // _FILE_H
|
|
||||||
@@ -1,366 +0,0 @@
|
|||||||
/* EQEMu: Everquest Server Emulator
|
|
||||||
*
|
|
||||||
* This code originated from `C++ Sockets Library` referenced below.
|
|
||||||
* Taken and stripped/modified to remove dependancies on parts of
|
|
||||||
* the library which we are not using, and to suit other needs.
|
|
||||||
* 2006 - EQEMu Development Team (http://eqemulator.net)
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** \file HTTPSocket.cpp
|
|
||||||
** \date 2004-04-06
|
|
||||||
** \author grymse@alhem.net
|
|
||||||
**/
|
|
||||||
/*
|
|
||||||
Copyright (C) 2004,2005 Anders Hedstrom
|
|
||||||
|
|
||||||
This library is made available under the terms of the GNU GPL.
|
|
||||||
|
|
||||||
If you would like to use this library in a closed-source application,
|
|
||||||
a separate license agreement is available. For information about
|
|
||||||
the closed-source license agreement for the C++ sockets library,
|
|
||||||
please visit http://www.alhem.net/Sockets/license.html and/or
|
|
||||||
email license@alhem.net.
|
|
||||||
|
|
||||||
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 2
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
#ifdef _WIN32
|
|
||||||
#pragma warning(disable:4786)
|
|
||||||
#endif
|
|
||||||
#include "../debug.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include "Parse.h"
|
|
||||||
#include "HTTPSocket.h"
|
|
||||||
#include "../TCPConnection.h"
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
namespace SOCKETS_NAMESPACE {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
HTTPSocket::HTTPSocket(uint32 ID, SOCKET in_socket, uint32 irIP, uint16 irPort)
|
|
||||||
:TCPConnection(ID,in_socket,irIP,irPort)
|
|
||||||
,m_first(true)
|
|
||||||
,m_header(true)
|
|
||||||
,m_http_version("HTTP/1.0")
|
|
||||||
,m_request(false)
|
|
||||||
,m_response(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
HTTPSocket::~HTTPSocket()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* eqemu stuff
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool HTTPSocket::ProcessReceivedData(char *errbuf)
|
|
||||||
{
|
|
||||||
if (errbuf)
|
|
||||||
errbuf[0] = 0;
|
|
||||||
if (!recvbuf)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
char *buff=(char *)recvbuf;
|
|
||||||
unsigned long bufflen=recvbuf_used;
|
|
||||||
|
|
||||||
while(1) {
|
|
||||||
if (m_header) {
|
|
||||||
char *ptr=(char *)memchr(buff,'\n',bufflen);
|
|
||||||
if (!ptr)
|
|
||||||
break;
|
|
||||||
int length=(ptr-buff)+1;
|
|
||||||
std::string line;
|
|
||||||
line.append(buff,length-2);
|
|
||||||
OnLine(line);
|
|
||||||
|
|
||||||
buff+=length;
|
|
||||||
bufflen-=length;
|
|
||||||
} else {
|
|
||||||
OnData(buff,bufflen);
|
|
||||||
buff+=bufflen;
|
|
||||||
bufflen=0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bufflen) {
|
|
||||||
memmove(recvbuf,buff,bufflen);
|
|
||||||
recvbuf_used=bufflen;
|
|
||||||
} else {
|
|
||||||
safe_delete_array(recvbuf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HTTPSocket::SendString(const char *str) {
|
|
||||||
return(TCPConnection::Send((const uchar *) str, strlen(str)));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HTTPSocket::SendBuf(const char *dat, unsigned int len) {
|
|
||||||
return(TCPConnection::Send((const uchar *) dat, len));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* /eqemu stuff
|
|
||||||
*/
|
|
||||||
|
|
||||||
void HTTPSocket::OnLine(const std::string& line)
|
|
||||||
{
|
|
||||||
if (m_first)
|
|
||||||
{
|
|
||||||
Parse pa(line);
|
|
||||||
std::string str = pa.getword();
|
|
||||||
if (str.substr(0,4) == "HTTP") // response
|
|
||||||
{
|
|
||||||
m_http_version = str;
|
|
||||||
m_status = pa.getword();
|
|
||||||
m_status_text = pa.getrest();
|
|
||||||
m_response = true;
|
|
||||||
}
|
|
||||||
else // request
|
|
||||||
{
|
|
||||||
m_method = str;
|
|
||||||
m_url = pa.getword();
|
|
||||||
size_t spl = m_url.find("?");
|
|
||||||
if (spl != std::string::npos)
|
|
||||||
{
|
|
||||||
m_uri = m_url.substr(0,spl);
|
|
||||||
m_query_string = m_url.substr(spl + 1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_uri = m_url;
|
|
||||||
}
|
|
||||||
m_http_version = pa.getword();
|
|
||||||
m_request = true;
|
|
||||||
}
|
|
||||||
m_first = false;
|
|
||||||
OnFirst();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!line.size())
|
|
||||||
{
|
|
||||||
// SetLineProtocol(false);
|
|
||||||
m_header = false;
|
|
||||||
OnHeaderComplete();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Parse pa(line,":");
|
|
||||||
std::string key = pa.getword();
|
|
||||||
std::string value = pa.getrest();
|
|
||||||
OnHeader(key,value);
|
|
||||||
/* If remote end tells us to keep connection alive, and we're operating
|
|
||||||
in http/1.1 mode (not http/1.0 mode), then we mark the socket to be
|
|
||||||
retained. */
|
|
||||||
/* if (!strcasecmp(key.c_str(), "connection") &&
|
|
||||||
!strcasecmp(value.c_str(), "keep-alive") )
|
|
||||||
{
|
|
||||||
SetRetain();
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void HTTPSocket::SendResponse()
|
|
||||||
{
|
|
||||||
std::string msg;
|
|
||||||
msg = m_http_version + " " + m_status + " " + m_status_text + "\r\n";
|
|
||||||
for (string_m::iterator it = m_response_header.begin(); it != m_response_header.end(); it++)
|
|
||||||
{
|
|
||||||
std::string key = (*it).first;
|
|
||||||
std::string val = (*it).second;
|
|
||||||
msg += key + ": " + val + "\r\n";
|
|
||||||
}
|
|
||||||
msg += "\r\n";
|
|
||||||
SendString( msg.c_str() );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void HTTPSocket::AddResponseHeader(const std::string& header, const char *format, ...)
|
|
||||||
{
|
|
||||||
static char slask[5000];
|
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
va_start(ap, format);
|
|
||||||
#ifdef _WIN32
|
|
||||||
vsprintf(slask, format, ap);
|
|
||||||
#else
|
|
||||||
vsnprintf(slask, 5000, format, ap);
|
|
||||||
#endif
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
m_response_header[header] = slask;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void HTTPSocket::SendRequest()
|
|
||||||
{
|
|
||||||
std::string msg;
|
|
||||||
msg = m_method + " " + m_url + " " + m_http_version + "\r\n";
|
|
||||||
for (string_m::iterator it = m_response_header.begin(); it != m_response_header.end(); it++)
|
|
||||||
{
|
|
||||||
std::string key = (*it).first;
|
|
||||||
std::string val = (*it).second;
|
|
||||||
msg += key + ": " + val + "\r\n";
|
|
||||||
}
|
|
||||||
msg += "\r\n";
|
|
||||||
SendString( msg.c_str() );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::string HTTPSocket::MyUseragent()
|
|
||||||
{
|
|
||||||
std::string version = "C++Sockets/";
|
|
||||||
#ifdef _VERSION
|
|
||||||
version += _VERSION;
|
|
||||||
#endif
|
|
||||||
return version;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void HTTPSocket::Reset()
|
|
||||||
{
|
|
||||||
m_first = true;
|
|
||||||
m_header = true;
|
|
||||||
m_request = false;
|
|
||||||
m_response = false;
|
|
||||||
// SetLineProtocol(true);
|
|
||||||
while (m_response_header.size())
|
|
||||||
{
|
|
||||||
string_m::iterator it = m_response_header.begin();
|
|
||||||
m_response_header.erase(it);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const std::string& HTTPSocket::GetMethod()
|
|
||||||
{
|
|
||||||
return m_method;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void HTTPSocket::SetMethod(const std::string& x)
|
|
||||||
{
|
|
||||||
m_method = x;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const std::string& HTTPSocket::GetUrl()
|
|
||||||
{
|
|
||||||
return m_url;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void HTTPSocket::SetUrl(const std::string& x)
|
|
||||||
{
|
|
||||||
m_url = x;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const std::string& HTTPSocket::GetUri()
|
|
||||||
{
|
|
||||||
return m_uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const std::string& HTTPSocket::GetQueryString()
|
|
||||||
{
|
|
||||||
return m_query_string;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const std::string& HTTPSocket::GetHttpVersion()
|
|
||||||
{
|
|
||||||
return m_http_version;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const std::string& HTTPSocket::GetStatus()
|
|
||||||
{
|
|
||||||
return m_status;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const std::string& HTTPSocket::GetStatusText()
|
|
||||||
{
|
|
||||||
return m_status_text;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool HTTPSocket::IsRequest()
|
|
||||||
{
|
|
||||||
return m_request;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool HTTPSocket::IsResponse()
|
|
||||||
{
|
|
||||||
return m_response;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void HTTPSocket::SetHttpVersion(const std::string& x)
|
|
||||||
{
|
|
||||||
m_http_version = x;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void HTTPSocket::SetStatus(const std::string& num, const std::string& text) {
|
|
||||||
m_status = num;
|
|
||||||
m_status_text = text;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HTTPSocket::SetStatus(const std::string& x)
|
|
||||||
{
|
|
||||||
m_status = x;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void HTTPSocket::SetStatusText(const std::string& x)
|
|
||||||
{
|
|
||||||
m_status_text = x;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void HTTPSocket::AddResponseHeader(const std::string& x,const std::string& y)
|
|
||||||
{
|
|
||||||
m_response_header[x] = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void HTTPSocket::SetUri(const std::string& x)
|
|
||||||
{
|
|
||||||
m_uri = x;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HTTPSocket::SendResponse(const std::string& status_num, const std::string& status_text) {
|
|
||||||
SetStatus(status_num, status_text);
|
|
||||||
SendResponse();
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@@ -1,137 +0,0 @@
|
|||||||
/* EQEMu: Everquest Server Emulator
|
|
||||||
*
|
|
||||||
* This code originated from `C++ Sockets Library` referenced below.
|
|
||||||
* Taken and stripped/modified to remove dependancies on parts of
|
|
||||||
* the library which we are not using, and to suit other needs.
|
|
||||||
* 2006 - EQEMu Development Team (http://eqemulator.net)
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** \file HTTPSocket.h Class HTTPSocket definition.
|
|
||||||
** \date 2004-04-06
|
|
||||||
** \author grymse@alhem.net
|
|
||||||
**/
|
|
||||||
/*
|
|
||||||
Copyright (C) 2004,2005 Anders Hedstrom
|
|
||||||
|
|
||||||
This library is made available under the terms of the GNU GPL.
|
|
||||||
|
|
||||||
If you would like to use this library in a closed-source application,
|
|
||||||
a separate license agreement is available. For information about
|
|
||||||
the closed-source license agreement for the C++ sockets library,
|
|
||||||
please visit http://www.alhem.net/Sockets/license.html and/or
|
|
||||||
email license@alhem.net.
|
|
||||||
|
|
||||||
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 2
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
#ifndef _HTTPSOCKET_H
|
|
||||||
#define _HTTPSOCKET_H
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <string>
|
|
||||||
#include "../TCPConnection.h"
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
namespace SOCKETS_NAMESPACE {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** \defgroup http HTTP Sockets */
|
|
||||||
/** HTTP request/response base class.
|
|
||||||
\ingroup http */
|
|
||||||
class HTTPSocket : public TCPConnection
|
|
||||||
{
|
|
||||||
/** map to hold http header values. */
|
|
||||||
typedef std::map<std::string,std::string> string_m;
|
|
||||||
public:
|
|
||||||
HTTPSocket(uint32 ID, SOCKET in_socket, uint32 irIP, uint16 irPort);
|
|
||||||
virtual ~HTTPSocket();
|
|
||||||
|
|
||||||
void OnLine(const std::string& line);
|
|
||||||
|
|
||||||
/** Callback executes when first line has been received.
|
|
||||||
GetMethod, GetUrl/GetUri, and GetHttpVersion are valid when this callback is executed. */
|
|
||||||
virtual void OnFirst() = 0;
|
|
||||||
/** For each header line this callback is executed.
|
|
||||||
\param key Http header name
|
|
||||||
\param value Http header value */
|
|
||||||
virtual void OnHeader(const std::string& key,const std::string& value) = 0;
|
|
||||||
/** Callback fires when all http headers have been received. */
|
|
||||||
virtual void OnHeaderComplete() = 0;
|
|
||||||
/** Chunk of http body data recevied. */
|
|
||||||
virtual void OnData(const char *,size_t) = 0;
|
|
||||||
|
|
||||||
const std::string& GetMethod();
|
|
||||||
void SetMethod(const std::string& x);
|
|
||||||
const std::string& GetUrl();
|
|
||||||
void SetUrl(const std::string& x);
|
|
||||||
const std::string& GetUri();
|
|
||||||
void SetUri(const std::string& x);
|
|
||||||
const std::string& GetQueryString();
|
|
||||||
const std::string& GetHttpVersion();
|
|
||||||
const std::string& GetStatus();
|
|
||||||
const std::string& GetStatusText();
|
|
||||||
bool IsRequest();
|
|
||||||
bool IsResponse();
|
|
||||||
|
|
||||||
void SetHttpVersion(const std::string& x);
|
|
||||||
void SetStatus(const std::string& x);
|
|
||||||
void SetStatus(const std::string& num, const std::string& text);
|
|
||||||
void SetStatusText(const std::string& x);
|
|
||||||
void AddResponseHeader(const std::string& x,const std::string& y);
|
|
||||||
void AddResponseHeader(const std::string& x,const char *format, ...);
|
|
||||||
void SendResponse();
|
|
||||||
void SendResponse(const std::string& status_num, const std::string& status_text);
|
|
||||||
void SendRequest();
|
|
||||||
|
|
||||||
/** Implement this to return your own User-agent string. */
|
|
||||||
virtual std::string MyUseragent();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
/** Reset state of socket to sucessfully implement keep-alive. */
|
|
||||||
virtual void Reset();
|
|
||||||
|
|
||||||
//stubs for crap which used to be in our parent class (TcpSocket)
|
|
||||||
bool SendString(const char *str);
|
|
||||||
bool SendBuf(const char *dat, unsigned int len);
|
|
||||||
|
|
||||||
virtual bool ProcessReceivedData(char* errbuf = 0);
|
|
||||||
|
|
||||||
private:
|
|
||||||
// HTTPSocket& operator=(const HTTPSocket& ) { return *this; }
|
|
||||||
bool m_first;
|
|
||||||
bool m_header;
|
|
||||||
std::string m_line;
|
|
||||||
std::string m_method;
|
|
||||||
std::string m_url;
|
|
||||||
std::string m_uri;
|
|
||||||
std::string m_query_string;
|
|
||||||
std::string m_http_version;
|
|
||||||
std::string m_status;
|
|
||||||
std::string m_status_text;
|
|
||||||
bool m_request;
|
|
||||||
bool m_response;
|
|
||||||
string_m m_response_header;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // _HTTPSOCKET_H
|
|
||||||
@@ -1,250 +0,0 @@
|
|||||||
/** \file HttpdCookies.cpp
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
Copyright (C) 2003-2005 Anders Hedstrom
|
|
||||||
|
|
||||||
This library is made available under the terms of the GNU GPL.
|
|
||||||
|
|
||||||
If you would like to use this library in a closed-source application,
|
|
||||||
a separate license agreement is available. For information about
|
|
||||||
the closed-source license agreement for the C++ sockets library,
|
|
||||||
please visit http://www.alhem.net/Sockets/license.html and/or
|
|
||||||
email license@alhem.net.
|
|
||||||
|
|
||||||
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 2
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "../debug.h"
|
|
||||||
#ifdef _WIN32
|
|
||||||
#pragma warning(disable:4786)
|
|
||||||
#endif
|
|
||||||
#include "Parse.h"
|
|
||||||
#include "Utility.h"
|
|
||||||
#include "HTTPSocket.h"
|
|
||||||
#include "HttpdCookies.h"
|
|
||||||
#include "../types.h"
|
|
||||||
#include <time.h>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
namespace SOCKETS_NAMESPACE {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
HttpdCookies::HttpdCookies()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpdCookies::HttpdCookies(const std::string& s)
|
|
||||||
{
|
|
||||||
Parse *pa = new Parse(s,";");
|
|
||||||
|
|
||||||
std::string slask = pa -> getword();
|
|
||||||
while (slask.size())
|
|
||||||
{
|
|
||||||
Parse *pa2 = new Parse(slask,"=");
|
|
||||||
std::string name = pa2 -> getword();
|
|
||||||
std::string value = pa2 -> getword();
|
|
||||||
delete pa2;
|
|
||||||
COOKIE *c = new COOKIE(name,value);
|
|
||||||
m_cookies.push_back(c);
|
|
||||||
//
|
|
||||||
slask = pa -> getword();
|
|
||||||
}
|
|
||||||
delete pa;
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpdCookies::~HttpdCookies()
|
|
||||||
{
|
|
||||||
for (cookie_v::iterator it = m_cookies.begin(); it != m_cookies.end(); it++)
|
|
||||||
{
|
|
||||||
COOKIE *c = *it;
|
|
||||||
delete c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HttpdCookies::getvalue(const std::string& name,std::string& buffer) //char *buffer,size_t length)
|
|
||||||
{
|
|
||||||
for (cookie_v::iterator it = m_cookies.begin(); it != m_cookies.end(); it++)
|
|
||||||
{
|
|
||||||
COOKIE *c = *it;
|
|
||||||
if (!strcasecmp(c -> name.c_str(),name.c_str()))
|
|
||||||
{
|
|
||||||
buffer = c -> value;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buffer = "";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HttpdCookies::replacevalue(const std::string& name,const std::string& value)
|
|
||||||
{
|
|
||||||
COOKIE *c = nullptr;
|
|
||||||
|
|
||||||
for (cookie_v::iterator it = m_cookies.begin(); it != m_cookies.end(); it++)
|
|
||||||
{
|
|
||||||
c = *it;
|
|
||||||
if (!strcasecmp(c -> name.c_str(),name.c_str()))
|
|
||||||
break;
|
|
||||||
c = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c)
|
|
||||||
{
|
|
||||||
c -> value = value;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
c = new COOKIE(name,value);
|
|
||||||
m_cookies.push_back(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HttpdCookies::replacevalue(const std::string& name,long l)
|
|
||||||
{
|
|
||||||
replacevalue(name, Utility::l2string(l));
|
|
||||||
}
|
|
||||||
|
|
||||||
void HttpdCookies::replacevalue(const std::string& name,int i)
|
|
||||||
{
|
|
||||||
replacevalue(name, Utility::l2string(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t HttpdCookies::getlength(const std::string& name)
|
|
||||||
{
|
|
||||||
COOKIE *c = nullptr;
|
|
||||||
|
|
||||||
for (cookie_v::iterator it = m_cookies.begin(); it != m_cookies.end(); it++)
|
|
||||||
{
|
|
||||||
c = *it;
|
|
||||||
if (!strcasecmp(c -> name.c_str(),name.c_str()))
|
|
||||||
break;
|
|
||||||
c = nullptr;
|
|
||||||
}
|
|
||||||
return c ? c -> value.size() : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HttpdCookies::setcookie(HTTPSocket *sock, const std::string& domain, const std::string& path, const std::string& name, const std::string& value)
|
|
||||||
{
|
|
||||||
char *str = new char[name.size() + value.size() + domain.size() + path.size() + 100];
|
|
||||||
|
|
||||||
// set-cookie response
|
|
||||||
if (domain.size())
|
|
||||||
{
|
|
||||||
sprintf(str, "%s=%s; domain=%s; path=%s; expires=%s",
|
|
||||||
name.c_str(), value.c_str(),
|
|
||||||
domain.c_str(),
|
|
||||||
path.c_str(),
|
|
||||||
expiredatetime().c_str());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sprintf(str, "%s=%s; path=%s; expires=%s",
|
|
||||||
name.c_str(), value.c_str(),
|
|
||||||
path.c_str(),
|
|
||||||
expiredatetime().c_str());
|
|
||||||
}
|
|
||||||
sock -> AddResponseHeader("Set-cookie", str);
|
|
||||||
delete[] str;
|
|
||||||
|
|
||||||
replacevalue(name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HttpdCookies::setcookie(HTTPSocket *sock, const std::string& domain, const std::string& path, const std::string& name, long value)
|
|
||||||
{
|
|
||||||
char *str = new char[name.size() + domain.size() + path.size() + 100];
|
|
||||||
char dt[80];
|
|
||||||
|
|
||||||
// set-cookie response
|
|
||||||
if (domain.size())
|
|
||||||
{
|
|
||||||
sprintf(str, "%s=%ld; domain=%s; path=%s; expires=%s",
|
|
||||||
name.c_str(), value,
|
|
||||||
domain.c_str(),
|
|
||||||
path.c_str(),
|
|
||||||
expiredatetime().c_str());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sprintf(str, "%s=%ld; path=%s; expires=%s",
|
|
||||||
name.c_str(), value,
|
|
||||||
path.c_str(),
|
|
||||||
expiredatetime().c_str());
|
|
||||||
}
|
|
||||||
sock -> AddResponseHeader("Set-cookie", str);
|
|
||||||
delete[] str;
|
|
||||||
|
|
||||||
sprintf(dt, "%ld", value);
|
|
||||||
replacevalue(name, dt);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HttpdCookies::setcookie(HTTPSocket *sock, const std::string& domain, const std::string& path, const std::string& name, int value)
|
|
||||||
{
|
|
||||||
char *str = new char[name.size() + domain.size() + path.size() + 100];
|
|
||||||
char dt[80];
|
|
||||||
|
|
||||||
// set-cookie response
|
|
||||||
if (domain.size())
|
|
||||||
{
|
|
||||||
sprintf(str, "%s=%d; domain=%s; path=%s; expires=%s",
|
|
||||||
name.c_str(), value,
|
|
||||||
domain.c_str(),
|
|
||||||
path.c_str(),
|
|
||||||
expiredatetime().c_str());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sprintf(str, "%s=%d; path=%s; expires=%s",
|
|
||||||
name.c_str(), value,
|
|
||||||
path.c_str(),
|
|
||||||
expiredatetime().c_str());
|
|
||||||
}
|
|
||||||
sock -> AddResponseHeader("Set-cookie", str);
|
|
||||||
delete[] str;
|
|
||||||
|
|
||||||
sprintf(dt, "%d", value);
|
|
||||||
replacevalue(name, dt);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const std::string& HttpdCookies::expiredatetime()
|
|
||||||
{
|
|
||||||
time_t t = time(nullptr);
|
|
||||||
struct tm * tp = gmtime(&t);
|
|
||||||
const char *days[7] = {"Sunday", "Monday",
|
|
||||||
"Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
|
|
||||||
const char *months[12] = {"Jan", "Feb", "Mar", "Apr", "May",
|
|
||||||
"Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
|
|
||||||
char dt[100];
|
|
||||||
|
|
||||||
sprintf(dt, "%s, %02d-%s-%04d %02d:%02d:%02d GMT",
|
|
||||||
days[tp -> tm_wday],
|
|
||||||
tp -> tm_mday,
|
|
||||||
months[tp -> tm_mon],
|
|
||||||
tp -> tm_year + 1910,
|
|
||||||
tp -> tm_hour,
|
|
||||||
tp -> tm_min,
|
|
||||||
tp -> tm_sec);
|
|
||||||
m_date = dt;
|
|
||||||
return m_date;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
/** \file HttpdCookies.h
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
Copyright (C) 2003-2005 Anders Hedstrom
|
|
||||||
|
|
||||||
This library is made available under the terms of the GNU GPL.
|
|
||||||
|
|
||||||
If you would like to use this library in a closed-source application,
|
|
||||||
a separate license agreement is available. For information about
|
|
||||||
the closed-source license agreement for the C++ sockets library,
|
|
||||||
please visit http://www.alhem.net/Sockets/license.html and/or
|
|
||||||
email license@alhem.net.
|
|
||||||
|
|
||||||
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 2
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _COOKIES_H
|
|
||||||
#define _COOKIES_H
|
|
||||||
|
|
||||||
#include <list>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
namespace SOCKETS_NAMESPACE {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
//! Store the cookies name/value pairs.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//! Retrieve and manage cookies during a cgi call.
|
|
||||||
class HTTPSocket;
|
|
||||||
|
|
||||||
/** HTTP Cookie parse/container class.
|
|
||||||
\sa HttpdSocket
|
|
||||||
\sa HttpdForm
|
|
||||||
\ingroup webserver */
|
|
||||||
class HttpdCookies
|
|
||||||
{
|
|
||||||
/** Name/value pair store struct.
|
|
||||||
\ingroup webserver */
|
|
||||||
struct COOKIE
|
|
||||||
{
|
|
||||||
COOKIE(const std::string& n,const std::string& v) : name(n),value(v) {}
|
|
||||||
std::string name;
|
|
||||||
std::string value;
|
|
||||||
};
|
|
||||||
/** list of key/value structs. */
|
|
||||||
typedef std::list<COOKIE *> cookie_v;
|
|
||||||
public:
|
|
||||||
HttpdCookies();
|
|
||||||
HttpdCookies(const std::string& query_string);
|
|
||||||
~HttpdCookies();
|
|
||||||
|
|
||||||
// int getvalue(const std::string& ,char *,size_t); // (name, buffer, length)
|
|
||||||
bool getvalue(const std::string&,std::string&);
|
|
||||||
void replacevalue(const std::string& ,const std::string& );
|
|
||||||
void replacevalue(const std::string& ,long);
|
|
||||||
void replacevalue(const std::string& ,int);
|
|
||||||
size_t getlength(const std::string& );
|
|
||||||
void setcookie(HTTPSocket *,const std::string& d,const std::string& p,const std::string& c,const std::string& v);
|
|
||||||
void setcookie(HTTPSocket *,const std::string& d,const std::string& p,const std::string& c,long v);
|
|
||||||
void setcookie(HTTPSocket *,const std::string& d,const std::string& p,const std::string& c,int v);
|
|
||||||
const std::string& expiredatetime();
|
|
||||||
|
|
||||||
cookie_v& GetHttpdCookies() { return m_cookies; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
cookie_v m_cookies;
|
|
||||||
std::string m_date;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // _COOKIES_H
|
|
||||||
@@ -1,621 +0,0 @@
|
|||||||
/** \file HttpdForm.cpp - read stdin, parse cgi input
|
|
||||||
**
|
|
||||||
** Written: 1999-Feb-10 grymse@alhem.net
|
|
||||||
**/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright (C) 1999-2005 Anders Hedstrom
|
|
||||||
|
|
||||||
This library is made available under the terms of the GNU GPL.
|
|
||||||
|
|
||||||
If you would like to use this library in a closed-source application,
|
|
||||||
a separate license agreement is available. For information about
|
|
||||||
the closed-source license agreement for the C++ sockets library,
|
|
||||||
please visit http://www.alhem.net/Sockets/license.html and/or
|
|
||||||
email license@alhem.net.
|
|
||||||
|
|
||||||
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 2
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
#include <stdio.h>
|
|
||||||
#ifdef _WIN32
|
|
||||||
#pragma warning(disable:4786)
|
|
||||||
#include <windows.h>
|
|
||||||
#endif
|
|
||||||
#include "socket_include.h"
|
|
||||||
#include "Parse.h"
|
|
||||||
#include "IFile.h"
|
|
||||||
#include "HttpdForm.h"
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
namespace SOCKETS_NAMESPACE {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
HttpdForm::HttpdForm(IFile *infil) : raw(false)
|
|
||||||
{
|
|
||||||
CGI *cgi = nullptr;
|
|
||||||
char *c_t = getenv("CONTENT_TYPE");
|
|
||||||
char *c_l = getenv("CONTENT_LENGTH");
|
|
||||||
size_t extra = 2;
|
|
||||||
char name[200];
|
|
||||||
|
|
||||||
m_current = m_cgi.end();
|
|
||||||
*name = 0;
|
|
||||||
|
|
||||||
if (c_t && !strncmp(c_t, "multipart/form-data",19))
|
|
||||||
{
|
|
||||||
Parse pa(c_t,";=");
|
|
||||||
char *tempcmp = nullptr;
|
|
||||||
size_t tc = 0;
|
|
||||||
size_t l = 0;
|
|
||||||
std::string str = pa.getword();
|
|
||||||
m_strBoundary = "";
|
|
||||||
while (str.size())
|
|
||||||
{
|
|
||||||
if (!strcmp(str.c_str(),"boundary"))
|
|
||||||
{
|
|
||||||
m_strBoundary = pa.getword();
|
|
||||||
l = m_strBoundary.size();
|
|
||||||
tempcmp = new char[l + extra];
|
|
||||||
}
|
|
||||||
//
|
|
||||||
str = pa.getword();
|
|
||||||
}
|
|
||||||
if (m_strBoundary.size())
|
|
||||||
{
|
|
||||||
std::string content_type;
|
|
||||||
std::string current_name;
|
|
||||||
std::string current_filename;
|
|
||||||
char slask[2000];
|
|
||||||
infil -> fgets(slask, 200);
|
|
||||||
while (!infil -> eof())
|
|
||||||
{
|
|
||||||
while (strlen(slask) && (slask[strlen(slask) - 1] == 13 || slask[strlen(slask) - 1] == 10))
|
|
||||||
{
|
|
||||||
slask[strlen(slask) - 1] = 0;
|
|
||||||
}
|
|
||||||
content_type = "";
|
|
||||||
current_name = "";
|
|
||||||
current_filename = "";
|
|
||||||
if ((strstr(slask,m_strBoundary.c_str()) || strstr(m_strBoundary.c_str(),slask)) && strcmp(slask, m_strBoundary.c_str()))
|
|
||||||
{
|
|
||||||
m_strBoundary = slask;
|
|
||||||
l = m_strBoundary.size();
|
|
||||||
delete[] tempcmp;
|
|
||||||
tempcmp = new char[l + extra];
|
|
||||||
}
|
|
||||||
if (!strcmp(slask, m_strBoundary.c_str()))
|
|
||||||
{
|
|
||||||
// Get headers until empty line
|
|
||||||
infil -> fgets(slask, 200);
|
|
||||||
while (strlen(slask) && (slask[strlen(slask) - 1] == 13 || slask[strlen(slask) - 1] == 10))
|
|
||||||
{
|
|
||||||
slask[strlen(slask) - 1] = 0;
|
|
||||||
}
|
|
||||||
while (!infil -> eof() && *slask)
|
|
||||||
{
|
|
||||||
Parse pa(slask,";");
|
|
||||||
std::string h = pa.getword();
|
|
||||||
if (!strcasecmp(h.c_str(),"Content-type:"))
|
|
||||||
{
|
|
||||||
content_type = pa.getword();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if (!strcasecmp(h.c_str(),"Content-Disposition:"))
|
|
||||||
{
|
|
||||||
h = pa.getword();
|
|
||||||
if (!strcmp(h.c_str(),"form-data"))
|
|
||||||
{
|
|
||||||
pa.EnableQuote(true);
|
|
||||||
h = pa.getword();
|
|
||||||
while (h.size())
|
|
||||||
{
|
|
||||||
Parse pa2(slask,"=");
|
|
||||||
std::string name = pa2.getword();
|
|
||||||
std::string h = pa2.getrest();
|
|
||||||
if (!strcmp(name.c_str(),"name"))
|
|
||||||
{
|
|
||||||
if (h.size() && h[0] == '"')
|
|
||||||
{
|
|
||||||
current_name = h.substr(1, h.size() - 2);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
current_name = h;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if (!strcmp(name.c_str(),"filename"))
|
|
||||||
{
|
|
||||||
if (h.size() && h[0] == '"')
|
|
||||||
{
|
|
||||||
current_filename = h.substr(1, h.size() - 2);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
current_filename = h;
|
|
||||||
}
|
|
||||||
size_t x = 0;
|
|
||||||
for (size_t i = 0; i < current_filename.size(); i++)
|
|
||||||
{
|
|
||||||
if (current_filename[i] == '/' || current_filename[i] == '\\')
|
|
||||||
x = i + 1;
|
|
||||||
}
|
|
||||||
if (x)
|
|
||||||
{
|
|
||||||
current_filename = current_filename.substr(x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
h = pa.getword();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// get next header value
|
|
||||||
infil -> fgets(slask, 200);
|
|
||||||
while (strlen(slask) && (slask[strlen(slask) - 1] == 13 || slask[strlen(slask) - 1] == 10))
|
|
||||||
{
|
|
||||||
slask[strlen(slask) - 1] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Read content, save...?
|
|
||||||
if (!current_filename.size()) // not a file
|
|
||||||
{
|
|
||||||
std::string val;
|
|
||||||
infil -> fgets(slask,1000);
|
|
||||||
while (!infil -> eof() && strncmp(slask,m_strBoundary.c_str(),m_strBoundary.size() ))
|
|
||||||
{
|
|
||||||
val += slask;
|
|
||||||
infil -> fgets(slask,1000);
|
|
||||||
}
|
|
||||||
// remove trailing cr/linefeed
|
|
||||||
while (val.size() && (val[val.size() - 1] == 13 || val[val.size() - 1] == 10))
|
|
||||||
{
|
|
||||||
val = val.substr(0,val.size() - 1);
|
|
||||||
}
|
|
||||||
cgi = new CGI(current_name, val);
|
|
||||||
m_cgi.push_back(cgi);
|
|
||||||
}
|
|
||||||
else // current_filename.size() > 0
|
|
||||||
{
|
|
||||||
// read until m_strBoundary...
|
|
||||||
FILE *fil;
|
|
||||||
int out = 0;
|
|
||||||
char c;
|
|
||||||
char fn[1000]; // where post'd file will be saved
|
|
||||||
#ifdef _WIN32
|
|
||||||
{
|
|
||||||
char tmp_path[1000];
|
|
||||||
::GetTempPath(1000, tmp_path);
|
|
||||||
if (tmp_path[strlen(tmp_path) - 1] != '\\')
|
|
||||||
{
|
|
||||||
strcat(tmp_path, "\\");
|
|
||||||
}
|
|
||||||
sprintf(fn,"%s%s",tmp_path,current_filename.c_str());
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
sprintf(fn,"/tmp/%s",current_filename.c_str());
|
|
||||||
#endif
|
|
||||||
if ((fil = fopen(fn, "wb")) != nullptr)
|
|
||||||
{
|
|
||||||
infil -> fread(&c,1,1);
|
|
||||||
while (!infil -> eof())
|
|
||||||
{
|
|
||||||
if (out)
|
|
||||||
{
|
|
||||||
fwrite(&tempcmp[tc],1,1,fil);
|
|
||||||
}
|
|
||||||
tempcmp[tc] = c;
|
|
||||||
tc++;
|
|
||||||
if (tc >= l + extra)
|
|
||||||
{
|
|
||||||
tc = 0;
|
|
||||||
out = 1;
|
|
||||||
}
|
|
||||||
if (tc)
|
|
||||||
{
|
|
||||||
if (!strncmp(tempcmp + tc + extra, m_strBoundary.c_str(), l - tc) &&
|
|
||||||
!strncmp(tempcmp, m_strBoundary.c_str() + l - tc, tc))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!strncmp(tempcmp + extra, m_strBoundary.c_str(), l))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
infil -> fread(&c,1,1);
|
|
||||||
}
|
|
||||||
fclose(fil);
|
|
||||||
|
|
||||||
cgi = new CGI(current_name,fn,fn);
|
|
||||||
m_cgi.push_back(cgi);
|
|
||||||
|
|
||||||
strcpy(slask, m_strBoundary.c_str());
|
|
||||||
infil -> fgets(slask + strlen(slask), 200); // next line
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// couldn't open file
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Probably '<m_strBoundary>--'
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} // while (!infil -> eof())
|
|
||||||
} // if (m_strBoundary)
|
|
||||||
if (tempcmp)
|
|
||||||
{
|
|
||||||
delete[] tempcmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int i = 0;
|
|
||||||
int cl = c_l ? atoi(c_l) : -1;
|
|
||||||
char c,chigh,clow;
|
|
||||||
char *slask = new char[8888];
|
|
||||||
bool got_name = false;
|
|
||||||
m_current = m_cgi.end();
|
|
||||||
|
|
||||||
*name = 0;
|
|
||||||
|
|
||||||
infil -> fread(&c,1,1);
|
|
||||||
cl--;
|
|
||||||
while (cl >= 0)
|
|
||||||
{
|
|
||||||
switch (c)
|
|
||||||
{
|
|
||||||
case '=': /* end of name */
|
|
||||||
slask[i] = 0;
|
|
||||||
i = 0;
|
|
||||||
strcpy(name,slask);
|
|
||||||
got_name = true;
|
|
||||||
break;
|
|
||||||
case '&': /* end of value */
|
|
||||||
slask[i] = 0;
|
|
||||||
i = 0;
|
|
||||||
if(got_name) {
|
|
||||||
got_name = false;
|
|
||||||
cgi = new CGI(name,slask);
|
|
||||||
m_cgi.push_back(cgi);
|
|
||||||
} else {
|
|
||||||
cgi = new CGI(slask,"");
|
|
||||||
m_cgi.push_back(cgi);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '+': /* space */
|
|
||||||
slask[i++] = ' ';
|
|
||||||
break;
|
|
||||||
case '%': /* hex value */
|
|
||||||
infil -> fread(&chigh,1,1);
|
|
||||||
cl--;
|
|
||||||
chigh -= 48;
|
|
||||||
chigh &= 0xff - 32;
|
|
||||||
if (chigh > 9)
|
|
||||||
chigh -= 7;
|
|
||||||
infil -> fread(&clow,1,1);
|
|
||||||
cl--;
|
|
||||||
clow -= 48;
|
|
||||||
clow &= 0xff - 32;
|
|
||||||
if (clow > 9)
|
|
||||||
clow -= 7;
|
|
||||||
slask[i++] = (char)(chigh * 16 + clow);
|
|
||||||
break;
|
|
||||||
default: /* just another char */
|
|
||||||
slask[i++] = c;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(infil -> eof())
|
|
||||||
break;
|
|
||||||
//
|
|
||||||
if (cl > 0)
|
|
||||||
{
|
|
||||||
infil -> fread(&c,1,1);
|
|
||||||
}
|
|
||||||
cl--;
|
|
||||||
}
|
|
||||||
slask[i] = 0;
|
|
||||||
i = 0;
|
|
||||||
if(got_name) {
|
|
||||||
cgi = new CGI(name,slask);
|
|
||||||
m_cgi.push_back(cgi);
|
|
||||||
} else {
|
|
||||||
cgi = new CGI(slask,"");
|
|
||||||
m_cgi.push_back(cgi);
|
|
||||||
}
|
|
||||||
delete[] slask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// HttpdForm(buffer,l) -- request_method GET
|
|
||||||
|
|
||||||
HttpdForm::HttpdForm(const std::string& buffer,size_t l) : raw(false)
|
|
||||||
{
|
|
||||||
CGI *cgi = nullptr;
|
|
||||||
char slask[8888];
|
|
||||||
char name[200];
|
|
||||||
int i = 0;
|
|
||||||
char c,chigh,clow;
|
|
||||||
bool got_name = false;
|
|
||||||
size_t ptr = 0;
|
|
||||||
|
|
||||||
m_current = m_cgi.end();
|
|
||||||
|
|
||||||
*name = 0;
|
|
||||||
|
|
||||||
ptr = 0;
|
|
||||||
while (ptr < l)
|
|
||||||
{
|
|
||||||
c = buffer[ptr++];
|
|
||||||
switch (c)
|
|
||||||
{
|
|
||||||
case '=': /* end of name */
|
|
||||||
slask[i] = 0;
|
|
||||||
i = 0;
|
|
||||||
got_name = true;
|
|
||||||
strcpy(name,slask);
|
|
||||||
break;
|
|
||||||
case '&': /* end of value */
|
|
||||||
slask[i] = 0;
|
|
||||||
i = 0;
|
|
||||||
if(got_name) {
|
|
||||||
got_name = false;
|
|
||||||
cgi = new CGI(name,slask);
|
|
||||||
m_cgi.push_back(cgi);
|
|
||||||
} else {
|
|
||||||
cgi = new CGI(slask, "");
|
|
||||||
m_cgi.push_back(cgi);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '+': /* space */
|
|
||||||
slask[i++] = ' ';
|
|
||||||
break;
|
|
||||||
case '%': /* hex value */
|
|
||||||
chigh = buffer[ptr++];
|
|
||||||
chigh -= 48;
|
|
||||||
chigh &= 0xff - 32;
|
|
||||||
if (chigh > 9)
|
|
||||||
chigh -= 7;
|
|
||||||
clow = buffer[ptr++];
|
|
||||||
clow -= 48;
|
|
||||||
clow &= 0xff - 32;
|
|
||||||
if (clow > 9)
|
|
||||||
clow -= 7;
|
|
||||||
slask[i++] = (char)(chigh * 16 + clow);
|
|
||||||
break;
|
|
||||||
default: /* just another char */
|
|
||||||
slask[i++] = c;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
slask[i] = 0;
|
|
||||||
i = 0;
|
|
||||||
if(got_name) {
|
|
||||||
cgi = new CGI(name,slask);
|
|
||||||
m_cgi.push_back(cgi);
|
|
||||||
} else {
|
|
||||||
cgi = new CGI(slask, "");
|
|
||||||
m_cgi.push_back(cgi);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
HttpdForm::~HttpdForm()
|
|
||||||
{
|
|
||||||
CGI *cgi = nullptr; //,*tmp;
|
|
||||||
|
|
||||||
for (cgi_v::iterator it = m_cgi.begin(); it != m_cgi.end(); it++)
|
|
||||||
{
|
|
||||||
cgi = *it;
|
|
||||||
delete cgi;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void HttpdForm::EnableRaw(bool b)
|
|
||||||
{
|
|
||||||
raw = b;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void HttpdForm::strcpyval(std::string& v,const char *value) //,size_t len)
|
|
||||||
{
|
|
||||||
v = "";
|
|
||||||
for (size_t i = 0; i < strlen(value); i++)
|
|
||||||
{
|
|
||||||
if (value[i] == '<')
|
|
||||||
{
|
|
||||||
v += "<";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if (value[i] == '>')
|
|
||||||
{
|
|
||||||
v += ">";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if (value[i] == '&')
|
|
||||||
{
|
|
||||||
v += "&";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
v += value[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool HttpdForm::getfirst(std::string& n) //char *n,size_t len)
|
|
||||||
{
|
|
||||||
m_current = m_cgi.begin();
|
|
||||||
return getnext(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool HttpdForm::getnext(std::string& n) //char *n,size_t len)
|
|
||||||
{
|
|
||||||
if (m_current != m_cgi.end() )
|
|
||||||
{
|
|
||||||
CGI *current = *m_current;
|
|
||||||
n = current -> name;
|
|
||||||
m_current++;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
n = "";
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool HttpdForm::getfirst(std::string& n,std::string& v) //char *n,size_t len,char *v,size_t vlen)
|
|
||||||
{
|
|
||||||
m_current = m_cgi.begin();
|
|
||||||
return getnext(n,v);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool HttpdForm::getnext(std::string& n,std::string& v) //char *n,size_t len,char *v,size_t vlen)
|
|
||||||
{
|
|
||||||
if (m_current != m_cgi.end() )
|
|
||||||
{
|
|
||||||
CGI *current = *m_current;
|
|
||||||
n = current -> name;
|
|
||||||
if (raw)
|
|
||||||
{
|
|
||||||
v = current -> value;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
strcpyval(v,current -> value.c_str());
|
|
||||||
}
|
|
||||||
m_current++;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
n = "";
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int HttpdForm::getvalue(const std::string& n,std::string& v) //char *v,size_t len)
|
|
||||||
{
|
|
||||||
CGI *cgi = nullptr;
|
|
||||||
int r = 0;
|
|
||||||
|
|
||||||
for (cgi_v::iterator it = m_cgi.begin(); it != m_cgi.end(); it++)
|
|
||||||
{
|
|
||||||
cgi = *it;
|
|
||||||
if (cgi -> name == n)
|
|
||||||
break;
|
|
||||||
cgi = nullptr;
|
|
||||||
}
|
|
||||||
if (cgi)
|
|
||||||
{
|
|
||||||
if (raw)
|
|
||||||
{
|
|
||||||
v = cgi -> value;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
strcpyval(v,cgi -> value.c_str());
|
|
||||||
}
|
|
||||||
r++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
v = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::string HttpdForm::getvalue(const std::string& n)
|
|
||||||
{
|
|
||||||
for (cgi_v::iterator it = m_cgi.begin(); it != m_cgi.end(); it++)
|
|
||||||
{
|
|
||||||
CGI *cgi = *it;
|
|
||||||
if (cgi -> name == n)
|
|
||||||
{
|
|
||||||
return cgi -> value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
size_t HttpdForm::getlength(const std::string& n)
|
|
||||||
{
|
|
||||||
CGI *cgi = nullptr;
|
|
||||||
size_t l;
|
|
||||||
|
|
||||||
for (cgi_v::iterator it = m_cgi.begin(); it != m_cgi.end(); it++)
|
|
||||||
{
|
|
||||||
cgi = *it;
|
|
||||||
if (cgi -> name == n)
|
|
||||||
break;
|
|
||||||
cgi = nullptr;
|
|
||||||
}
|
|
||||||
l = cgi ? cgi -> value.size() : 0;
|
|
||||||
if (cgi && !raw)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < cgi -> value.size(); i++)
|
|
||||||
{
|
|
||||||
switch (cgi -> value[i])
|
|
||||||
{
|
|
||||||
case '<': // <
|
|
||||||
case '>': // >
|
|
||||||
l += 4;
|
|
||||||
break;
|
|
||||||
case '&': // &
|
|
||||||
l += 5;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
HttpdForm::cgi_v& HttpdForm::getbase()
|
|
||||||
{
|
|
||||||
return m_cgi;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const std::string& HttpdForm::GetBoundary()
|
|
||||||
{
|
|
||||||
return m_strBoundary;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@@ -1,115 +0,0 @@
|
|||||||
/** \file HttpdForm.h - read stdin, parse cgi input
|
|
||||||
**
|
|
||||||
** Written: 1999-Feb-10 grymse@alhem.net
|
|
||||||
**/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright (C) 1999-2005 Anders Hedstrom
|
|
||||||
|
|
||||||
This library is made available under the terms of the GNU GPL.
|
|
||||||
|
|
||||||
If you would like to use this library in a closed-source application,
|
|
||||||
a separate license agreement is available. For information about
|
|
||||||
the closed-source license agreement for the C++ sockets library,
|
|
||||||
please visit http://www.alhem.net/Sockets/license.html and/or
|
|
||||||
email license@alhem.net.
|
|
||||||
|
|
||||||
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 2
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _FORM_H
|
|
||||||
#define _FORM_H
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <list>
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
namespace SOCKETS_NAMESPACE {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
class IFile;
|
|
||||||
|
|
||||||
/** Parse/store a http query_string/form-data body.
|
|
||||||
\ingroup webserver */
|
|
||||||
class HttpdForm
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Store the name/value pairs from a GET/POST operation.
|
|
||||||
* "name" does not have to be unique.
|
|
||||||
\ingroup webserver
|
|
||||||
*/
|
|
||||||
struct CGI
|
|
||||||
{
|
|
||||||
CGI(const std::string& n,const std::string& v) : name(n),value(v) {}
|
|
||||||
CGI(const std::string& n,const std::string& v,const std::string& p) : name(n),value(v),path(p) {}
|
|
||||||
std::string name;
|
|
||||||
std::string value;
|
|
||||||
std::string path;
|
|
||||||
};
|
|
||||||
/** list of key/value pairs. */
|
|
||||||
typedef std::list<CGI *> cgi_v;
|
|
||||||
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Default constructor (used in POST operations).
|
|
||||||
* Input is read from stdin. Number of characters to read
|
|
||||||
* can be found in the environment variable CONTENT_LENGTH.
|
|
||||||
*/
|
|
||||||
HttpdForm(IFile *);
|
|
||||||
/**
|
|
||||||
* Another constructor (used in GET operations).
|
|
||||||
* Input is read from the environment variable QUERY_STRING.
|
|
||||||
* @param query_string The httpd server provided QUERY_STRING
|
|
||||||
* @param length Query string length.
|
|
||||||
*/
|
|
||||||
HttpdForm(const std::string& query_string,size_t length);
|
|
||||||
~HttpdForm();
|
|
||||||
|
|
||||||
void EnableRaw(bool);
|
|
||||||
|
|
||||||
void strcpyval(std::string&,const char *); //,size_t);
|
|
||||||
|
|
||||||
/* get names */
|
|
||||||
bool getfirst(std::string& n); //char *,size_t);
|
|
||||||
bool getnext(std::string& n); //char *,size_t);
|
|
||||||
|
|
||||||
/* get names and values */
|
|
||||||
bool getfirst(std::string& n,std::string& v); //char *,size_t,char *,size_t);
|
|
||||||
bool getnext(std::string& n,std::string& v); //char *,size_t,char *,size_t);
|
|
||||||
|
|
||||||
/* get value */
|
|
||||||
int getvalue(const std::string& ,std::string& ); //char *,size_t);
|
|
||||||
std::string getvalue(const std::string& );
|
|
||||||
size_t getlength(const std::string& );
|
|
||||||
cgi_v& getbase();
|
|
||||||
|
|
||||||
const std::string& GetBoundary();
|
|
||||||
|
|
||||||
private:
|
|
||||||
HttpdForm(const HttpdForm& ) {}
|
|
||||||
HttpdForm& operator=(const HttpdForm& ) { return *this; }
|
|
||||||
cgi_v m_cgi;
|
|
||||||
cgi_v::iterator m_current;
|
|
||||||
std::string m_strBoundary;
|
|
||||||
bool raw;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // _FORM_H
|
|
||||||
@@ -1,353 +0,0 @@
|
|||||||
/** \file HttpdSocket.cpp
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
Copyright (C) 2001-2004,2005 Anders Hedstrom (grymse@alhem.net)
|
|
||||||
|
|
||||||
This library is made available under the terms of the GNU GPL.
|
|
||||||
|
|
||||||
If you would like to use this library in a closed-source application,
|
|
||||||
a separate license agreement is available. For information about
|
|
||||||
the closed-source license agreement for the C++ sockets library,
|
|
||||||
please visit http://www.alhem.net/Sockets/license.html and/or
|
|
||||||
email license@alhem.net.
|
|
||||||
|
|
||||||
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 2
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
#ifdef _WIN32
|
|
||||||
#pragma warning(disable:4786)
|
|
||||||
#endif
|
|
||||||
#include "../debug.h"
|
|
||||||
#include "Utility.h"
|
|
||||||
#include "HttpdCookies.h"
|
|
||||||
#include "HttpdForm.h"
|
|
||||||
#include "MemFile.h"
|
|
||||||
#include "HttpdSocket.h"
|
|
||||||
#include "../types.h"
|
|
||||||
#include <time.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
#define DEB(x)
|
|
||||||
/*
|
|
||||||
#define DEB(x) { \
|
|
||||||
FILE *fil = fopen("httpdlog","at"); \
|
|
||||||
if (!fil) \
|
|
||||||
fil = fopen("httpdlog","wt"); \
|
|
||||||
if (fil) { x; fclose(fil); } \
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
namespace SOCKETS_NAMESPACE {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// statics
|
|
||||||
int HttpdSocket::m_request_count = 0;
|
|
||||||
std::string HttpdSocket::m_start = "";
|
|
||||||
|
|
||||||
|
|
||||||
HttpdSocket::HttpdSocket(uint32 ID, SOCKET in_socket, uint32 irIP, uint16 irPort)
|
|
||||||
: HTTPSocket(ID,in_socket,irIP,irPort)
|
|
||||||
,m_content_length(0)
|
|
||||||
,m_file(nullptr)
|
|
||||||
,m_received(0)
|
|
||||||
,m_request_id(++m_request_count)
|
|
||||||
,m_cookies(nullptr)
|
|
||||||
,m_form(nullptr)
|
|
||||||
{
|
|
||||||
m_http_date = datetime2httpdate(GetDate());
|
|
||||||
if (!m_start.size())
|
|
||||||
m_start = m_http_date;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
HttpdSocket::~HttpdSocket()
|
|
||||||
{
|
|
||||||
if (m_file)
|
|
||||||
{
|
|
||||||
delete m_file;
|
|
||||||
}
|
|
||||||
if (m_cookies)
|
|
||||||
delete m_cookies;
|
|
||||||
if (m_form)
|
|
||||||
delete m_form;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void HttpdSocket::OnFirst()
|
|
||||||
{
|
|
||||||
// printf("Request: %s %s %s\n",GetMethod().c_str(),GetUrl().c_str(),GetHttpVersion().c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void HttpdSocket::OnHeader(const std::string& key,const std::string& value)
|
|
||||||
{
|
|
||||||
if (!strcasecmp(key.c_str(),"content-length"))
|
|
||||||
{
|
|
||||||
m_content_length = atoi(value.c_str());
|
|
||||||
m_content_length_str = value;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if (!strcasecmp(key.c_str(),"cookie"))
|
|
||||||
{
|
|
||||||
m_http_cookie = value;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if (!strcasecmp(key.c_str(),"content-type"))
|
|
||||||
{
|
|
||||||
m_content_type = value;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if (!strcasecmp(key.c_str(),"if-modified-since"))
|
|
||||||
{
|
|
||||||
m_if_modified_since = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void HttpdSocket::OnHeaderComplete()
|
|
||||||
{
|
|
||||||
m_cookies = new HttpdCookies(m_http_cookie);
|
|
||||||
|
|
||||||
#if (defined(SOLARIS8) || defined(SOLARIS))
|
|
||||||
{
|
|
||||||
char slask[1000];
|
|
||||||
if (GetMethod() == "GET")
|
|
||||||
{
|
|
||||||
sprintf(slask,"QUERY_STRING=%s", GetQueryString().c_str());
|
|
||||||
putenv(slask);
|
|
||||||
}
|
|
||||||
sprintf(slask,"REQUEST_METHOD=%s", GetMethod().c_str());
|
|
||||||
putenv(slask);
|
|
||||||
sprintf(slask,"HTTP_COOKIE=%s", m_http_cookie.c_str());
|
|
||||||
putenv(slask);
|
|
||||||
sprintf(slask,"CONTENT_TYPE=%s", m_content_type.c_str());
|
|
||||||
putenv(slask);
|
|
||||||
sprintf(slask,"CONTENT_LENGTH=%s", m_content_length_str.c_str());
|
|
||||||
putenv(slask);
|
|
||||||
}
|
|
||||||
#elif defined _WIN32
|
|
||||||
{
|
|
||||||
char slask[1000];
|
|
||||||
if (GetMethod() == "GET")
|
|
||||||
{
|
|
||||||
sprintf(slask,"QUERY_STRING=%s", GetQueryString().c_str());
|
|
||||||
_putenv(slask);
|
|
||||||
}
|
|
||||||
sprintf(slask,"REQUEST_METHOD=%s", GetMethod().c_str());
|
|
||||||
_putenv(slask);
|
|
||||||
sprintf(slask,"HTTP_COOKIE=%s", m_http_cookie.c_str());
|
|
||||||
_putenv(slask);
|
|
||||||
sprintf(slask,"CONTENT_TYPE=%s", m_content_type.c_str());
|
|
||||||
_putenv(slask);
|
|
||||||
sprintf(slask,"CONTENT_LENGTH=%s", m_content_length_str.c_str());
|
|
||||||
_putenv(slask);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (GetMethod() == "GET")
|
|
||||||
{
|
|
||||||
setenv("QUERY_STRING", GetQueryString().c_str(), 1);
|
|
||||||
}
|
|
||||||
setenv("REQUEST_METHOD", GetMethod().c_str(), 1);
|
|
||||||
setenv("HTTP_COOKIE", m_http_cookie.c_str(), 1);
|
|
||||||
setenv("CONTENT_TYPE", m_content_type.c_str(), 1);
|
|
||||||
setenv("CONTENT_LENGTH", m_content_length_str.c_str(), 1);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (GetMethod() == "POST")
|
|
||||||
{
|
|
||||||
m_file = new MemFile;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if (GetMethod() == "GET")
|
|
||||||
{
|
|
||||||
m_form = new HttpdForm(GetQueryString(), GetQueryString().size() );
|
|
||||||
AddResponseHeader("Date", datetime2httpdate(GetDate()) );
|
|
||||||
Exec();
|
|
||||||
Reset(); // prepare for next request
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AddResponseHeader("Date", GetHttpDate());
|
|
||||||
AddResponseHeader("Connection", "close");
|
|
||||||
SetStatus("405");
|
|
||||||
SetStatusText("Method not allowed");
|
|
||||||
SendResponse();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void HttpdSocket::OnData(const char *p,size_t l)
|
|
||||||
{
|
|
||||||
//printf("Got %d bytes: %.*s\n", l, l, p);
|
|
||||||
if (m_file)
|
|
||||||
{
|
|
||||||
m_file -> fwrite(p,1,l);
|
|
||||||
}
|
|
||||||
m_received += l;
|
|
||||||
if (m_received >= m_content_length && m_content_length)
|
|
||||||
{
|
|
||||||
// all done
|
|
||||||
if (m_file && !m_form)
|
|
||||||
{
|
|
||||||
m_form = new HttpdForm(m_file);
|
|
||||||
AddResponseHeader("Date", datetime2httpdate(GetDate()) );
|
|
||||||
Exec();
|
|
||||||
Reset(); // prepare for next request
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void HttpdSocket::Send64(const std::string& str64, const std::string& type)
|
|
||||||
{
|
|
||||||
if (!strcasecmp(m_start.c_str(), m_if_modified_since.c_str()))
|
|
||||||
{
|
|
||||||
SetStatus("304");
|
|
||||||
SetStatusText("Not Modified");
|
|
||||||
SendResponse();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
size_t len = Base64::decode_length(str64);
|
|
||||||
unsigned char *buf = new unsigned char[len];
|
|
||||||
|
|
||||||
SetStatus("200");
|
|
||||||
SetStatusText("OK");
|
|
||||||
|
|
||||||
AddResponseHeader("Content-length", Utility::l2string( (long)len) );
|
|
||||||
AddResponseHeader("Content-type", type );
|
|
||||||
AddResponseHeader("Last-modified", m_start);
|
|
||||||
SendResponse();
|
|
||||||
|
|
||||||
Base64::decode(str64, buf, len);
|
|
||||||
SendBuf( (char *)buf, len);
|
|
||||||
delete[] buf;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::string HttpdSocket::datetime2httpdate(const std::string& dt)
|
|
||||||
{
|
|
||||||
struct tm tp;
|
|
||||||
time_t t;
|
|
||||||
const char *days[] = { "Sun","Mon","Tue","Wed","Thu","Fri","Sat" };
|
|
||||||
const char *months[] = { "Jan","Feb","Mar","Apr","May","Jun",
|
|
||||||
"Jul","Aug","Sep","Oct","Nov","Dec" };
|
|
||||||
int i;
|
|
||||||
char s[40];
|
|
||||||
|
|
||||||
/* 1997-12-16 09:50:40 */
|
|
||||||
|
|
||||||
if (dt.size() == 19)
|
|
||||||
{
|
|
||||||
tp.tm_year = atoi(dt.substr(0,4).c_str()) - 1900;
|
|
||||||
i = atoi(dt.substr(5,2).c_str()) - 1;
|
|
||||||
tp.tm_mon = i >= 0 ? i : 0;
|
|
||||||
tp.tm_mday = atoi(dt.substr(8,2).c_str());
|
|
||||||
tp.tm_hour = atoi(dt.substr(11,2).c_str());
|
|
||||||
tp.tm_min = atoi(dt.substr(14,2).c_str());
|
|
||||||
tp.tm_sec = atoi(dt.substr(17,2).c_str());
|
|
||||||
tp.tm_wday = 0;
|
|
||||||
tp.tm_yday = 0;
|
|
||||||
tp.tm_isdst = 0;
|
|
||||||
t = mktime(&tp);
|
|
||||||
/*if (t == -1)
|
|
||||||
{
|
|
||||||
Handler().LogError(this, "datetime2httpdate", 0, "mktime() failed");
|
|
||||||
}*/
|
|
||||||
|
|
||||||
sprintf(s,"%s, %02d %s %d %02d:%02d:%02d GMT",
|
|
||||||
days[tp.tm_wday],
|
|
||||||
tp.tm_mday,
|
|
||||||
months[tp.tm_mon],
|
|
||||||
tp.tm_year + 1900,
|
|
||||||
tp.tm_hour,tp.tm_min,tp.tm_sec);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*s = 0;
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::string HttpdSocket::GetDate()
|
|
||||||
{
|
|
||||||
time_t t = time(nullptr);
|
|
||||||
struct tm* tp = localtime(&t);
|
|
||||||
char slask[40];
|
|
||||||
if (tp)
|
|
||||||
{
|
|
||||||
sprintf(slask,"%d-%02d-%02d %02d:%02d:%02d",
|
|
||||||
tp -> tm_year + 1900,
|
|
||||||
tp -> tm_mon + 1,
|
|
||||||
tp -> tm_mday,
|
|
||||||
tp -> tm_hour,tp -> tm_min,tp -> tm_sec);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*slask = 0;
|
|
||||||
}
|
|
||||||
return slask;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void HttpdSocket::Reset()
|
|
||||||
{
|
|
||||||
HTTPSocket::Reset();
|
|
||||||
m_content_length = 0;
|
|
||||||
if (m_file)
|
|
||||||
{
|
|
||||||
delete m_file;
|
|
||||||
m_file = nullptr;
|
|
||||||
}
|
|
||||||
m_received = 0;
|
|
||||||
m_request_id = ++m_request_count;
|
|
||||||
if (m_cookies)
|
|
||||||
delete m_cookies;
|
|
||||||
m_cookies = nullptr;
|
|
||||||
if (m_form)
|
|
||||||
delete m_form;
|
|
||||||
m_form = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const std::string& HttpdSocket::GetHttpDate()
|
|
||||||
{
|
|
||||||
return m_http_date;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
HttpdCookies *HttpdSocket::GetCookies()
|
|
||||||
{
|
|
||||||
return m_cookies;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
HttpdForm *HttpdSocket::GetHttpForm()
|
|
||||||
{
|
|
||||||
return m_form;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
/** \file HttpdSocket.h
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
Copyright (C) 2001-2004,2005 Anders Hedstrom (grymse@alhem.net)
|
|
||||||
|
|
||||||
This library is made available under the terms of the GNU GPL.
|
|
||||||
|
|
||||||
If you would like to use this library in a closed-source application,
|
|
||||||
a separate license agreement is available. For information about
|
|
||||||
the closed-source license agreement for the C++ sockets library,
|
|
||||||
please visit http://www.alhem.net/Sockets/license.html and/or
|
|
||||||
email license@alhem.net.
|
|
||||||
|
|
||||||
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 2
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
#ifndef _HTTPDSOCKET_H
|
|
||||||
#define _HTTPDSOCKET_H
|
|
||||||
|
|
||||||
#include "HTTPSocket.h"
|
|
||||||
|
|
||||||
class TCPConnection;
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
namespace SOCKETS_NAMESPACE {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
class HttpdCookies;
|
|
||||||
class HttpdForm;
|
|
||||||
class IFile;
|
|
||||||
|
|
||||||
/** \defgroup webserver Webserver framework */
|
|
||||||
/** Web server socket framework.
|
|
||||||
\ingroup webserver */
|
|
||||||
class HttpdSocket : public HTTPSocket
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HttpdSocket(uint32 ID, SOCKET in_socket, uint32 irIP, uint16 irPort);
|
|
||||||
~HttpdSocket();
|
|
||||||
|
|
||||||
void OnFirst();
|
|
||||||
void OnHeader(const std::string& key,const std::string& value);
|
|
||||||
void OnHeaderComplete();
|
|
||||||
void OnData(const char *,size_t);
|
|
||||||
|
|
||||||
/** This method needs to be implemented with logic to produce
|
|
||||||
a response to an incoming request. */
|
|
||||||
virtual void Exec() = 0;
|
|
||||||
/** Get current date in http rfc format. */
|
|
||||||
const std::string& GetHttpDate();
|
|
||||||
/** Get pointer to cookie class. */
|
|
||||||
HttpdCookies *GetCookies();
|
|
||||||
/** Get pointer to query string/form data class. */
|
|
||||||
HttpdForm *GetHttpForm();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
/** Decode and send a base64-encoded string.
|
|
||||||
\param str64 Base64-encoded string
|
|
||||||
\param type Mime type of content (content-type header) */
|
|
||||||
void Send64(const std::string& str64, const std::string& type);
|
|
||||||
std::string datetime2httpdate(const std::string& dt);
|
|
||||||
std::string GetDate();
|
|
||||||
void Reset();
|
|
||||||
// headers
|
|
||||||
std::string m_http_cookie;
|
|
||||||
std::string m_content_type;
|
|
||||||
std::string m_content_length_str;
|
|
||||||
std::string m_if_modified_since;
|
|
||||||
|
|
||||||
private:
|
|
||||||
static int m_request_count;
|
|
||||||
static std::string m_start;
|
|
||||||
size_t m_content_length;
|
|
||||||
IFile *m_file;
|
|
||||||
size_t m_received;
|
|
||||||
int m_request_id;
|
|
||||||
std::string m_http_date;
|
|
||||||
HttpdCookies *m_cookies;
|
|
||||||
HttpdForm *m_form;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // _HTTPDSOCKET_H
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
/** \file IFile.h
|
|
||||||
** \date 2005-04-25
|
|
||||||
** \author grymse@alhem.net
|
|
||||||
**/
|
|
||||||
/*
|
|
||||||
Copyright (C) 2004,2005 Anders Hedstrom
|
|
||||||
|
|
||||||
This library is made available under the terms of the GNU GPL.
|
|
||||||
|
|
||||||
If you would like to use this library in a closed-source application,
|
|
||||||
a separate license agreement is available. For information about
|
|
||||||
the closed-source license agreement for the C++ sockets library,
|
|
||||||
please visit http://www.alhem.net/Sockets/license.html and/or
|
|
||||||
email license@alhem.net.
|
|
||||||
|
|
||||||
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 2
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
#ifndef _IFILE_H
|
|
||||||
#define _IFILE_H
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
namespace SOCKETS_NAMESPACE {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** \defgroup file File handling */
|
|
||||||
/** Pure virtual file I/O interface.
|
|
||||||
\ingroup file */
|
|
||||||
class IFile
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~IFile() {}
|
|
||||||
|
|
||||||
virtual bool fopen(const std::string&, const std::string&) = 0;
|
|
||||||
virtual void fclose() = 0;
|
|
||||||
|
|
||||||
virtual size_t fread(char *, size_t, size_t) = 0;
|
|
||||||
virtual size_t fwrite(const char *, size_t, size_t) = 0;
|
|
||||||
|
|
||||||
virtual char *fgets(char *, int) = 0;
|
|
||||||
virtual void fprintf(char *format, ...) = 0;
|
|
||||||
|
|
||||||
virtual off_t size() = 0;
|
|
||||||
virtual bool eof() = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // _IFILE_H
|
|
||||||
@@ -1,214 +0,0 @@
|
|||||||
/** \file MemFile.cpp
|
|
||||||
** \date 2005-04-25
|
|
||||||
** \author grymse@alhem.net
|
|
||||||
**/
|
|
||||||
/*
|
|
||||||
Copyright (C) 2004,2005 Anders Hedstrom
|
|
||||||
|
|
||||||
This library is made available under the terms of the GNU GPL.
|
|
||||||
|
|
||||||
If you would like to use this library in a closed-source application,
|
|
||||||
a separate license agreement is available. For information about
|
|
||||||
the closed-source license agreement for the C++ sockets library,
|
|
||||||
please visit http://www.alhem.net/Sockets/license.html and/or
|
|
||||||
email license@alhem.net.
|
|
||||||
|
|
||||||
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 2
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
#ifdef _WIN32
|
|
||||||
#pragma warning(disable:4786)
|
|
||||||
#endif
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
|
|
||||||
#include "MemFile.h"
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
#ifdef _DEBUG
|
|
||||||
#define DEB(x) x
|
|
||||||
#else
|
|
||||||
#define DEB(x)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
namespace SOCKETS_NAMESPACE {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
std::map<std::string,MemFile::block_t *> MemFile::m_files;
|
|
||||||
|
|
||||||
|
|
||||||
MemFile::MemFile()
|
|
||||||
:m_temporary(true)
|
|
||||||
,m_base(new block_t)
|
|
||||||
,m_current_read(m_base)
|
|
||||||
,m_current_write(m_base)
|
|
||||||
,m_read_ptr(0)
|
|
||||||
,m_write_ptr(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
MemFile::MemFile(const std::string& path)
|
|
||||||
:m_path(path)
|
|
||||||
,m_temporary(false)
|
|
||||||
,m_base(m_files[path])
|
|
||||||
,m_current_read(nullptr)
|
|
||||||
,m_current_write(nullptr)
|
|
||||||
,m_read_ptr(0)
|
|
||||||
,m_write_ptr(0)
|
|
||||||
{
|
|
||||||
if (!m_base)
|
|
||||||
{
|
|
||||||
m_base = new block_t;
|
|
||||||
m_files[path] = m_base;
|
|
||||||
}
|
|
||||||
m_current_read = m_base;
|
|
||||||
m_current_write = m_base;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
MemFile::~MemFile()
|
|
||||||
{
|
|
||||||
while (m_base && m_temporary)
|
|
||||||
{
|
|
||||||
block_t *p = m_base;
|
|
||||||
m_base = p -> next;
|
|
||||||
delete p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool MemFile::fopen(const std::string& path, const std::string& mode)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void MemFile::fclose()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
size_t MemFile::fread(char *ptr, size_t size, size_t nmemb)
|
|
||||||
{
|
|
||||||
size_t p = m_read_ptr % BLOCKSIZE;
|
|
||||||
size_t sz = size * nmemb;
|
|
||||||
if (p + sz < BLOCKSIZE)
|
|
||||||
{
|
|
||||||
//printf("Read @ %d(%d). %d bytes. (%c)\n", m_read_ptr, p, sz, *(m_current_read -> data + p));
|
|
||||||
memcpy(ptr, m_current_read -> data + p, sz);
|
|
||||||
m_read_ptr += sz;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
size_t sz1 = BLOCKSIZE - p;
|
|
||||||
size_t sz2 = size - sz1;
|
|
||||||
memcpy(ptr, m_current_read -> data + p, sz1);
|
|
||||||
m_read_ptr += sz1;
|
|
||||||
if (m_current_read -> next)
|
|
||||||
{
|
|
||||||
m_current_read = m_current_read -> next;
|
|
||||||
memcpy(ptr + sz1, m_current_read -> data, sz2);
|
|
||||||
m_read_ptr += sz2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DEB(printf("Read beyond available data\n");)
|
|
||||||
return sz1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sz;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
size_t MemFile::fwrite(const char *ptr, size_t size, size_t nmemb)
|
|
||||||
{
|
|
||||||
size_t p = m_write_ptr % BLOCKSIZE;
|
|
||||||
size_t sz = size * nmemb;
|
|
||||||
if (p + sz < BLOCKSIZE)
|
|
||||||
{
|
|
||||||
//printf("Write @ %d(%d). %d bytes.\n", m_write_ptr, p, sz);
|
|
||||||
memcpy(m_current_write -> data + p, ptr, sz);
|
|
||||||
m_write_ptr += sz;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
size_t sz1 = BLOCKSIZE - p;
|
|
||||||
size_t sz2 = size - sz1;
|
|
||||||
memcpy(m_current_write -> data + p, ptr, sz1);
|
|
||||||
block_t *next = new block_t;
|
|
||||||
m_current_write -> next = next;
|
|
||||||
m_current_write = next;
|
|
||||||
memcpy(m_current_write -> data, ptr + sz1, sz2);
|
|
||||||
m_write_ptr += sz;
|
|
||||||
}
|
|
||||||
return sz;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
char *MemFile::fgets(char *s, int size)
|
|
||||||
{
|
|
||||||
int n = 0;
|
|
||||||
while (n < size - 1 && !eof())
|
|
||||||
{
|
|
||||||
char c;
|
|
||||||
fread(&c, 1, 1);
|
|
||||||
if (c == 10)
|
|
||||||
{
|
|
||||||
s[n] = 0;
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
s[n++] = c;
|
|
||||||
}
|
|
||||||
s[n] = 0;
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void MemFile::fprintf(char *format, ...)
|
|
||||||
{
|
|
||||||
va_list ap;
|
|
||||||
char tmp[BLOCKSIZE];
|
|
||||||
va_start(ap, format);
|
|
||||||
#ifdef _WIN32
|
|
||||||
vsprintf(tmp, format, ap);
|
|
||||||
#else
|
|
||||||
vsnprintf(tmp, BLOCKSIZE - 1, format, ap);
|
|
||||||
#endif
|
|
||||||
va_end(ap);
|
|
||||||
fwrite(tmp, 1, strlen(tmp));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
off_t MemFile::size()
|
|
||||||
{
|
|
||||||
return (off_t)m_write_ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool MemFile::eof()
|
|
||||||
{
|
|
||||||
return (m_read_ptr < m_write_ptr) ? false : true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
/** \file MemFile.h
|
|
||||||
** \date 2005-04-25
|
|
||||||
** \author grymse@alhem.net
|
|
||||||
**/
|
|
||||||
/*
|
|
||||||
Copyright (C) 2004,2005 Anders Hedstrom
|
|
||||||
|
|
||||||
This library is made available under the terms of the GNU GPL.
|
|
||||||
|
|
||||||
If you would like to use this library in a closed-source application,
|
|
||||||
a separate license agreement is available. For information about
|
|
||||||
the closed-source license agreement for the C++ sockets library,
|
|
||||||
please visit http://www.alhem.net/Sockets/license.html and/or
|
|
||||||
email license@alhem.net.
|
|
||||||
|
|
||||||
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 2
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
#ifndef _MEMFILE_H
|
|
||||||
#define _MEMFILE_H
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include "IFile.h"
|
|
||||||
|
|
||||||
#define BLOCKSIZE 32768
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
namespace SOCKETS_NAMESPACE {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/** Implements a memory file.
|
|
||||||
\ingroup file */
|
|
||||||
class MemFile : public IFile
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/** File block structure.
|
|
||||||
\ingroup file */
|
|
||||||
struct block_t {
|
|
||||||
block_t() : next(nullptr) {}
|
|
||||||
struct block_t *next;
|
|
||||||
char data[BLOCKSIZE];
|
|
||||||
};
|
|
||||||
public:
|
|
||||||
MemFile();
|
|
||||||
MemFile(const std::string& path);
|
|
||||||
~MemFile();
|
|
||||||
|
|
||||||
bool fopen(const std::string& path, const std::string& mode);
|
|
||||||
void fclose();
|
|
||||||
|
|
||||||
size_t fread(char *ptr, size_t size, size_t nmemb);
|
|
||||||
size_t fwrite(const char *ptr, size_t size, size_t nmemb);
|
|
||||||
|
|
||||||
char *fgets(char *s, int size);
|
|
||||||
void fprintf(char *format, ...);
|
|
||||||
|
|
||||||
off_t size();
|
|
||||||
bool eof();
|
|
||||||
|
|
||||||
private:
|
|
||||||
MemFile(const MemFile& ) {} // copy constructor
|
|
||||||
MemFile& operator=(const MemFile& ) { return *this; } // assignment operator
|
|
||||||
|
|
||||||
static std::map<std::string,block_t *> m_files;
|
|
||||||
std::string m_path;
|
|
||||||
bool m_temporary;
|
|
||||||
block_t *m_base;
|
|
||||||
block_t *m_current_read;
|
|
||||||
block_t *m_current_write;
|
|
||||||
size_t m_read_ptr;
|
|
||||||
size_t m_write_ptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // _MEMFILE_H
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
/**
|
|
||||||
** File ......... Mime.cpp
|
|
||||||
** Published .... 2004-07-13
|
|
||||||
** Author ....... grymse@alhem.net
|
|
||||||
**/
|
|
||||||
/*
|
|
||||||
Copyright (C) 2004 Anders Hedstrom
|
|
||||||
|
|
||||||
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 2
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "Parse.h"
|
|
||||||
#include "Mime.h"
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Mime::Mime() {
|
|
||||||
}
|
|
||||||
|
|
||||||
Mime::Mime(const std::string& filename) {
|
|
||||||
LoadMimeFile(filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Mime::LoadMimeFile(const std::string& filename) {
|
|
||||||
FILE *fil;
|
|
||||||
if ((fil = fopen(filename.c_str(),"rt")) != nullptr) {
|
|
||||||
char * slask = new char[1000];
|
|
||||||
fgets(slask,1000,fil);
|
|
||||||
while (!feof(fil))
|
|
||||||
{
|
|
||||||
while (strlen(slask) && (slask[strlen(slask) - 1] == 13 || slask[strlen(slask) - 1] == 10))
|
|
||||||
{
|
|
||||||
slask[strlen(slask) - 1] = 0;
|
|
||||||
}
|
|
||||||
Parse pa(slask);
|
|
||||||
std::string mime_type = pa.getword();
|
|
||||||
std::string ext = pa.getword();
|
|
||||||
while (ext.size())
|
|
||||||
{
|
|
||||||
m_mime[ext] = mime_type;
|
|
||||||
ext = pa.getword();
|
|
||||||
}
|
|
||||||
//
|
|
||||||
fgets(slask,1000,fil);
|
|
||||||
}
|
|
||||||
delete[] slask;
|
|
||||||
fclose(fil);
|
|
||||||
return(true);
|
|
||||||
}
|
|
||||||
return(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Mime::~Mime()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Mime::Clear() {
|
|
||||||
m_mime.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Mime::GetMimeFromFilename(const std::string &filename) const {
|
|
||||||
std::string::size_type pos = filename.find_last_of('.');
|
|
||||||
if(pos == std::string::npos)
|
|
||||||
return(std::string("text/plain"));
|
|
||||||
return(GetMimeFromExtension(filename.substr(pos+1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Mime::GetMimeFromExtension(const std::string& ext) const {
|
|
||||||
mime_m::const_iterator res;
|
|
||||||
res = m_mime.find(ext);
|
|
||||||
if(res == m_mime.end())
|
|
||||||
return(std::string("text/plain"));
|
|
||||||
|
|
||||||
return res->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
/**
|
|
||||||
** File ......... Mime.h
|
|
||||||
** Published .... 2004-07-13
|
|
||||||
** Author ....... grymse@alhem.net
|
|
||||||
**/
|
|
||||||
/*
|
|
||||||
Copyright (C) 2004 Anders Hedstrom
|
|
||||||
|
|
||||||
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 2
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
#ifndef _MIME_H
|
|
||||||
#define _MIME_H
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
namespace SOCKETS_NAMESPACE {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class Mime {
|
|
||||||
typedef std::map<std::string,std::string> mime_m;
|
|
||||||
public:
|
|
||||||
Mime();
|
|
||||||
Mime(const std::string& mime_file);
|
|
||||||
~Mime();
|
|
||||||
|
|
||||||
void Clear();
|
|
||||||
bool LoadMimeFile(const std::string& mime_file);
|
|
||||||
|
|
||||||
std::string GetMimeFromFilename(const std::string &filename) const;
|
|
||||||
std::string GetMimeFromExtension(const std::string &ext) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
mime_m m_mime;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // _MIME_H
|
|
||||||
@@ -1,327 +0,0 @@
|
|||||||
/** \file Parse.cpp - parse a string
|
|
||||||
**
|
|
||||||
** Written: 1999-Feb-10 grymse@alhem.net
|
|
||||||
**/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright (C) 1999-2005 Anders Hedstrom
|
|
||||||
|
|
||||||
This library is made available under the terms of the GNU GPL.
|
|
||||||
|
|
||||||
If you would like to use this library in a closed-source application,
|
|
||||||
a separate license agreement is available. For information about
|
|
||||||
the closed-source license agreement for the C++ sockets library,
|
|
||||||
please visit http://www.alhem.net/Sockets/license.html and/or
|
|
||||||
email license@alhem.net.
|
|
||||||
|
|
||||||
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 2
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "Parse.h"
|
|
||||||
|
|
||||||
#ifdef _DEBUG
|
|
||||||
#define DEB(x)
|
|
||||||
#else
|
|
||||||
#define DEB(x)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
namespace SOCKETS_NAMESPACE {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/* implementation of class Parse */
|
|
||||||
|
|
||||||
Parse::Parse()
|
|
||||||
:pa_the_str("")
|
|
||||||
,pa_splits("")
|
|
||||||
,pa_ord("")
|
|
||||||
,pa_the_ptr(0)
|
|
||||||
,pa_breakchar(0)
|
|
||||||
,pa_enable(0)
|
|
||||||
,pa_disable(0)
|
|
||||||
,pa_nospace(0)
|
|
||||||
,pa_quote(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Parse::Parse(const std::string&s)
|
|
||||||
:pa_the_str(s)
|
|
||||||
,pa_splits("")
|
|
||||||
,pa_ord("")
|
|
||||||
,pa_the_ptr(0)
|
|
||||||
,pa_breakchar(0)
|
|
||||||
,pa_enable(0)
|
|
||||||
,pa_disable(0)
|
|
||||||
,pa_nospace(0)
|
|
||||||
,pa_quote(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Parse::Parse(const std::string&s,const std::string&sp)
|
|
||||||
:pa_the_str(s)
|
|
||||||
,pa_splits(sp)
|
|
||||||
,pa_ord("")
|
|
||||||
,pa_the_ptr(0)
|
|
||||||
,pa_breakchar(0)
|
|
||||||
,pa_enable(0)
|
|
||||||
,pa_disable(0)
|
|
||||||
,pa_nospace(0)
|
|
||||||
,pa_quote(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Parse::Parse(const std::string&s,const std::string&sp,short nospace)
|
|
||||||
:pa_the_str(s)
|
|
||||||
,pa_splits(sp)
|
|
||||||
,pa_ord("")
|
|
||||||
,pa_the_ptr(0)
|
|
||||||
,pa_breakchar(0)
|
|
||||||
,pa_enable(0)
|
|
||||||
,pa_disable(0)
|
|
||||||
,pa_nospace(1)
|
|
||||||
,pa_quote(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Parse::~Parse()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
#define C ((pa_the_ptr<pa_the_str.size()) ? pa_the_str[pa_the_ptr] : 0)
|
|
||||||
|
|
||||||
short Parse::issplit(char c)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < pa_splits.size(); i++)
|
|
||||||
if (pa_splits[i] == c)
|
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Parse::getsplit(void)
|
|
||||||
{
|
|
||||||
size_t x;
|
|
||||||
|
|
||||||
if (C == '=')
|
|
||||||
{
|
|
||||||
x = pa_the_ptr++;
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
while (C && (issplit(C)))
|
|
||||||
pa_the_ptr++;
|
|
||||||
x = pa_the_ptr;
|
|
||||||
while (C && !issplit(C) && C != '=')
|
|
||||||
pa_the_ptr++;
|
|
||||||
}
|
|
||||||
if (x == pa_the_ptr && C == '=')
|
|
||||||
pa_the_ptr++;
|
|
||||||
pa_ord = (x < pa_the_str.size()) ? pa_the_str.substr(x,pa_the_ptr - x) : "";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Parse::getword(void)
|
|
||||||
{
|
|
||||||
size_t x;
|
|
||||||
int disabled = 0;
|
|
||||||
int quote = 0;
|
|
||||||
int rem = 0;
|
|
||||||
|
|
||||||
if (pa_nospace)
|
|
||||||
{
|
|
||||||
while (C && issplit(C))
|
|
||||||
pa_the_ptr++;
|
|
||||||
x = pa_the_ptr;
|
|
||||||
while (C && !issplit(C) && (C != pa_breakchar || !pa_breakchar || disabled))
|
|
||||||
{
|
|
||||||
if (pa_breakchar && C == pa_disable)
|
|
||||||
disabled = 1;
|
|
||||||
if (pa_breakchar && C == pa_enable)
|
|
||||||
disabled = 0;
|
|
||||||
if (pa_quote && C == '"')
|
|
||||||
quote = 1;
|
|
||||||
pa_the_ptr++;
|
|
||||||
while (quote && C && C != '"')
|
|
||||||
{
|
|
||||||
pa_the_ptr++;
|
|
||||||
}
|
|
||||||
if (pa_quote && C == '"')
|
|
||||||
{
|
|
||||||
pa_the_ptr++;
|
|
||||||
}
|
|
||||||
quote = 0;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
if (C == pa_breakchar && pa_breakchar)
|
|
||||||
{
|
|
||||||
x = pa_the_ptr++;
|
|
||||||
rem = 1;
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
while (C && (C == ' ' || C == 9 || C == 13 || C == 10 || issplit(C)))
|
|
||||||
pa_the_ptr++;
|
|
||||||
x = pa_the_ptr;
|
|
||||||
while (C && C != ' ' && C != 9 && C != 13 && C != 10 && !issplit(C) &&
|
|
||||||
(C != pa_breakchar || !pa_breakchar || disabled))
|
|
||||||
{
|
|
||||||
if (pa_breakchar && C == pa_disable)
|
|
||||||
disabled = 1;
|
|
||||||
if (pa_breakchar && C == pa_enable)
|
|
||||||
disabled = 0;
|
|
||||||
if (pa_quote && C == '"')
|
|
||||||
{
|
|
||||||
quote = 1;
|
|
||||||
pa_the_ptr++;
|
|
||||||
while (quote && C && C != '"')
|
|
||||||
{
|
|
||||||
pa_the_ptr++;
|
|
||||||
}
|
|
||||||
if (pa_quote && C == '"')
|
|
||||||
{
|
|
||||||
pa_the_ptr++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
pa_the_ptr++;
|
|
||||||
quote = 0;
|
|
||||||
}
|
|
||||||
pa_the_ptr++;
|
|
||||||
rem = 1;
|
|
||||||
}
|
|
||||||
if (x == pa_the_ptr && C == pa_breakchar && pa_breakchar)
|
|
||||||
pa_the_ptr++;
|
|
||||||
}
|
|
||||||
if (x < pa_the_str.size())
|
|
||||||
{
|
|
||||||
pa_ord = pa_the_str.substr(x,pa_the_ptr - x - rem);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pa_ord = "";
|
|
||||||
}
|
|
||||||
return pa_ord;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Parse::getword(std::string&s)
|
|
||||||
{
|
|
||||||
s = Parse::getword();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Parse::getsplit(std::string&s)
|
|
||||||
{
|
|
||||||
Parse::getsplit();
|
|
||||||
s = pa_ord;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Parse::getword(std::string&s,std::string&fill,int l)
|
|
||||||
{
|
|
||||||
Parse::getword();
|
|
||||||
s = "";
|
|
||||||
while (s.size() + pa_ord.size() < (size_t)l)
|
|
||||||
s += fill;
|
|
||||||
s += pa_ord;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Parse::getrest()
|
|
||||||
{
|
|
||||||
std::string s;
|
|
||||||
while (C && (C == ' ' || C == 9 || issplit(C)))
|
|
||||||
pa_the_ptr++;
|
|
||||||
s = (pa_the_ptr < pa_the_str.size()) ? pa_the_str.substr(pa_the_ptr) : "";
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Parse::getrest(std::string&s)
|
|
||||||
{
|
|
||||||
while (C && (C == ' ' || C == 9 || issplit(C)))
|
|
||||||
pa_the_ptr++;
|
|
||||||
s = (pa_the_ptr < pa_the_str.size()) ? pa_the_str.substr(pa_the_ptr) : "";
|
|
||||||
}
|
|
||||||
|
|
||||||
long Parse::getvalue(void)
|
|
||||||
{
|
|
||||||
Parse::getword();
|
|
||||||
return atol(pa_ord.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Parse::setbreak(char c)
|
|
||||||
{
|
|
||||||
pa_breakchar = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Parse::getwordlen(void)
|
|
||||||
{
|
|
||||||
size_t x,y = pa_the_ptr,len;
|
|
||||||
|
|
||||||
if (C == pa_breakchar && pa_breakchar)
|
|
||||||
{
|
|
||||||
x = pa_the_ptr++;
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
while (C && (C == ' ' || C == 9 || C == 13 || C == 10 || issplit(C)))
|
|
||||||
pa_the_ptr++;
|
|
||||||
x = pa_the_ptr;
|
|
||||||
while (C && C != ' ' && C != 9 && C != 13 && C != 10 && !issplit(C) && (C != pa_breakchar || !pa_breakchar))
|
|
||||||
pa_the_ptr++;
|
|
||||||
}
|
|
||||||
if (x == pa_the_ptr && C == pa_breakchar && pa_breakchar)
|
|
||||||
pa_the_ptr++;
|
|
||||||
len = pa_the_ptr - x;
|
|
||||||
pa_the_ptr = y;
|
|
||||||
return (int)len;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Parse::getrestlen(void)
|
|
||||||
{
|
|
||||||
size_t y = pa_the_ptr;
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
while (C && (C == ' ' || C == 9 || issplit(C)))
|
|
||||||
pa_the_ptr++;
|
|
||||||
len = strlen(pa_the_str.c_str() + pa_the_ptr);
|
|
||||||
pa_the_ptr = y;
|
|
||||||
return (int)len;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Parse::getline(void)
|
|
||||||
{
|
|
||||||
size_t x;
|
|
||||||
|
|
||||||
x = pa_the_ptr;
|
|
||||||
while (C && C != 13 && C != 10)
|
|
||||||
pa_the_ptr++;
|
|
||||||
pa_ord = (x < pa_the_str.size()) ? pa_the_str.substr(x,pa_the_ptr - x) : "";
|
|
||||||
if (C == 13)
|
|
||||||
pa_the_ptr++;
|
|
||||||
if (C == 10)
|
|
||||||
pa_the_ptr++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Parse::getline(std::string&s)
|
|
||||||
{
|
|
||||||
getline();
|
|
||||||
s = pa_ord;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* end of implementation of class Parse */
|
|
||||||
/***************************************************/
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
/** \file Parse.h - parse a string
|
|
||||||
**
|
|
||||||
** Written: 1999-Feb-10 grymse@alhem.net
|
|
||||||
**/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright (C) 1999-2005 Anders Hedstrom
|
|
||||||
|
|
||||||
This library is made available under the terms of the GNU GPL.
|
|
||||||
|
|
||||||
If you would like to use this library in a closed-source application,
|
|
||||||
a separate license agreement is available. For information about
|
|
||||||
the closed-source license agreement for the C++ sockets library,
|
|
||||||
please visit http://www.alhem.net/Sockets/license.html and/or
|
|
||||||
email license@alhem.net.
|
|
||||||
|
|
||||||
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 2
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _PARSE_H
|
|
||||||
#define _PARSE_H
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
namespace SOCKETS_NAMESPACE {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/***************************************************/
|
|
||||||
/* interface of class Parse */
|
|
||||||
|
|
||||||
/** Splits a string whatever way you want.
|
|
||||||
\ingroup util */
|
|
||||||
class Parse
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Parse();
|
|
||||||
Parse(const std::string&);
|
|
||||||
Parse(const std::string&,const std::string&);
|
|
||||||
Parse(const std::string&,const std::string&,short);
|
|
||||||
~Parse();
|
|
||||||
short issplit(char);
|
|
||||||
void getsplit(void);
|
|
||||||
void getsplit(std::string&);
|
|
||||||
std::string getword(void);
|
|
||||||
void getword(std::string&);
|
|
||||||
void getword(std::string&,std::string&,int);
|
|
||||||
std::string getrest();
|
|
||||||
void getrest(std::string&);
|
|
||||||
long getvalue(void);
|
|
||||||
void setbreak(char);
|
|
||||||
int getwordlen(void);
|
|
||||||
int getrestlen(void);
|
|
||||||
void enablebreak(char c) {
|
|
||||||
pa_enable = c;
|
|
||||||
}
|
|
||||||
void disablebreak(char c) {
|
|
||||||
pa_disable = c;
|
|
||||||
}
|
|
||||||
void getline(void);
|
|
||||||
void getline(std::string&);
|
|
||||||
size_t getptr(void) { return pa_the_ptr; }
|
|
||||||
void EnableQuote(bool b) { pa_quote = b; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string pa_the_str;
|
|
||||||
std::string pa_splits;
|
|
||||||
std::string pa_ord;
|
|
||||||
size_t pa_the_ptr;
|
|
||||||
char pa_breakchar;
|
|
||||||
char pa_enable;
|
|
||||||
char pa_disable;
|
|
||||||
short pa_nospace;
|
|
||||||
bool pa_quote;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // _PARSE_H
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
EQEmu took this code from `C++ Sockets Library`
|
|
||||||
http://www.alhem.net/Sockets/
|
|
||||||
and integrated it into our world server. We did not care for the actual
|
|
||||||
socket code (didnt work on windows) so we scrapped all of it, and just
|
|
||||||
used the HTTP framework code.
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
Find uuid.h here
|
|
||||||
http://www.die.net/doc/linux/include/uuid/uuid.h
|
|
||||||
or here
|
|
||||||
http://www.thedna.net/uuid.h
|
|
||||||
|
|
||||||
@@ -1,167 +0,0 @@
|
|||||||
/** \file Utility.cpp
|
|
||||||
** \date 2004-02-13
|
|
||||||
** \author grymse@alhem.net
|
|
||||||
**/
|
|
||||||
/*
|
|
||||||
Copyright (C) 2004,2005 Anders Hedstrom
|
|
||||||
|
|
||||||
This library is made available under the terms of the GNU GPL.
|
|
||||||
|
|
||||||
If you would like to use this library in a closed-source application,
|
|
||||||
a separate license agreement is available. For information about
|
|
||||||
the closed-source license agreement for the C++ sockets library,
|
|
||||||
please visit http://www.alhem.net/Sockets/license.html and/or
|
|
||||||
email license@alhem.net.
|
|
||||||
|
|
||||||
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 2
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
#include "Utility.h"
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
namespace SOCKETS_NAMESPACE {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
std::string Utility::base64(const std::string& str_in)
|
|
||||||
{
|
|
||||||
std::string str;
|
|
||||||
Base64::encode(str_in, str, false); // , false == do not add cr/lf
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::string Utility::base64d(const std::string& str_in)
|
|
||||||
{
|
|
||||||
std::string str;
|
|
||||||
Base64::decode(str_in, str);
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::string Utility::l2string(long l)
|
|
||||||
{
|
|
||||||
std::string str;
|
|
||||||
char tmp[100];
|
|
||||||
sprintf(tmp,"%ld",l);
|
|
||||||
str = tmp;
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::string Utility::bigint2string(uint64_t l)
|
|
||||||
{
|
|
||||||
std::string str;
|
|
||||||
uint64_t tmp = l;
|
|
||||||
while (tmp)
|
|
||||||
{
|
|
||||||
uint64_t a = tmp % 10;
|
|
||||||
str = (char)(a + 48) + str;
|
|
||||||
tmp /= 10;
|
|
||||||
}
|
|
||||||
if (!str.size())
|
|
||||||
{
|
|
||||||
str = "0";
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
uint64_t Utility::atoi64(const std::string& str)
|
|
||||||
{
|
|
||||||
uint64_t l = 0;
|
|
||||||
for (size_t i = 0; i < str.size(); i++)
|
|
||||||
{
|
|
||||||
l = l * 10 + str[i] - 48;
|
|
||||||
}
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
unsigned int Utility::hex2unsigned(const std::string& str)
|
|
||||||
{
|
|
||||||
unsigned int r = 0;
|
|
||||||
for (size_t i = 0; i < str.size(); i++)
|
|
||||||
{
|
|
||||||
r = r * 16 + str[i] - 48 - ((str[i] >= 'A') ? 7 : 0) - ((str[i] >= 'a') ? 32 : 0);
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Encode string per RFC1738 URL encoding rules
|
|
||||||
* tnx rstaveley
|
|
||||||
*/
|
|
||||||
std::string Utility::rfc1738_encode(const std::string& src)
|
|
||||||
{
|
|
||||||
static char hex[] = "0123456789ABCDEF";
|
|
||||||
std::string dst;
|
|
||||||
for (size_t i = 0; i < src.size(); i++)
|
|
||||||
{
|
|
||||||
if (isalnum(src[i]))
|
|
||||||
{
|
|
||||||
dst += src[i];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if (src[i] == ' ')
|
|
||||||
{
|
|
||||||
dst += '+';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dst += '%';
|
|
||||||
dst += hex[src[i] / 16];
|
|
||||||
dst += hex[src[i] % 16];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return dst;
|
|
||||||
} // rfc1738_encode
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Decode string per RFC1738 URL encoding rules
|
|
||||||
* tnx rstaveley
|
|
||||||
*/
|
|
||||||
std::string Utility::rfc1738_decode(const std::string& src)
|
|
||||||
{
|
|
||||||
std::string dst;
|
|
||||||
for (size_t i = 0; i < src.size(); i++)
|
|
||||||
{
|
|
||||||
if (src[i] == '%' && isxdigit(src[i + 1]) && isxdigit(src[i + 2]))
|
|
||||||
{
|
|
||||||
char c1 = src[++i];
|
|
||||||
char c2 = src[++i];
|
|
||||||
c1 = c1 - 48 - ((c1 >= 'A') ? 7 : 0) - ((c1 >= 'a') ? 32 : 0);
|
|
||||||
c2 = c2 - 48 - ((c2 >= 'A') ? 7 : 0) - ((c2 >= 'a') ? 32 : 0);
|
|
||||||
dst += (char)(c1 * 16 + c2);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if (src[i] == '+')
|
|
||||||
{
|
|
||||||
dst += ' ';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dst += src[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return dst;
|
|
||||||
} // rfc1738_decode
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
/** \file Utility.h
|
|
||||||
** \date 2004-02-13
|
|
||||||
** \author grymse@alhem.net
|
|
||||||
**/
|
|
||||||
/*
|
|
||||||
Copyright (C) 2004,2005 Anders Hedstrom
|
|
||||||
|
|
||||||
This library is made available under the terms of the GNU GPL.
|
|
||||||
|
|
||||||
If you would like to use this library in a closed-source application,
|
|
||||||
a separate license agreement is available. For information about
|
|
||||||
the closed-source license agreement for the C++ sockets library,
|
|
||||||
please visit http://www.alhem.net/Sockets/license.html and/or
|
|
||||||
email license@alhem.net.
|
|
||||||
|
|
||||||
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 2
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
#ifndef _UTILITY_H
|
|
||||||
#define _UTILITY_H
|
|
||||||
|
|
||||||
#include <ctype.h>
|
|
||||||
#ifdef _WIN32
|
|
||||||
typedef unsigned __int64 uint64_t;
|
|
||||||
#else
|
|
||||||
#include <stdlib.h>
|
|
||||||
#ifdef SOLARIS
|
|
||||||
# include <sys/types.h>
|
|
||||||
#else
|
|
||||||
# include <stdint.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#include "Base64.h"
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
namespace SOCKETS_NAMESPACE {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** Conversion utilities.
|
|
||||||
\ingroup util */
|
|
||||||
class Utility
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static std::string base64(const std::string& str_in);
|
|
||||||
static std::string base64d(const std::string& str_in);
|
|
||||||
static std::string l2string(long l);
|
|
||||||
static std::string bigint2string(uint64_t l);
|
|
||||||
static uint64_t atoi64(const std::string& str);
|
|
||||||
static unsigned int hex2unsigned(const std::string& str);
|
|
||||||
static std::string rfc1738_encode(const std::string& src);
|
|
||||||
static std::string rfc1738_decode(const std::string& src);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // _UTILITY_H
|
|
||||||
@@ -1,340 +0,0 @@
|
|||||||
GNU GENERAL PUBLIC LICENSE
|
|
||||||
Version 2, June 1991
|
|
||||||
|
|
||||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
|
||||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
|
||||||
of this license document, but changing it is not allowed.
|
|
||||||
|
|
||||||
Preamble
|
|
||||||
|
|
||||||
The licenses for most software are designed to take away your
|
|
||||||
freedom to share and change it. By contrast, the GNU General Public
|
|
||||||
License is intended to guarantee your freedom to share and change free
|
|
||||||
software--to make sure the software is free for all its users. This
|
|
||||||
General Public License applies to most of the Free Software
|
|
||||||
Foundation's software and to any other program whose authors commit to
|
|
||||||
using it. (Some other Free Software Foundation software is covered by
|
|
||||||
the GNU Library General Public License instead.) You can apply it to
|
|
||||||
your programs, too.
|
|
||||||
|
|
||||||
When we speak of free software, we are referring to freedom, not
|
|
||||||
price. Our General Public Licenses are designed to make sure that you
|
|
||||||
have the freedom to distribute copies of free software (and charge for
|
|
||||||
this service if you wish), that you receive source code or can get it
|
|
||||||
if you want it, that you can change the software or use pieces of it
|
|
||||||
in new free programs; and that you know you can do these things.
|
|
||||||
|
|
||||||
To protect your rights, we need to make restrictions that forbid
|
|
||||||
anyone to deny you these rights or to ask you to surrender the rights.
|
|
||||||
These restrictions translate to certain responsibilities for you if you
|
|
||||||
distribute copies of the software, or if you modify it.
|
|
||||||
|
|
||||||
For example, if you distribute copies of such a program, whether
|
|
||||||
gratis or for a fee, you must give the recipients all the rights that
|
|
||||||
you have. You must make sure that they, too, receive or can get the
|
|
||||||
source code. And you must show them these terms so they know their
|
|
||||||
rights.
|
|
||||||
|
|
||||||
We protect your rights with two steps: (1) copyright the software, and
|
|
||||||
(2) offer you this license which gives you legal permission to copy,
|
|
||||||
distribute and/or modify the software.
|
|
||||||
|
|
||||||
Also, for each author's protection and ours, we want to make certain
|
|
||||||
that everyone understands that there is no warranty for this free
|
|
||||||
software. If the software is modified by someone else and passed on, we
|
|
||||||
want its recipients to know that what they have is not the original, so
|
|
||||||
that any problems introduced by others will not reflect on the original
|
|
||||||
authors' reputations.
|
|
||||||
|
|
||||||
Finally, any free program is threatened constantly by software
|
|
||||||
patents. We wish to avoid the danger that redistributors of a free
|
|
||||||
program will individually obtain patent licenses, in effect making the
|
|
||||||
program proprietary. To prevent this, we have made it clear that any
|
|
||||||
patent must be licensed for everyone's free use or not licensed at all.
|
|
||||||
|
|
||||||
The precise terms and conditions for copying, distribution and
|
|
||||||
modification follow.
|
|
||||||
|
|
||||||
GNU GENERAL PUBLIC LICENSE
|
|
||||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
|
||||||
|
|
||||||
0. This License applies to any program or other work which contains
|
|
||||||
a notice placed by the copyright holder saying it may be distributed
|
|
||||||
under the terms of this General Public License. The "Program", below,
|
|
||||||
refers to any such program or work, and a "work based on the Program"
|
|
||||||
means either the Program or any derivative work under copyright law:
|
|
||||||
that is to say, a work containing the Program or a portion of it,
|
|
||||||
either verbatim or with modifications and/or translated into another
|
|
||||||
language. (Hereinafter, translation is included without limitation in
|
|
||||||
the term "modification".) Each licensee is addressed as "you".
|
|
||||||
|
|
||||||
Activities other than copying, distribution and modification are not
|
|
||||||
covered by this License; they are outside its scope. The act of
|
|
||||||
running the Program is not restricted, and the output from the Program
|
|
||||||
is covered only if its contents constitute a work based on the
|
|
||||||
Program (independent of having been made by running the Program).
|
|
||||||
Whether that is true depends on what the Program does.
|
|
||||||
|
|
||||||
1. You may copy and distribute verbatim copies of the Program's
|
|
||||||
source code as you receive it, in any medium, provided that you
|
|
||||||
conspicuously and appropriately publish on each copy an appropriate
|
|
||||||
copyright notice and disclaimer of warranty; keep intact all the
|
|
||||||
notices that refer to this License and to the absence of any warranty;
|
|
||||||
and give any other recipients of the Program a copy of this License
|
|
||||||
along with the Program.
|
|
||||||
|
|
||||||
You may charge a fee for the physical act of transferring a copy, and
|
|
||||||
you may at your option offer warranty protection in exchange for a fee.
|
|
||||||
|
|
||||||
2. You may modify your copy or copies of the Program or any portion
|
|
||||||
of it, thus forming a work based on the Program, and copy and
|
|
||||||
distribute such modifications or work under the terms of Section 1
|
|
||||||
above, provided that you also meet all of these conditions:
|
|
||||||
|
|
||||||
a) You must cause the modified files to carry prominent notices
|
|
||||||
stating that you changed the files and the date of any change.
|
|
||||||
|
|
||||||
b) You must cause any work that you distribute or publish, that in
|
|
||||||
whole or in part contains or is derived from the Program or any
|
|
||||||
part thereof, to be licensed as a whole at no charge to all third
|
|
||||||
parties under the terms of this License.
|
|
||||||
|
|
||||||
c) If the modified program normally reads commands interactively
|
|
||||||
when run, you must cause it, when started running for such
|
|
||||||
interactive use in the most ordinary way, to print or display an
|
|
||||||
announcement including an appropriate copyright notice and a
|
|
||||||
notice that there is no warranty (or else, saying that you provide
|
|
||||||
a warranty) and that users may redistribute the program under
|
|
||||||
these conditions, and telling the user how to view a copy of this
|
|
||||||
License. (Exception: if the Program itself is interactive but
|
|
||||||
does not normally print such an announcement, your work based on
|
|
||||||
the Program is not required to print an announcement.)
|
|
||||||
|
|
||||||
These requirements apply to the modified work as a whole. If
|
|
||||||
identifiable sections of that work are not derived from the Program,
|
|
||||||
and can be reasonably considered independent and separate works in
|
|
||||||
themselves, then this License, and its terms, do not apply to those
|
|
||||||
sections when you distribute them as separate works. But when you
|
|
||||||
distribute the same sections as part of a whole which is a work based
|
|
||||||
on the Program, the distribution of the whole must be on the terms of
|
|
||||||
this License, whose permissions for other licensees extend to the
|
|
||||||
entire whole, and thus to each and every part regardless of who wrote it.
|
|
||||||
|
|
||||||
Thus, it is not the intent of this section to claim rights or contest
|
|
||||||
your rights to work written entirely by you; rather, the intent is to
|
|
||||||
exercise the right to control the distribution of derivative or
|
|
||||||
collective works based on the Program.
|
|
||||||
|
|
||||||
In addition, mere aggregation of another work not based on the Program
|
|
||||||
with the Program (or with a work based on the Program) on a volume of
|
|
||||||
a storage or distribution medium does not bring the other work under
|
|
||||||
the scope of this License.
|
|
||||||
|
|
||||||
3. You may copy and distribute the Program (or a work based on it,
|
|
||||||
under Section 2) in object code or executable form under the terms of
|
|
||||||
Sections 1 and 2 above provided that you also do one of the following:
|
|
||||||
|
|
||||||
a) Accompany it with the complete corresponding machine-readable
|
|
||||||
source code, which must be distributed under the terms of Sections
|
|
||||||
1 and 2 above on a medium customarily used for software interchange; or,
|
|
||||||
|
|
||||||
b) Accompany it with a written offer, valid for at least three
|
|
||||||
years, to give any third party, for a charge no more than your
|
|
||||||
cost of physically performing source distribution, a complete
|
|
||||||
machine-readable copy of the corresponding source code, to be
|
|
||||||
distributed under the terms of Sections 1 and 2 above on a medium
|
|
||||||
customarily used for software interchange; or,
|
|
||||||
|
|
||||||
c) Accompany it with the information you received as to the offer
|
|
||||||
to distribute corresponding source code. (This alternative is
|
|
||||||
allowed only for noncommercial distribution and only if you
|
|
||||||
received the program in object code or executable form with such
|
|
||||||
an offer, in accord with Subsection b above.)
|
|
||||||
|
|
||||||
The source code for a work means the preferred form of the work for
|
|
||||||
making modifications to it. For an executable work, complete source
|
|
||||||
code means all the source code for all modules it contains, plus any
|
|
||||||
associated interface definition files, plus the scripts used to
|
|
||||||
control compilation and installation of the executable. However, as a
|
|
||||||
special exception, the source code distributed need not include
|
|
||||||
anything that is normally distributed (in either source or binary
|
|
||||||
form) with the major components (compiler, kernel, and so on) of the
|
|
||||||
operating system on which the executable runs, unless that component
|
|
||||||
itself accompanies the executable.
|
|
||||||
|
|
||||||
If distribution of executable or object code is made by offering
|
|
||||||
access to copy from a designated place, then offering equivalent
|
|
||||||
access to copy the source code from the same place counts as
|
|
||||||
distribution of the source code, even though third parties are not
|
|
||||||
compelled to copy the source along with the object code.
|
|
||||||
|
|
||||||
4. You may not copy, modify, sublicense, or distribute the Program
|
|
||||||
except as expressly provided under this License. Any attempt
|
|
||||||
otherwise to copy, modify, sublicense or distribute the Program is
|
|
||||||
void, and will automatically terminate your rights under this License.
|
|
||||||
However, parties who have received copies, or rights, from you under
|
|
||||||
this License will not have their licenses terminated so long as such
|
|
||||||
parties remain in full compliance.
|
|
||||||
|
|
||||||
5. You are not required to accept this License, since you have not
|
|
||||||
signed it. However, nothing else grants you permission to modify or
|
|
||||||
distribute the Program or its derivative works. These actions are
|
|
||||||
prohibited by law if you do not accept this License. Therefore, by
|
|
||||||
modifying or distributing the Program (or any work based on the
|
|
||||||
Program), you indicate your acceptance of this License to do so, and
|
|
||||||
all its terms and conditions for copying, distributing or modifying
|
|
||||||
the Program or works based on it.
|
|
||||||
|
|
||||||
6. Each time you redistribute the Program (or any work based on the
|
|
||||||
Program), the recipient automatically receives a license from the
|
|
||||||
original licensor to copy, distribute or modify the Program subject to
|
|
||||||
these terms and conditions. You may not impose any further
|
|
||||||
restrictions on the recipients' exercise of the rights granted herein.
|
|
||||||
You are not responsible for enforcing compliance by third parties to
|
|
||||||
this License.
|
|
||||||
|
|
||||||
7. If, as a consequence of a court judgment or allegation of patent
|
|
||||||
infringement or for any other reason (not limited to patent issues),
|
|
||||||
conditions are imposed on you (whether by court order, agreement or
|
|
||||||
otherwise) that contradict the conditions of this License, they do not
|
|
||||||
excuse you from the conditions of this License. If you cannot
|
|
||||||
distribute so as to satisfy simultaneously your obligations under this
|
|
||||||
License and any other pertinent obligations, then as a consequence you
|
|
||||||
may not distribute the Program at all. For example, if a patent
|
|
||||||
license would not permit royalty-free redistribution of the Program by
|
|
||||||
all those who receive copies directly or indirectly through you, then
|
|
||||||
the only way you could satisfy both it and this License would be to
|
|
||||||
refrain entirely from distribution of the Program.
|
|
||||||
|
|
||||||
If any portion of this section is held invalid or unenforceable under
|
|
||||||
any particular circumstance, the balance of the section is intended to
|
|
||||||
apply and the section as a whole is intended to apply in other
|
|
||||||
circumstances.
|
|
||||||
|
|
||||||
It is not the purpose of this section to induce you to infringe any
|
|
||||||
patents or other property right claims or to contest validity of any
|
|
||||||
such claims; this section has the sole purpose of protecting the
|
|
||||||
integrity of the free software distribution system, which is
|
|
||||||
implemented by public license practices. Many people have made
|
|
||||||
generous contributions to the wide range of software distributed
|
|
||||||
through that system in reliance on consistent application of that
|
|
||||||
system; it is up to the author/donor to decide if he or she is willing
|
|
||||||
to distribute software through any other system and a licensee cannot
|
|
||||||
impose that choice.
|
|
||||||
|
|
||||||
This section is intended to make thoroughly clear what is believed to
|
|
||||||
be a consequence of the rest of this License.
|
|
||||||
|
|
||||||
8. If the distribution and/or use of the Program is restricted in
|
|
||||||
certain countries either by patents or by copyrighted interfaces, the
|
|
||||||
original copyright holder who places the Program under this License
|
|
||||||
may add an explicit geographical distribution limitation excluding
|
|
||||||
those countries, so that distribution is permitted only in or among
|
|
||||||
countries not thus excluded. In such case, this License incorporates
|
|
||||||
the limitation as if written in the body of this License.
|
|
||||||
|
|
||||||
9. The Free Software Foundation may publish revised and/or new versions
|
|
||||||
of the General Public License from time to time. Such new versions will
|
|
||||||
be similar in spirit to the present version, but may differ in detail to
|
|
||||||
address new problems or concerns.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the Program
|
|
||||||
specifies a version number of this License which applies to it and "any
|
|
||||||
later version", you have the option of following the terms and conditions
|
|
||||||
either of that version or of any later version published by the Free
|
|
||||||
Software Foundation. If the Program does not specify a version number of
|
|
||||||
this License, you may choose any version ever published by the Free Software
|
|
||||||
Foundation.
|
|
||||||
|
|
||||||
10. If you wish to incorporate parts of the Program into other free
|
|
||||||
programs whose distribution conditions are different, write to the author
|
|
||||||
to ask for permission. For software which is copyrighted by the Free
|
|
||||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
|
||||||
make exceptions for this. Our decision will be guided by the two goals
|
|
||||||
of preserving the free status of all derivatives of our free software and
|
|
||||||
of promoting the sharing and reuse of software generally.
|
|
||||||
|
|
||||||
NO WARRANTY
|
|
||||||
|
|
||||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
|
||||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
|
||||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
|
||||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
|
||||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
|
||||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
|
||||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
|
||||||
REPAIR OR CORRECTION.
|
|
||||||
|
|
||||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
|
||||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
|
||||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
|
||||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
|
||||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
|
||||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
|
||||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
|
||||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
|
||||||
POSSIBILITY OF SUCH DAMAGES.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
How to Apply These Terms to Your New Programs
|
|
||||||
|
|
||||||
If you develop a new program, and you want it to be of the greatest
|
|
||||||
possible use to the public, the best way to achieve this is to make it
|
|
||||||
free software which everyone can redistribute and change under these terms.
|
|
||||||
|
|
||||||
To do so, attach the following notices to the program. It is safest
|
|
||||||
to attach them to the start of each source file to most effectively
|
|
||||||
convey the exclusion of warranty; and each file should have at least
|
|
||||||
the "copyright" line and a pointer to where the full notice is found.
|
|
||||||
|
|
||||||
<one line to give the program's name and a brief idea of what it does.>
|
|
||||||
Copyright (C) <year> <name of author>
|
|
||||||
|
|
||||||
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 2 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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
|
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
|
||||||
|
|
||||||
If the program is interactive, make it output a short notice like this
|
|
||||||
when it starts in an interactive mode:
|
|
||||||
|
|
||||||
Gnomovision version 69, Copyright (C) year name of author
|
|
||||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
|
||||||
This is free software, and you are welcome to redistribute it
|
|
||||||
under certain conditions; type `show c' for details.
|
|
||||||
|
|
||||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
|
||||||
parts of the General Public License. Of course, the commands you use may
|
|
||||||
be called something other than `show w' and `show c'; they could even be
|
|
||||||
mouse-clicks or menu items--whatever suits your program.
|
|
||||||
|
|
||||||
You should also get your employer (if you work as a programmer) or your
|
|
||||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
|
||||||
necessary. Here is a sample; alter the names:
|
|
||||||
|
|
||||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
|
||||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
|
||||||
|
|
||||||
<signature of Ty Coon>, 1 April 1989
|
|
||||||
Ty Coon, President of Vice
|
|
||||||
|
|
||||||
This General Public License does not permit incorporating your program into
|
|
||||||
proprietary programs. If your program is a subroutine library, you may
|
|
||||||
consider it more useful to permit linking proprietary applications with the
|
|
||||||
library. If this is what you want to do, use the GNU Library General
|
|
||||||
Public License instead of this License.
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
/** \file socket_include.cpp
|
|
||||||
** \date 2004-11-28
|
|
||||||
** \author grymse@alhem.net
|
|
||||||
**/
|
|
||||||
/*
|
|
||||||
Copyright (C) 2004,2005 Anders Hedstrom
|
|
||||||
|
|
||||||
This library is made available under the terms of the GNU GPL.
|
|
||||||
|
|
||||||
If you would like to use this library in a closed-source application,
|
|
||||||
a separate license agreement is available. For information about
|
|
||||||
the closed-source license agreement for the C++ sockets library,
|
|
||||||
please visit http://www.alhem.net/Sockets/license.html and/or
|
|
||||||
email license@alhem.net.
|
|
||||||
|
|
||||||
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 2
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
// only to be included in win32 projects
|
|
||||||
const char *StrError(int x)
|
|
||||||
{
|
|
||||||
static char tmp[100];
|
|
||||||
switch (x)
|
|
||||||
{
|
|
||||||
case 10004: return "Interrupted function call.";
|
|
||||||
case 10013: return "Permission denied.";
|
|
||||||
case 10014: return "Bad address.";
|
|
||||||
case 10022: return "Invalid argument.";
|
|
||||||
case 10024: return "Too many open files.";
|
|
||||||
case 10035: return "Resource temporarily unavailable.";
|
|
||||||
case 10036: return "Operation now in progress.";
|
|
||||||
case 10037: return "Operation already in progress.";
|
|
||||||
case 10038: return "Socket operation on nonsocket.";
|
|
||||||
case 10039: return "Destination address required.";
|
|
||||||
case 10040: return "Message too long.";
|
|
||||||
case 10041: return "Protocol wrong type for socket.";
|
|
||||||
case 10042: return "Bad protocol option.";
|
|
||||||
case 10043: return "Protocol not supported.";
|
|
||||||
case 10044: return "Socket type not supported.";
|
|
||||||
case 10045: return "Operation not supported.";
|
|
||||||
case 10046: return "Protocol family not supported.";
|
|
||||||
case 10047: return "Address family not supported by protocol family.";
|
|
||||||
case 10048: return "Address already in use.";
|
|
||||||
case 10049: return "Cannot assign requested address.";
|
|
||||||
case 10050: return "Network is down.";
|
|
||||||
case 10051: return "Network is unreachable.";
|
|
||||||
case 10052: return "Network dropped connection on reset.";
|
|
||||||
case 10053: return "Software caused connection abort.";
|
|
||||||
case 10054: return "Connection reset by peer.";
|
|
||||||
case 10055: return "No buffer space available.";
|
|
||||||
case 10056: return "Socket is already connected.";
|
|
||||||
case 10057: return "Socket is not connected.";
|
|
||||||
case 10058: return "Cannot send after socket shutdown.";
|
|
||||||
case 10060: return "Connection timed out.";
|
|
||||||
case 10061: return "Connection refused.";
|
|
||||||
case 10064: return "Host is down.";
|
|
||||||
case 10065: return "No route to host.";
|
|
||||||
case 10067: return "Too many processes.";
|
|
||||||
case 10091: return "Network subsystem is unavailable.";
|
|
||||||
case 10092: return "Winsock.dll version out of range.";
|
|
||||||
case 10093: return "Successful WSAStartup not yet performed.";
|
|
||||||
case 10101: return "Graceful shutdown in progress.";
|
|
||||||
case 10109: return "Class type not found.";
|
|
||||||
case 11001: return "Host not found.";
|
|
||||||
case 11002: return "Nonauthoritative host not found.";
|
|
||||||
case 11003: return "This is a nonrecoverable error.";
|
|
||||||
case 11004: return "Valid name, no data record of requested type.";
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
sprintf(tmp, "Winsock error code: %d", x);
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
@@ -1,218 +0,0 @@
|
|||||||
/** \file socket_include.h
|
|
||||||
** \date 2005-04-12
|
|
||||||
** \author grymse@alhem.net
|
|
||||||
**/
|
|
||||||
/*
|
|
||||||
Copyright (C) 2004,2005 Anders Hedstrom
|
|
||||||
|
|
||||||
This library is made available under the terms of the GNU GPL.
|
|
||||||
|
|
||||||
If you would like to use this library in a closed-source application,
|
|
||||||
a separate license agreement is available. For information about
|
|
||||||
the closed-source license agreement for the C++ sockets library,
|
|
||||||
please visit http://www.alhem.net/Sockets/license.html and/or
|
|
||||||
email license@alhem.net.
|
|
||||||
|
|
||||||
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 2
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
#ifndef _SOCKET_INCLUDE_H
|
|
||||||
#define _SOCKET_INCLUDE_H
|
|
||||||
|
|
||||||
#if (defined(__unix__) || defined(unix)) && !defined(USG)
|
|
||||||
#include <sys/param.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
// ----------------------------------------
|
|
||||||
// common unix includes / defines
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <netdb.h>
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
namespace SOCKETS_NAMESPACE {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define Errno errno
|
|
||||||
#define StrError strerror
|
|
||||||
|
|
||||||
// WIN32 adapt
|
|
||||||
#define closesocket close
|
|
||||||
#define INVALID_SOCKET -1
|
|
||||||
#define SOCKET_ERROR -1
|
|
||||||
typedef int SOCKET;
|
|
||||||
|
|
||||||
#ifndef INADDR_NONE
|
|
||||||
#define INADDR_NONE ((unsigned long) -1)
|
|
||||||
#endif // INADDR_NONE
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // !_WIN32
|
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------
|
|
||||||
// Generic
|
|
||||||
#ifndef SOL_IP
|
|
||||||
#define SOL_IP IPPROTO_IP
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------
|
|
||||||
// OS specific adaptions
|
|
||||||
|
|
||||||
#ifdef SOLARIS
|
|
||||||
// ----------------------------------------
|
|
||||||
// Solaris
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
namespace SOCKETS_NAMESPACE {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef unsigned short port_t;
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define s6_addr16 _S6_un._S6_u8
|
|
||||||
#define MSG_NOSIGNAL 0
|
|
||||||
|
|
||||||
#elif defined __FreeBSD__
|
|
||||||
// ----------------------------------------
|
|
||||||
// FreeBSD
|
|
||||||
# if __FreeBSD_version >= 400014
|
|
||||||
# define s6_addr16 __u6_addr.__u6_addr16
|
|
||||||
# if !defined(MSG_NOSIGNAL)
|
|
||||||
# define MSG_NOSIGNAL 0
|
|
||||||
# endif
|
|
||||||
# include <netinet/in.h>
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
namespace SOCKETS_NAMESPACE {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef in_addr_t ipaddr_t;
|
|
||||||
typedef in_port_t port_t;
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
# define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
|
|
||||||
# define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
|
|
||||||
# else
|
|
||||||
# error FreeBSD versions prior to 400014 does not support ipv6
|
|
||||||
# endif
|
|
||||||
|
|
||||||
#elif defined MACOSX
|
|
||||||
// ----------------------------------------
|
|
||||||
// Mac OS X
|
|
||||||
#include <string.h>
|
|
||||||
#include <mach/port.h>
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
namespace SOCKETS_NAMESPACE {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef unsigned long ipaddr_t;
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define s6_addr16 __u6_addr.__u6_addr16
|
|
||||||
#define MSG_NOSIGNAL 0 // oops - thanks Derek
|
|
||||||
#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
|
|
||||||
#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
|
|
||||||
|
|
||||||
#elif defined _WIN32
|
|
||||||
// ----------------------------------------
|
|
||||||
// Win32
|
|
||||||
#pragma comment(lib, "wsock32.lib")
|
|
||||||
#define strcasecmp _stricmp
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
namespace SOCKETS_NAMESPACE {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef unsigned long ipaddr_t;
|
|
||||||
typedef unsigned short port_t;
|
|
||||||
typedef int socklen_t;
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define MSG_NOSIGNAL 0
|
|
||||||
#define SHUT_RDWR 2
|
|
||||||
|
|
||||||
// 1.8.6: define FD_SETSIZE to something bigger than 64 if there are a lot of
|
|
||||||
// simultaneous connections (must be done before including winsock.h)
|
|
||||||
//#define FD_SETSIZE 1024
|
|
||||||
#include <winsock.h>
|
|
||||||
|
|
||||||
#define Errno WSAGetLastError()
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
namespace SOCKETS_NAMESPACE {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const char *StrError(int x);
|
|
||||||
|
|
||||||
// class WSAInitializer is a part of the Socket class (on win32)
|
|
||||||
// as a static instance - so whenever an application uses a Socket,
|
|
||||||
// winsock is initialized
|
|
||||||
class WSAInitializer // Winsock Initializer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
WSAInitializer() {
|
|
||||||
if (WSAStartup(0x101,&m_wsadata))
|
|
||||||
{
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
~WSAInitializer() {
|
|
||||||
WSACleanup();
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
WSADATA m_wsadata;
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#else
|
|
||||||
// ----------------------------------------
|
|
||||||
// LINUX
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
namespace SOCKETS_NAMESPACE {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef unsigned long ipaddr_t;
|
|
||||||
typedef unsigned short port_t;
|
|
||||||
#ifdef SOCKETS_NAMESPACE
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _THREADSAFE_SOCKETS
|
|
||||||
#include "Mutex.h"
|
|
||||||
#include "Lock.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // _SOCKET_INCLUDE_H
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,192 +0,0 @@
|
|||||||
/**********************************************************************
|
|
||||||
*
|
|
||||||
* StackWalker.h
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* History:
|
|
||||||
* 2005-07-27 v1 - First public release on http://www.codeproject.com/
|
|
||||||
* (for additional changes see History in 'StackWalker.cpp'!
|
|
||||||
* 2013-01-26 - Modified by KimLS(KLS) for EQEmu's purposes
|
|
||||||
*
|
|
||||||
**********************************************************************/
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
// #pragma once is supported starting with _MCS_VER 1000,
|
|
||||||
// so we need not to check the version (because we only support _MSC_VER >= 1100)!
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
// special defines for VC5/6 (if no actual PSDK is installed):
|
|
||||||
#if _MSC_VER < 1300
|
|
||||||
typedef unsigned __int64 DWORD64, *PDWORD64;
|
|
||||||
#if defined(_WIN64)
|
|
||||||
typedef unsigned __int64 SIZE_T, *PSIZE_T;
|
|
||||||
#else
|
|
||||||
typedef unsigned long SIZE_T, *PSIZE_T;
|
|
||||||
#endif
|
|
||||||
#endif // _MSC_VER < 1300
|
|
||||||
|
|
||||||
class StackWalkerInternal; // forward
|
|
||||||
class StackWalker
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef enum StackWalkOptions
|
|
||||||
{
|
|
||||||
// No addition info will be retrived
|
|
||||||
// (only the address is available)
|
|
||||||
RetrieveNone = 0,
|
|
||||||
|
|
||||||
// Try to get the symbol-name
|
|
||||||
RetrieveSymbol = 1,
|
|
||||||
|
|
||||||
// Try to get the line for this symbol
|
|
||||||
RetrieveLine = 2,
|
|
||||||
|
|
||||||
// Try to retrieve the module-infos
|
|
||||||
RetrieveModuleInfo = 4,
|
|
||||||
|
|
||||||
// Also retrieve the version for the DLL/EXE
|
|
||||||
RetrieveFileVersion = 8,
|
|
||||||
|
|
||||||
// Contains all the abouve
|
|
||||||
RetrieveVerbose = 0xF,
|
|
||||||
|
|
||||||
// Generate a "good" symbol-search-path
|
|
||||||
SymBuildPath = 0x10,
|
|
||||||
|
|
||||||
// Also use the public Microsoft-Symbol-Server
|
|
||||||
SymUseSymSrv = 0x20,
|
|
||||||
|
|
||||||
// Contains all the abouve "Sym"-options
|
|
||||||
SymAll = 0x30,
|
|
||||||
|
|
||||||
// Contains all options (default)
|
|
||||||
OptionsAll = 0x3F
|
|
||||||
} StackWalkOptions;
|
|
||||||
|
|
||||||
StackWalker(
|
|
||||||
int options = OptionsAll, // 'int' is by design, to combine the enum-flags
|
|
||||||
LPCSTR szSymPath = nullptr,
|
|
||||||
DWORD dwProcessId = GetCurrentProcessId(),
|
|
||||||
HANDLE hProcess = GetCurrentProcess()
|
|
||||||
);
|
|
||||||
StackWalker(DWORD dwProcessId, HANDLE hProcess);
|
|
||||||
virtual ~StackWalker();
|
|
||||||
|
|
||||||
typedef BOOL (__stdcall *PReadProcessMemoryRoutine)(
|
|
||||||
HANDLE hProcess,
|
|
||||||
DWORD64 qwBaseAddress,
|
|
||||||
PVOID lpBuffer,
|
|
||||||
DWORD nSize,
|
|
||||||
LPDWORD lpNumberOfBytesRead,
|
|
||||||
LPVOID pUserData // optional data, which was passed in "ShowCallstack"
|
|
||||||
);
|
|
||||||
|
|
||||||
BOOL LoadModules();
|
|
||||||
|
|
||||||
BOOL ShowCallstack(
|
|
||||||
HANDLE hThread = GetCurrentThread(),
|
|
||||||
const CONTEXT *context = nullptr,
|
|
||||||
PReadProcessMemoryRoutine readMemoryFunction = nullptr,
|
|
||||||
LPVOID pUserData = nullptr // optional to identify some data in the 'readMemoryFunction'-callback
|
|
||||||
);
|
|
||||||
|
|
||||||
#if _MSC_VER >= 1300
|
|
||||||
// due to some reasons, the "STACKWALK_MAX_NAMELEN" must be declared as "public"
|
|
||||||
// in older compilers in order to use it... starting with VC7 we can declare it as "protected"
|
|
||||||
protected:
|
|
||||||
#endif
|
|
||||||
enum { STACKWALK_MAX_NAMELEN = 1024 }; // max name length for found symbols
|
|
||||||
|
|
||||||
protected:
|
|
||||||
// Entry for each Callstack-Entry
|
|
||||||
typedef struct CallstackEntry
|
|
||||||
{
|
|
||||||
DWORD64 offset; // if 0, we have no valid entry
|
|
||||||
CHAR name[STACKWALK_MAX_NAMELEN];
|
|
||||||
CHAR undName[STACKWALK_MAX_NAMELEN];
|
|
||||||
CHAR undFullName[STACKWALK_MAX_NAMELEN];
|
|
||||||
DWORD64 offsetFromSmybol;
|
|
||||||
DWORD offsetFromLine;
|
|
||||||
DWORD lineNumber;
|
|
||||||
CHAR lineFileName[STACKWALK_MAX_NAMELEN];
|
|
||||||
DWORD symType;
|
|
||||||
LPCSTR symTypeString;
|
|
||||||
CHAR moduleName[STACKWALK_MAX_NAMELEN];
|
|
||||||
DWORD64 baseOfImage;
|
|
||||||
CHAR loadedImageName[STACKWALK_MAX_NAMELEN];
|
|
||||||
} CallstackEntry;
|
|
||||||
|
|
||||||
typedef 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);
|
|
||||||
virtual void OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry);
|
|
||||||
virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr);
|
|
||||||
virtual void OnOutput(LPCSTR szText);
|
|
||||||
|
|
||||||
StackWalkerInternal *m_sw;
|
|
||||||
HANDLE m_hProcess;
|
|
||||||
DWORD m_dwProcessId;
|
|
||||||
BOOL m_modulesLoaded;
|
|
||||||
LPSTR m_szSymPath;
|
|
||||||
|
|
||||||
int m_options;
|
|
||||||
|
|
||||||
static BOOL __stdcall myReadProcMem(HANDLE hProcess, DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead);
|
|
||||||
|
|
||||||
friend StackWalkerInternal;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// The "ugly" assembler-implementation is needed for systems before XP
|
|
||||||
// If you have a new PSDK and you only compile for XP and later, then you can use
|
|
||||||
// the "RtlCaptureContext"
|
|
||||||
// Currently there is no define which determines the PSDK-Version...
|
|
||||||
// So we just use the compiler-version (and assumes that the PSDK is
|
|
||||||
// the one which was installed by the VS-IDE)
|
|
||||||
|
|
||||||
// INFO: If you want, you can use the RtlCaptureContext if you only target XP and later...
|
|
||||||
// But I currently use it in x64/IA64 environments...
|
|
||||||
//#if defined(_M_IX86) && (_WIN32_WINNT <= 0x0500) && (_MSC_VER < 1400)
|
|
||||||
|
|
||||||
#if defined(_M_IX86)
|
|
||||||
#ifdef CURRENT_THREAD_VIA_EXCEPTION
|
|
||||||
// TODO: The following is not a "good" implementation,
|
|
||||||
// because the callstack is only valid in the "__except" block...
|
|
||||||
#define GET_CURRENT_CONTEXT(c, contextFlags) \
|
|
||||||
do { \
|
|
||||||
memset(&c, 0, sizeof(CONTEXT)); \
|
|
||||||
EXCEPTION_POINTERS *pExp = nullptr; \
|
|
||||||
__try { \
|
|
||||||
throw 0; \
|
|
||||||
} __except( ( (pExp = GetExceptionInformation()) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_EXECUTE_HANDLER)) {} \
|
|
||||||
if (pExp != nullptr) \
|
|
||||||
memcpy(&c, pExp->ContextRecord, sizeof(CONTEXT)); \
|
|
||||||
c.ContextFlags = contextFlags; \
|
|
||||||
} while(0);
|
|
||||||
#else
|
|
||||||
// The following should be enough for walking the callstack...
|
|
||||||
#define GET_CURRENT_CONTEXT(c, contextFlags) \
|
|
||||||
do { \
|
|
||||||
memset(&c, 0, sizeof(CONTEXT)); \
|
|
||||||
c.ContextFlags = contextFlags; \
|
|
||||||
__asm call x \
|
|
||||||
__asm x: pop eax \
|
|
||||||
__asm mov c.Eip, eax \
|
|
||||||
__asm mov c.Ebp, ebp \
|
|
||||||
__asm mov c.Esp, esp \
|
|
||||||
} while(0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
// The following is defined for x86 (XP and higher), x64 and IA64:
|
|
||||||
#define GET_CURRENT_CONTEXT(c, contextFlags) \
|
|
||||||
do { \
|
|
||||||
memset(&c, 0, sizeof(CONTEXT)); \
|
|
||||||
c.ContextFlags = contextFlags; \
|
|
||||||
RtlCaptureContext(&c); \
|
|
||||||
} while(0);
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
@@ -1,386 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2013 Facebook, Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "StringUtil.h"
|
|
||||||
|
|
||||||
#include <cstring> // for strncpy
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
#define snprintf _snprintf
|
|
||||||
#define strncasecmp _strnicmp
|
|
||||||
#define strcasecmp _stricmp
|
|
||||||
|
|
||||||
#else
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef va_copy
|
|
||||||
#define va_copy(d,s) ((d) = (s))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// original source:
|
|
||||||
// https://github.com/facebook/folly/blob/master/folly/String.cpp
|
|
||||||
//
|
|
||||||
void vStringFormat(std::string& output, const char* format, va_list args)
|
|
||||||
{
|
|
||||||
va_list tmpargs;
|
|
||||||
|
|
||||||
va_copy(tmpargs,args);
|
|
||||||
int characters_used = vsnprintf(nullptr, 0, format, tmpargs);
|
|
||||||
va_end(tmpargs);
|
|
||||||
|
|
||||||
if (characters_used < 0) {
|
|
||||||
// Looks like we have an invalid format string.
|
|
||||||
// error out.
|
|
||||||
std::string errorMessage("Invalid format string; snprintf returned negative with format string: ");
|
|
||||||
errorMessage.append(format);
|
|
||||||
|
|
||||||
throw std::runtime_error(errorMessage);
|
|
||||||
}
|
|
||||||
else if ((unsigned int)characters_used > output.capacity()) {
|
|
||||||
output.resize(characters_used+1);
|
|
||||||
va_copy(tmpargs,args);
|
|
||||||
characters_used = vsnprintf(&output[0], output.capacity(), format, tmpargs);
|
|
||||||
va_end(tmpargs);
|
|
||||||
|
|
||||||
if (characters_used < 0) {
|
|
||||||
// We shouldn't have a format error by this point, but I can't imagine what error we
|
|
||||||
// could have by this point. Still, error out and report it.
|
|
||||||
std::string errorMessage("Invalid format string or unknown vsnprintf error; vsnprintf returned negative with format string: ");
|
|
||||||
errorMessage.append(format);
|
|
||||||
|
|
||||||
throw std::runtime_error(errorMessage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
output.resize(characters_used + 1);
|
|
||||||
|
|
||||||
va_copy(tmpargs,args);
|
|
||||||
characters_used = vsnprintf(&output[0], output.capacity(), format, tmpargs);
|
|
||||||
va_end(tmpargs);
|
|
||||||
|
|
||||||
if (characters_used < 0) {
|
|
||||||
// We shouldn't have a format error by this point, but I can't imagine what error we
|
|
||||||
// could have by this point. still error out and report it.
|
|
||||||
std::string errorMessage("Invalid format string or unknown vsnprintf error; vsnprintf returned negative with format string: ");
|
|
||||||
errorMessage.append(format);
|
|
||||||
|
|
||||||
throw std::runtime_error(errorMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void StringFormat(std::string& output, const char* format, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
va_start(args, format);
|
|
||||||
vStringFormat(output,format,args);
|
|
||||||
va_end(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
// normal strncpy doesnt put a null term on copied strings, this one does
|
|
||||||
// ref: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcecrt/htm/_wcecrt_strncpy_wcsncpy.asp
|
|
||||||
char* strn0cpy(char* dest, const char* source, uint32 size) {
|
|
||||||
if (!dest)
|
|
||||||
return 0;
|
|
||||||
if (size == 0 || source == 0) {
|
|
||||||
dest[0] = 0;
|
|
||||||
return dest;
|
|
||||||
}
|
|
||||||
strncpy(dest, source, size);
|
|
||||||
dest[size - 1] = 0;
|
|
||||||
return dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
// String N w/null Copy Truncated?
|
|
||||||
// return value =true if entire string(source) fit, false if it was truncated
|
|
||||||
bool strn0cpyt(char* dest, const char* source, uint32 size) {
|
|
||||||
if (!dest)
|
|
||||||
return 0;
|
|
||||||
if (size == 0 || source == 0) {
|
|
||||||
dest[0] = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
strncpy(dest, source, size);
|
|
||||||
dest[size - 1] = 0;
|
|
||||||
return (bool) (source[strlen(dest)] == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *MakeLowerString(const char *source) {
|
|
||||||
static char str[128];
|
|
||||||
if (!source)
|
|
||||||
return nullptr;
|
|
||||||
MakeLowerString(source, str);
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MakeLowerString(const char *source, char *target) {
|
|
||||||
if (!source || !target) {
|
|
||||||
*target=0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
while (*source)
|
|
||||||
{
|
|
||||||
*target = tolower(*source);
|
|
||||||
target++;source++;
|
|
||||||
}
|
|
||||||
*target = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int MakeAnyLenString(char** ret, const char* format, ...) {
|
|
||||||
int buf_len = 128;
|
|
||||||
int chars = -1;
|
|
||||||
va_list argptr, tmpargptr;
|
|
||||||
va_start(argptr, format);
|
|
||||||
while (chars == -1 || chars >= buf_len) {
|
|
||||||
safe_delete_array(*ret);
|
|
||||||
if (chars == -1)
|
|
||||||
buf_len *= 2;
|
|
||||||
else
|
|
||||||
buf_len = chars + 1;
|
|
||||||
*ret = new char[buf_len];
|
|
||||||
va_copy(tmpargptr, argptr);
|
|
||||||
chars = vsnprintf(*ret, buf_len, format, tmpargptr);
|
|
||||||
}
|
|
||||||
va_end(argptr);
|
|
||||||
return chars;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 AppendAnyLenString(char** ret, uint32* bufsize, uint32* strlen, const char* format, ...) {
|
|
||||||
if (*bufsize == 0)
|
|
||||||
*bufsize = 256;
|
|
||||||
if (*ret == 0)
|
|
||||||
*strlen = 0;
|
|
||||||
int chars = -1;
|
|
||||||
char* oldret = 0;
|
|
||||||
va_list argptr, tmpargptr;
|
|
||||||
va_start(argptr, format);
|
|
||||||
while (chars == -1 || chars >= (int32)(*bufsize-*strlen)) {
|
|
||||||
if (chars == -1)
|
|
||||||
*bufsize += 256;
|
|
||||||
else
|
|
||||||
*bufsize += chars + 25;
|
|
||||||
oldret = *ret;
|
|
||||||
*ret = new char[*bufsize];
|
|
||||||
if (oldret) {
|
|
||||||
if (*strlen)
|
|
||||||
memcpy(*ret, oldret, *strlen);
|
|
||||||
safe_delete_array(oldret);
|
|
||||||
}
|
|
||||||
va_copy(tmpargptr, argptr);
|
|
||||||
chars = vsnprintf(&(*ret)[*strlen], (*bufsize-*strlen), format, tmpargptr);
|
|
||||||
}
|
|
||||||
va_end(argptr);
|
|
||||||
*strlen += chars;
|
|
||||||
return *strlen;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 hextoi(const char* num) {
|
|
||||||
if (num == nullptr)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
int len = strlen(num);
|
|
||||||
if (len < 3)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (num[0] != '0' || (num[1] != 'x' && num[1] != 'X'))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
uint32 ret = 0;
|
|
||||||
int mul = 1;
|
|
||||||
for (int i=len-1; i>=2; i--) {
|
|
||||||
if (num[i] >= 'A' && num[i] <= 'F')
|
|
||||||
ret += ((num[i] - 'A') + 10) * mul;
|
|
||||||
else if (num[i] >= 'a' && num[i] <= 'f')
|
|
||||||
ret += ((num[i] - 'a') + 10) * mul;
|
|
||||||
else if (num[i] >= '0' && num[i] <= '9')
|
|
||||||
ret += (num[i] - '0') * mul;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
mul *= 16;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64 hextoi64(const char* num) {
|
|
||||||
if (num == nullptr)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
int len = strlen(num);
|
|
||||||
if (len < 3)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (num[0] != '0' || (num[1] != 'x' && num[1] != 'X'))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
uint64 ret = 0;
|
|
||||||
int mul = 1;
|
|
||||||
for (int i=len-1; i>=2; i--) {
|
|
||||||
if (num[i] >= 'A' && num[i] <= 'F')
|
|
||||||
ret += ((num[i] - 'A') + 10) * mul;
|
|
||||||
else if (num[i] >= 'a' && num[i] <= 'f')
|
|
||||||
ret += ((num[i] - 'a') + 10) * mul;
|
|
||||||
else if (num[i] >= '0' && num[i] <= '9')
|
|
||||||
ret += (num[i] - '0') * mul;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
mul *= 16;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool atobool(const char* iBool) {
|
|
||||||
|
|
||||||
if (iBool == nullptr)
|
|
||||||
return false;
|
|
||||||
if (!strcasecmp(iBool, "true"))
|
|
||||||
return true;
|
|
||||||
if (!strcasecmp(iBool, "false"))
|
|
||||||
return false;
|
|
||||||
if (!strcasecmp(iBool, "yes"))
|
|
||||||
return true;
|
|
||||||
if (!strcasecmp(iBool, "no"))
|
|
||||||
return false;
|
|
||||||
if (!strcasecmp(iBool, "on"))
|
|
||||||
return true;
|
|
||||||
if (!strcasecmp(iBool, "off"))
|
|
||||||
return false;
|
|
||||||
if (!strcasecmp(iBool, "enable"))
|
|
||||||
return true;
|
|
||||||
if (!strcasecmp(iBool, "disable"))
|
|
||||||
return false;
|
|
||||||
if (!strcasecmp(iBool, "enabled"))
|
|
||||||
return true;
|
|
||||||
if (!strcasecmp(iBool, "disabled"))
|
|
||||||
return false;
|
|
||||||
if (!strcasecmp(iBool, "y"))
|
|
||||||
return true;
|
|
||||||
if (!strcasecmp(iBool, "n"))
|
|
||||||
return false;
|
|
||||||
if (atoi(iBool))
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// solar: removes the crap and turns the underscores into spaces.
|
|
||||||
char *CleanMobName(const char *in, char *out)
|
|
||||||
{
|
|
||||||
unsigned i, j;
|
|
||||||
|
|
||||||
for(i = j = 0; i < strlen(in); i++)
|
|
||||||
{
|
|
||||||
// convert _ to space.. any other conversions like this? I *think* this
|
|
||||||
// is the only non alpha char that's not stripped but converted.
|
|
||||||
if(in[i] == '_')
|
|
||||||
{
|
|
||||||
out[j++] = ' ';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(isalpha(in[i]) || (in[i] == '`')) // numbers, #, or any other crap just gets skipped
|
|
||||||
out[j++] = in[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out[j] = 0; // terimnate the string before returning it
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void RemoveApostrophes(std::string &s)
|
|
||||||
{
|
|
||||||
for(unsigned int i = 0; i < s.length(); ++i)
|
|
||||||
if(s[i] == '\'')
|
|
||||||
s[i] = '_';
|
|
||||||
}
|
|
||||||
|
|
||||||
char *RemoveApostrophes(const char *s)
|
|
||||||
{
|
|
||||||
char *NewString = new char[strlen(s) + 1];
|
|
||||||
|
|
||||||
strcpy(NewString, s);
|
|
||||||
|
|
||||||
for(unsigned int i = 0 ; i < strlen(NewString); ++i)
|
|
||||||
if(NewString[i] == '\'')
|
|
||||||
NewString[i] = '_';
|
|
||||||
|
|
||||||
return NewString;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *ConvertArray(int input, char *returnchar)
|
|
||||||
{
|
|
||||||
sprintf(returnchar, "%i" ,input);
|
|
||||||
return returnchar;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *ConvertArrayF(float input, char *returnchar)
|
|
||||||
{
|
|
||||||
sprintf(returnchar, "%0.2f", input);
|
|
||||||
return returnchar;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> SplitString(const std::string &str, char delim) {
|
|
||||||
std::vector<std::string> ret;
|
|
||||||
std::stringstream ss(str);
|
|
||||||
std::string item;
|
|
||||||
|
|
||||||
while(std::getline(ss, item, delim)) {
|
|
||||||
ret.push_back(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string EscapeString(const std::string &s) {
|
|
||||||
std::string ret;
|
|
||||||
|
|
||||||
size_t sz = s.length();
|
|
||||||
for(size_t i = 0; i < sz; ++i) {
|
|
||||||
char c = s[i];
|
|
||||||
switch(c) {
|
|
||||||
case '\x00':
|
|
||||||
ret += "\\x00";
|
|
||||||
break;
|
|
||||||
case '\n':
|
|
||||||
ret += "\\n";
|
|
||||||
break;
|
|
||||||
case '\r':
|
|
||||||
ret += "\\r";
|
|
||||||
break;
|
|
||||||
case '\\':
|
|
||||||
ret += "\\\\";
|
|
||||||
break;
|
|
||||||
case '\'':
|
|
||||||
ret += "\\'";
|
|
||||||
break;
|
|
||||||
case '\"':
|
|
||||||
ret += "\\\"";
|
|
||||||
break;
|
|
||||||
case '\x1a':
|
|
||||||
ret += "\\x1a";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ret.push_back(c);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2013 Facebook, Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
#ifndef _STRINGUTIL_H_
|
|
||||||
#define _STRINGUTIL_H_
|
|
||||||
|
|
||||||
#include <sstream>
|
|
||||||
#include <vector>
|
|
||||||
#include <cstdarg>
|
|
||||||
#include "types.h"
|
|
||||||
|
|
||||||
|
|
||||||
void vStringFormat(std::string& output, const char* format, va_list args);
|
|
||||||
void StringFormat(std::string& output, const char* format, ...);
|
|
||||||
std::string EscapeString(const std::string &s);
|
|
||||||
|
|
||||||
const char *MakeLowerString(const char *source);
|
|
||||||
|
|
||||||
void MakeLowerString(const char *source, char *target);
|
|
||||||
|
|
||||||
int MakeAnyLenString(char** ret, const char* format, ...);
|
|
||||||
uint32 AppendAnyLenString(char** ret, uint32* bufsize, uint32* strlen, const char* format, ...);
|
|
||||||
|
|
||||||
uint32 hextoi(const char* num);
|
|
||||||
uint64 hextoi64(const char* num);
|
|
||||||
bool atobool(const char* iBool);
|
|
||||||
|
|
||||||
char* strn0cpy(char* dest, const char* source, uint32 size);
|
|
||||||
// return value =true if entire string(source) fit, false if it was truncated
|
|
||||||
bool strn0cpyt(char* dest, const char* source, uint32 size);
|
|
||||||
|
|
||||||
char *CleanMobName(const char *in, char *out);
|
|
||||||
|
|
||||||
const char *ConvertArray(int input, char *returnchar);
|
|
||||||
const char *ConvertArrayF(float input, char *returnchar);
|
|
||||||
|
|
||||||
void RemoveApostrophes(std::string &s);
|
|
||||||
char *RemoveApostrophes(const char *s);
|
|
||||||
|
|
||||||
std::vector<std::string> SplitString(const std::string &s, char delim);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
|
|
||||||
#include "debug.h"
|
|
||||||
#include "StructStrategy.h"
|
|
||||||
#include "logsys.h"
|
|
||||||
#include "EQStream.h"
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
|
|
||||||
//note: all encoders and decoders must be valid functions.
|
|
||||||
//so if you specify set_defaults=false
|
|
||||||
StructStrategy::StructStrategy() {
|
|
||||||
int r;
|
|
||||||
for(r = 0; r < _maxEmuOpcode; r++) {
|
|
||||||
encoders[r] = PassEncoder;
|
|
||||||
decoders[r] = PassDecoder;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void StructStrategy::Encode(EQApplicationPacket **p, EQStream *dest, bool ack_req) const {
|
|
||||||
EmuOpcode op = (*p)->GetOpcode();
|
|
||||||
Encoder proc = encoders[op];
|
|
||||||
proc(p, dest, ack_req);
|
|
||||||
}
|
|
||||||
|
|
||||||
void StructStrategy::Decode(EQApplicationPacket *p) const {
|
|
||||||
EmuOpcode op = p->GetOpcode();
|
|
||||||
Decoder proc = decoders[op];
|
|
||||||
proc(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void StructStrategy::ErrorEncoder(EQApplicationPacket **in_p, EQStream *dest, bool ack_req) {
|
|
||||||
EQApplicationPacket *p = *in_p;
|
|
||||||
*in_p = nullptr;
|
|
||||||
|
|
||||||
_log(NET__STRUCTS, "Error encoding opcode %s: no encoder provided. Dropping.", OpcodeManager::EmuToName(p->GetOpcode()));
|
|
||||||
|
|
||||||
delete p;
|
|
||||||
}
|
|
||||||
|
|
||||||
void StructStrategy::ErrorDecoder(EQApplicationPacket *p) {
|
|
||||||
_log(NET__STRUCTS, "Error decoding opcode %s: no decoder provided. Invalidating.", OpcodeManager::EmuToName(p->GetOpcode()));
|
|
||||||
p->SetOpcode(OP_Unknown);
|
|
||||||
}
|
|
||||||
|
|
||||||
void StructStrategy::PassEncoder(EQApplicationPacket **p, EQStream *dest, bool ack_req) {
|
|
||||||
dest->FastQueuePacket(p, ack_req);
|
|
||||||
}
|
|
||||||
|
|
||||||
void StructStrategy::PassDecoder(EQApplicationPacket *p) {
|
|
||||||
//do nothing since we decode in place
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//effectively a singleton, but I decided to do it this way for no apparent reason.
|
|
||||||
namespace StructStrategyFactory {
|
|
||||||
|
|
||||||
static std::map<EmuOpcode, const StructStrategy *> strategies;
|
|
||||||
|
|
||||||
void RegisterPatch(EmuOpcode first_opcode, const StructStrategy *structs) {
|
|
||||||
strategies[first_opcode] = structs;
|
|
||||||
}
|
|
||||||
|
|
||||||
const StructStrategy *FindPatch(EmuOpcode first_opcode) {
|
|
||||||
std::map<EmuOpcode, const StructStrategy *>::const_iterator res;
|
|
||||||
res = strategies.find(first_opcode);
|
|
||||||
if(res == strategies.end())
|
|
||||||
return(nullptr);
|
|
||||||
return(res->second);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
#ifndef STRUCTSTRATEGY_H_
|
|
||||||
#define STRUCTSTRATEGY_H_
|
|
||||||
|
|
||||||
class EQApplicationPacket;
|
|
||||||
class EQStream;
|
|
||||||
#include "emu_opcodes.h"
|
|
||||||
#include "clientversions.h"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
class StructStrategy {
|
|
||||||
public:
|
|
||||||
//the encoder takes ownership of the supplied packet, and may enqueue multiple resulting packets into the stream
|
|
||||||
typedef void (*Encoder)(EQApplicationPacket **p, EQStream *dest, bool ack_req);
|
|
||||||
//the decoder may only edit the supplied packet, producing a single packet for eqemu to consume.
|
|
||||||
typedef void (*Decoder)(EQApplicationPacket *p);
|
|
||||||
|
|
||||||
StructStrategy();
|
|
||||||
virtual ~StructStrategy() {}
|
|
||||||
|
|
||||||
//this method takes an eqemu struct, and enqueues the produced structs into the stream.
|
|
||||||
void Encode(EQApplicationPacket **p, EQStream *dest, bool ack_req) const;
|
|
||||||
//this method takes an EQ wire struct, and converts it into an eqemu struct
|
|
||||||
void Decode(EQApplicationPacket *p) const;
|
|
||||||
|
|
||||||
virtual std::string Describe() const = 0;
|
|
||||||
virtual const EQClientVersion ClientVersion() const = 0;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
//some common coders:
|
|
||||||
//Print an error saying unknown struct/opcode and drop it
|
|
||||||
static void ErrorEncoder(EQApplicationPacket **p, EQStream *dest, bool ack_req);
|
|
||||||
static void ErrorDecoder(EQApplicationPacket *p);
|
|
||||||
//pass the packet through without modification (emu == EQ) (default)
|
|
||||||
static void PassEncoder(EQApplicationPacket **p, EQStream *dest, bool ack_req);
|
|
||||||
static void PassDecoder(EQApplicationPacket *p);
|
|
||||||
|
|
||||||
Encoder encoders[_maxEmuOpcode];
|
|
||||||
Decoder decoders[_maxEmuOpcode];
|
|
||||||
};
|
|
||||||
|
|
||||||
//effectively a singleton, but I decided to do it this way for no apparent reason.
|
|
||||||
namespace StructStrategyFactory {
|
|
||||||
void RegisterPatch(EmuOpcode first_opcode, const StructStrategy *structs);
|
|
||||||
|
|
||||||
//does NOT return ownership of the strategy.
|
|
||||||
const StructStrategy *FindPatch(EmuOpcode first_opcode);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif /*STRUCTSTRATEGY_H_*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
#ifndef TCPBASICSERVER_H_
|
|
||||||
#define TCPBASICSERVER_H_
|
|
||||||
|
|
||||||
#include "TCPServer.h"
|
|
||||||
#include "TCPConnection.h"
|
|
||||||
|
|
||||||
class TCPBasicServer : public TCPServer<TCPConnection> {
|
|
||||||
public:
|
|
||||||
inline TCPBasicServer(uint16 iPort = 0) : TCPServer<TCPConnection>(iPort) { }
|
|
||||||
inline virtual void CreateNewConnection(uint32 ID, SOCKET in_socket, uint32 irIP, uint16 irPort) {
|
|
||||||
TCPConnection *conn = new TCPConnection(ID, in_socket, irIP, irPort);
|
|
||||||
AddConnection(conn);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /*TCPBASICSERVER_H_*/
|
|
||||||
|
|
||||||
@@ -1,945 +0,0 @@
|
|||||||
/* EQEMu: Everquest Server Emulator
|
|
||||||
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
|
||||||
|
|
||||||
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; version 2 of the License.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
||||||
are required to give you total support for your newly bought product;
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
#include "../common/debug.h"
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <iomanip>
|
|
||||||
|
|
||||||
#include "TCPConnection.h"
|
|
||||||
#include "../common/servertalk.h"
|
|
||||||
#include "../common/timer.h"
|
|
||||||
#include "../common/packet_dump.h"
|
|
||||||
|
|
||||||
#ifdef FREEBSD //Timothy Whitman - January 7, 2003
|
|
||||||
#define MSG_NOSIGNAL 0
|
|
||||||
#endif
|
|
||||||
#ifdef DARWIN
|
|
||||||
#define MSG_NOSIGNAL SO_NOSIGPIPE // Corysia Taware - Sept. 27, 2013
|
|
||||||
// See http://lists.apple.com/archives/macnetworkprog/2002/Dec/msg00091.html
|
|
||||||
#endif // DARWIN
|
|
||||||
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
InitWinsock winsock;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define LOOP_GRANULARITY 3 //# of ms between checking our socket/queues
|
|
||||||
|
|
||||||
#define TCPN_DEBUG 0
|
|
||||||
#define TCPN_DEBUG_Console 0
|
|
||||||
#define TCPN_DEBUG_Memory 0
|
|
||||||
#define TCPN_LOG_RAW_DATA_OUT 0 //1 = info, 2 = length limited dump, 3 = full dump
|
|
||||||
#define TCPN_LOG_RAW_DATA_IN 0 //1 = info, 2 = length limited dump, 3 = full dump
|
|
||||||
|
|
||||||
//client version
|
|
||||||
TCPConnection::TCPConnection()
|
|
||||||
: ConnectionType(Outgoing),
|
|
||||||
connection_socket(0),
|
|
||||||
id(0),
|
|
||||||
rIP(0),
|
|
||||||
rPort(0)
|
|
||||||
{
|
|
||||||
pState = TCPS_Ready;
|
|
||||||
pFree = false;
|
|
||||||
pEcho = false;
|
|
||||||
recvbuf = nullptr;
|
|
||||||
sendbuf = nullptr;
|
|
||||||
pRunLoop = false;
|
|
||||||
charAsyncConnect = 0;
|
|
||||||
pAsyncConnect = false;
|
|
||||||
m_previousLineEnd = false;
|
|
||||||
#if TCPN_DEBUG_Memory >= 7
|
|
||||||
std::cout << "Constructor #2 on outgoing TCP# " << GetID() << std::endl;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
//server version
|
|
||||||
TCPConnection::TCPConnection(uint32 ID, SOCKET in_socket, uint32 irIP, uint16 irPort)
|
|
||||||
: ConnectionType(Incomming),
|
|
||||||
connection_socket(in_socket),
|
|
||||||
id(ID),
|
|
||||||
rIP(irIP),
|
|
||||||
rPort(irPort)
|
|
||||||
{
|
|
||||||
pState = TCPS_Connected;
|
|
||||||
pFree = false;
|
|
||||||
pEcho = false;
|
|
||||||
recvbuf = nullptr;
|
|
||||||
sendbuf = nullptr;
|
|
||||||
pRunLoop = false;
|
|
||||||
charAsyncConnect = 0;
|
|
||||||
pAsyncConnect = false;
|
|
||||||
m_previousLineEnd = false;
|
|
||||||
#if TCPN_DEBUG_Memory >= 7
|
|
||||||
std::cout << "Constructor #2 on incoming TCP# " << GetID() << std::endl;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
TCPConnection::~TCPConnection() {
|
|
||||||
FinishDisconnect();
|
|
||||||
ClearBuffers();
|
|
||||||
if (ConnectionType == Outgoing) {
|
|
||||||
MRunLoop.lock();
|
|
||||||
pRunLoop = false;
|
|
||||||
MRunLoop.unlock();
|
|
||||||
MLoopRunning.lock();
|
|
||||||
MLoopRunning.unlock();
|
|
||||||
#if TCPN_DEBUG_Memory >= 6
|
|
||||||
std::cout << "Deconstructor on outgoing TCP# " << GetID() << std::endl;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#if TCPN_DEBUG_Memory >= 5
|
|
||||||
else {
|
|
||||||
std::cout << "Deconstructor on incomming TCP# " << GetID() << std::endl;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
safe_delete_array(recvbuf);
|
|
||||||
safe_delete_array(sendbuf);
|
|
||||||
safe_delete_array(charAsyncConnect);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TCPConnection::SetState(State_t in_state) {
|
|
||||||
MState.lock();
|
|
||||||
pState = in_state;
|
|
||||||
MState.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
TCPConnection::State_t TCPConnection::GetState() const {
|
|
||||||
State_t ret;
|
|
||||||
MState.lock();
|
|
||||||
ret = pState;
|
|
||||||
MState.unlock();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TCPConnection::GetSockName(char *host, uint16 *port)
|
|
||||||
{
|
|
||||||
bool result=false;
|
|
||||||
LockMutex lock(&MState);
|
|
||||||
if (!Connected())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
struct sockaddr_in local;
|
|
||||||
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
int addrlen;
|
|
||||||
#else
|
|
||||||
#ifdef FREEBSD
|
|
||||||
socklen_t addrlen;
|
|
||||||
#else
|
|
||||||
size_t addrlen;
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
addrlen=sizeof(struct sockaddr_in);
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
if (!getsockname(connection_socket,(struct sockaddr *)&local,&addrlen)) {
|
|
||||||
#else
|
|
||||||
if (!getsockname(connection_socket,(struct sockaddr *)&local,(socklen_t *)&addrlen)) {
|
|
||||||
#endif
|
|
||||||
unsigned long ip=local.sin_addr.s_addr;
|
|
||||||
sprintf(host,"%d.%d.%d.%d",
|
|
||||||
*(unsigned char *)&ip,
|
|
||||||
*((unsigned char *)&ip+1),
|
|
||||||
*((unsigned char *)&ip+2),
|
|
||||||
*((unsigned char *)&ip+3));
|
|
||||||
*port=ntohs(local.sin_port);
|
|
||||||
|
|
||||||
result=true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TCPConnection::Free() {
|
|
||||||
Disconnect();
|
|
||||||
pFree = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TCPConnection::Send(const uchar* data, int32 size) {
|
|
||||||
if (!Connected())
|
|
||||||
return false;
|
|
||||||
if (!size)
|
|
||||||
return true;
|
|
||||||
ServerSendQueuePushEnd(data, size);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TCPConnection::ServerSendQueuePushEnd(const uchar* data, int32 size) {
|
|
||||||
MSendQueue.lock();
|
|
||||||
if (sendbuf == nullptr) {
|
|
||||||
sendbuf = new uchar[size];
|
|
||||||
sendbuf_size = size;
|
|
||||||
sendbuf_used = 0;
|
|
||||||
}
|
|
||||||
else if (size > (sendbuf_size - sendbuf_used)) {
|
|
||||||
sendbuf_size += size + 1024;
|
|
||||||
uchar* tmp = new uchar[sendbuf_size];
|
|
||||||
memcpy(tmp, sendbuf, sendbuf_used);
|
|
||||||
safe_delete_array(sendbuf);
|
|
||||||
sendbuf = tmp;
|
|
||||||
}
|
|
||||||
memcpy(&sendbuf[sendbuf_used], data, size);
|
|
||||||
sendbuf_used += size;
|
|
||||||
MSendQueue.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TCPConnection::ServerSendQueuePushEnd(uchar** data, int32 size) {
|
|
||||||
MSendQueue.lock();
|
|
||||||
if (sendbuf == 0) {
|
|
||||||
sendbuf = *data;
|
|
||||||
sendbuf_size = size;
|
|
||||||
sendbuf_used = size;
|
|
||||||
MSendQueue.unlock();
|
|
||||||
*data = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (size > (sendbuf_size - sendbuf_used)) {
|
|
||||||
sendbuf_size += size;
|
|
||||||
uchar* tmp = new uchar[sendbuf_size];
|
|
||||||
memcpy(tmp, sendbuf, sendbuf_used);
|
|
||||||
safe_delete_array(sendbuf);
|
|
||||||
sendbuf = tmp;
|
|
||||||
}
|
|
||||||
memcpy(&sendbuf[sendbuf_used], *data, size);
|
|
||||||
sendbuf_used += size;
|
|
||||||
MSendQueue.unlock();
|
|
||||||
safe_delete_array(*data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TCPConnection::ServerSendQueuePushFront(uchar* data, int32 size) {
|
|
||||||
MSendQueue.lock();
|
|
||||||
if (sendbuf == 0) {
|
|
||||||
sendbuf = new uchar[size];
|
|
||||||
sendbuf_size = size;
|
|
||||||
sendbuf_used = 0;
|
|
||||||
}
|
|
||||||
else if (size > (sendbuf_size - sendbuf_used)) {
|
|
||||||
sendbuf_size += size;
|
|
||||||
uchar* tmp = new uchar[sendbuf_size];
|
|
||||||
memcpy(&tmp[size], sendbuf, sendbuf_used);
|
|
||||||
safe_delete_array(sendbuf);
|
|
||||||
sendbuf = tmp;
|
|
||||||
}
|
|
||||||
memcpy(sendbuf, data, size);
|
|
||||||
sendbuf_used += size;
|
|
||||||
MSendQueue.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TCPConnection::ServerSendQueuePop(uchar** data, int32* size) {
|
|
||||||
bool ret;
|
|
||||||
if (!MSendQueue.trylock())
|
|
||||||
return false;
|
|
||||||
if (sendbuf) {
|
|
||||||
*data = sendbuf;
|
|
||||||
*size = sendbuf_used;
|
|
||||||
sendbuf = 0;
|
|
||||||
ret = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ret = false;
|
|
||||||
}
|
|
||||||
MSendQueue.unlock();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TCPConnection::ServerSendQueuePopForce(uchar** data, int32* size) {
|
|
||||||
bool ret;
|
|
||||||
MSendQueue.lock();
|
|
||||||
if (sendbuf) {
|
|
||||||
*data = sendbuf;
|
|
||||||
*size = sendbuf_used;
|
|
||||||
sendbuf = 0;
|
|
||||||
ret = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ret = false;
|
|
||||||
}
|
|
||||||
MSendQueue.unlock();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* TCPConnection::PopLine() {
|
|
||||||
char* ret;
|
|
||||||
if (!MLineOutQueue.trylock())
|
|
||||||
return 0;
|
|
||||||
ret = (char*) LineOutQueue.pop();
|
|
||||||
MLineOutQueue.unlock();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TCPConnection::LineOutQueuePush(char* line) {
|
|
||||||
MLineOutQueue.lock();
|
|
||||||
LineOutQueue.push(line);
|
|
||||||
MLineOutQueue.unlock();
|
|
||||||
return(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void TCPConnection::FinishDisconnect() {
|
|
||||||
MState.lock();
|
|
||||||
if (connection_socket != INVALID_SOCKET && connection_socket != 0) {
|
|
||||||
if (pState == TCPS_Connected || pState == TCPS_Disconnecting || pState == TCPS_Disconnected) {
|
|
||||||
bool sent_something = false;
|
|
||||||
SendData(sent_something);
|
|
||||||
}
|
|
||||||
pState = TCPS_Closing;
|
|
||||||
shutdown(connection_socket, 0x01);
|
|
||||||
shutdown(connection_socket, 0x00);
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
closesocket(connection_socket);
|
|
||||||
#else
|
|
||||||
close(connection_socket);
|
|
||||||
#endif
|
|
||||||
connection_socket = 0;
|
|
||||||
rIP = 0;
|
|
||||||
rPort = 0;
|
|
||||||
ClearBuffers();
|
|
||||||
}
|
|
||||||
pState = TCPS_Disconnected;
|
|
||||||
MState.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TCPConnection::Disconnect() {
|
|
||||||
MState.lock();
|
|
||||||
if(pState == TCPS_Connected || pState == TCPS_Connecting) {
|
|
||||||
pState = TCPS_Disconnecting;
|
|
||||||
}
|
|
||||||
MState.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TCPConnection::GetAsyncConnect() {
|
|
||||||
bool ret;
|
|
||||||
MAsyncConnect.lock();
|
|
||||||
ret = pAsyncConnect;
|
|
||||||
MAsyncConnect.unlock();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TCPConnection::SetAsyncConnect(bool iValue) {
|
|
||||||
bool ret;
|
|
||||||
MAsyncConnect.lock();
|
|
||||||
ret = pAsyncConnect;
|
|
||||||
pAsyncConnect = iValue;
|
|
||||||
MAsyncConnect.unlock();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TCPConnection::ConnectReady() const {
|
|
||||||
State_t s = GetState();
|
|
||||||
if (s != TCPS_Ready && s != TCPS_Disconnected)
|
|
||||||
return(false);
|
|
||||||
return(ConnectionType == Outgoing);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TCPConnection::AsyncConnect(const char* irAddress, uint16 irPort) {
|
|
||||||
safe_delete_array(charAsyncConnect);
|
|
||||||
charAsyncConnect = new char[strlen(irAddress) + 1];
|
|
||||||
strcpy(charAsyncConnect, irAddress);
|
|
||||||
AsyncConnect((uint32) 0, irPort);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TCPConnection::AsyncConnect(uint32 irIP, uint16 irPort) {
|
|
||||||
if (ConnectionType != Outgoing) {
|
|
||||||
// If this code runs, we got serious problems
|
|
||||||
// Crash and burn.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(!ConnectReady()) {
|
|
||||||
#if TCPN_DEBUG > 0
|
|
||||||
printf("Trying to do async connect in invalid state %s\n", GetState());
|
|
||||||
#endif
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
MAsyncConnect.lock();
|
|
||||||
if (pAsyncConnect) {
|
|
||||||
MAsyncConnect.unlock();
|
|
||||||
#if TCPN_DEBUG > 0
|
|
||||||
printf("Trying to do async connect when already doing one.\n");
|
|
||||||
#endif
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#if TCPN_DEBUG > 0
|
|
||||||
printf("Start async connect.\n");
|
|
||||||
#endif
|
|
||||||
pAsyncConnect = true;
|
|
||||||
if(irIP != 0)
|
|
||||||
safe_delete_array(charAsyncConnect);
|
|
||||||
rIP = irIP;
|
|
||||||
rPort = irPort;
|
|
||||||
MAsyncConnect.unlock();
|
|
||||||
if (!pRunLoop) {
|
|
||||||
pRunLoop = true;
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
_beginthread(TCPConnectionLoop, 0, this);
|
|
||||||
#else
|
|
||||||
pthread_t thread;
|
|
||||||
pthread_create(&thread, nullptr, TCPConnectionLoop, this);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TCPConnection::Connect(const char* irAddress, uint16 irPort, char* errbuf) {
|
|
||||||
if (errbuf)
|
|
||||||
errbuf[0] = 0;
|
|
||||||
uint32 tmpIP = ResolveIP(irAddress);
|
|
||||||
if (!tmpIP) {
|
|
||||||
if (errbuf) {
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): Couldnt resolve hostname. Error: %i", WSAGetLastError());
|
|
||||||
#else
|
|
||||||
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): Couldnt resolve hostname. Error #%i: %s", errno, strerror(errno));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return ConnectIP(tmpIP, irPort, errbuf);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TCPConnection::ConnectIP(uint32 in_ip, uint16 in_port, char* errbuf) {
|
|
||||||
if (errbuf)
|
|
||||||
errbuf[0] = 0;
|
|
||||||
if (ConnectionType != Outgoing) {
|
|
||||||
// If this code runs, we got serious problems
|
|
||||||
// Crash and burn.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
MState.lock();
|
|
||||||
if (ConnectReady()) {
|
|
||||||
pState = TCPS_Connecting;
|
|
||||||
} else {
|
|
||||||
MState.unlock();
|
|
||||||
SetAsyncConnect(false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
MState.unlock();
|
|
||||||
if (!pRunLoop) {
|
|
||||||
pRunLoop = true;
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
_beginthread(TCPConnectionLoop, 0, this);
|
|
||||||
#else
|
|
||||||
pthread_t thread;
|
|
||||||
pthread_create(&thread, nullptr, TCPConnectionLoop, this);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
connection_socket = INVALID_SOCKET;
|
|
||||||
struct sockaddr_in server_sin;
|
|
||||||
//struct in_addr in;
|
|
||||||
|
|
||||||
if ((connection_socket = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET || connection_socket == 0) {
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
if (errbuf)
|
|
||||||
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): Allocating socket failed. Error: %i", WSAGetLastError());
|
|
||||||
#else
|
|
||||||
if (errbuf)
|
|
||||||
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): Allocating socket failed. Error: %s", strerror(errno));
|
|
||||||
#endif
|
|
||||||
SetState(TCPS_Ready);
|
|
||||||
SetAsyncConnect(false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
server_sin.sin_family = AF_INET;
|
|
||||||
server_sin.sin_addr.s_addr = in_ip;
|
|
||||||
server_sin.sin_port = htons(in_port);
|
|
||||||
|
|
||||||
// Establish a connection to the server socket.
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
if (connect(connection_socket, (PSOCKADDR) &server_sin, sizeof (server_sin)) == SOCKET_ERROR) {
|
|
||||||
if (errbuf)
|
|
||||||
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): connect() failed. Error: %i", WSAGetLastError());
|
|
||||||
closesocket(connection_socket);
|
|
||||||
connection_socket = 0;
|
|
||||||
SetState(TCPS_Ready);
|
|
||||||
SetAsyncConnect(false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (connect(connection_socket, (struct sockaddr *) &server_sin, sizeof (server_sin)) == SOCKET_ERROR) {
|
|
||||||
if (errbuf)
|
|
||||||
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): connect() failed. Error: %s", strerror(errno));
|
|
||||||
close(connection_socket);
|
|
||||||
connection_socket = 0;
|
|
||||||
SetState(TCPS_Ready);
|
|
||||||
SetAsyncConnect(false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
int bufsize = 64 * 1024; // 64kbyte recieve buffer, up from default of 8k
|
|
||||||
setsockopt(connection_socket, SOL_SOCKET, SO_RCVBUF, (char*) &bufsize, sizeof(bufsize));
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
unsigned long nonblocking = 1;
|
|
||||||
ioctlsocket(connection_socket, FIONBIO, &nonblocking);
|
|
||||||
#else
|
|
||||||
fcntl(connection_socket, F_SETFL, O_NONBLOCK);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
SetEcho(false);
|
|
||||||
ClearBuffers();
|
|
||||||
|
|
||||||
rIP = in_ip;
|
|
||||||
rPort = in_port;
|
|
||||||
SetState(TCPS_Connected);
|
|
||||||
SetAsyncConnect(false);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TCPConnection::ClearBuffers() {
|
|
||||||
LockMutex lock1(&MSendQueue);
|
|
||||||
LockMutex lock3(&MRunLoop);
|
|
||||||
LockMutex lock4(&MState);
|
|
||||||
safe_delete_array(recvbuf);
|
|
||||||
safe_delete_array(sendbuf);
|
|
||||||
|
|
||||||
char* line = 0;
|
|
||||||
while ((line = LineOutQueue.pop()))
|
|
||||||
safe_delete_array(line);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TCPConnection::CheckNetActive() {
|
|
||||||
MState.lock();
|
|
||||||
if (pState == TCPS_Connected || pState == TCPS_Disconnecting) {
|
|
||||||
MState.unlock();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
MState.unlock();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This is always called from an IO thread. Either the server socket's thread, or a
|
|
||||||
* special thread we create when we make an outbound connection. */
|
|
||||||
bool TCPConnection::Process() {
|
|
||||||
char errbuf[TCPConnection_ErrorBufferSize];
|
|
||||||
switch(GetState()) {
|
|
||||||
case TCPS_Ready:
|
|
||||||
case TCPS_Connecting:
|
|
||||||
if (ConnectionType == Outgoing) {
|
|
||||||
if (GetAsyncConnect()) {
|
|
||||||
if (charAsyncConnect)
|
|
||||||
rIP = ResolveIP(charAsyncConnect);
|
|
||||||
ConnectIP(rIP, rPort);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return(true);
|
|
||||||
|
|
||||||
case TCPS_Connected:
|
|
||||||
// only receive data in the connected state, no others...
|
|
||||||
if (!RecvData(errbuf)) {
|
|
||||||
struct in_addr in;
|
|
||||||
in.s_addr = GetrIP();
|
|
||||||
//std::cout << inet_ntoa(in) << ":" << GetrPort() << ": " << errbuf << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
/* we break to do the send */
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TCPS_Disconnecting: {
|
|
||||||
//waiting for any sending data to go out...
|
|
||||||
MSendQueue.lock();
|
|
||||||
if(sendbuf) {
|
|
||||||
if(sendbuf_used > 0) {
|
|
||||||
//something left to send, keep processing...
|
|
||||||
MSendQueue.unlock();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
//else, send buffer is empty.
|
|
||||||
safe_delete_array(sendbuf);
|
|
||||||
} //else, no send buffer, we are done.
|
|
||||||
MSendQueue.unlock();
|
|
||||||
}
|
|
||||||
/* Fallthrough */
|
|
||||||
|
|
||||||
case TCPS_Disconnected:
|
|
||||||
FinishDisconnect();
|
|
||||||
MRunLoop.lock();
|
|
||||||
pRunLoop = false;
|
|
||||||
MRunLoop.unlock();
|
|
||||||
// SetState(TCPS_Ready); //reset the state in case they want to use it again...
|
|
||||||
return(false);
|
|
||||||
|
|
||||||
case TCPS_Closing:
|
|
||||||
//I dont understand this state...
|
|
||||||
|
|
||||||
case TCPS_Error:
|
|
||||||
MRunLoop.lock();
|
|
||||||
pRunLoop = false;
|
|
||||||
MRunLoop.unlock();
|
|
||||||
return(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* we get here in connected or disconnecting with more data to send */
|
|
||||||
|
|
||||||
bool sent_something = false;
|
|
||||||
if (!SendData(sent_something, errbuf)) {
|
|
||||||
struct in_addr in;
|
|
||||||
in.s_addr = GetrIP();
|
|
||||||
std::cout << inet_ntoa(in) << ":" << GetrPort() << ": " << errbuf << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TCPConnection::RecvData(char* errbuf) {
|
|
||||||
if (errbuf)
|
|
||||||
errbuf[0] = 0;
|
|
||||||
if (!Connected()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int status = 0;
|
|
||||||
if (recvbuf == 0) {
|
|
||||||
recvbuf = new uchar[5120];
|
|
||||||
recvbuf_size = 5120;
|
|
||||||
recvbuf_used = 0;
|
|
||||||
recvbuf_echo = 0;
|
|
||||||
}
|
|
||||||
else if ((recvbuf_size - recvbuf_used) < 2048) {
|
|
||||||
uchar* tmpbuf = new uchar[recvbuf_size + 5120];
|
|
||||||
memcpy(tmpbuf, recvbuf, recvbuf_used);
|
|
||||||
recvbuf_size += 5120;
|
|
||||||
safe_delete_array(recvbuf);
|
|
||||||
recvbuf = tmpbuf;
|
|
||||||
if (recvbuf_size >= MaxTCPReceiveBuffferSize) {
|
|
||||||
if (errbuf)
|
|
||||||
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::RecvData(): recvbuf_size >= MaxTCPReceiveBuffferSize");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
status = recv(connection_socket, (char *) &recvbuf[recvbuf_used], (recvbuf_size - recvbuf_used), 0);
|
|
||||||
|
|
||||||
if (status >= 1) {
|
|
||||||
#if TCPN_LOG_RAW_DATA_IN >= 1
|
|
||||||
struct in_addr in;
|
|
||||||
in.s_addr = GetrIP();
|
|
||||||
CoutTimestamp(true);
|
|
||||||
std::cout << ": Read " << status << " bytes from network. (recvbuf_used = " << recvbuf_used << ") " << inet_ntoa(in) << ":" << GetrPort();
|
|
||||||
std::cout << std::endl;
|
|
||||||
#if TCPN_LOG_RAW_DATA_IN == 2
|
|
||||||
int32 tmp = status;
|
|
||||||
if (tmp > 32)
|
|
||||||
tmp = 32;
|
|
||||||
DumpPacket(&recvbuf[recvbuf_used], status);
|
|
||||||
#elif TCPN_LOG_RAW_DATA_IN >= 3
|
|
||||||
DumpPacket(&recvbuf[recvbuf_used], status);
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
recvbuf_used += status;
|
|
||||||
if (!ProcessReceivedData(errbuf))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if (status == SOCKET_ERROR) {
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
if (!(WSAGetLastError() == WSAEWOULDBLOCK)) {
|
|
||||||
if (errbuf)
|
|
||||||
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::RecvData(): Error: %i", WSAGetLastError());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (!(errno == EWOULDBLOCK)) {
|
|
||||||
if (errbuf)
|
|
||||||
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::RecvData(): Error: %s", strerror(errno));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
} else if (status == 0) {
|
|
||||||
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::RecvData(): Connection closed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool TCPConnection::GetEcho() {
|
|
||||||
bool ret;
|
|
||||||
ret = pEcho;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TCPConnection::SetEcho(bool iValue) {
|
|
||||||
pEcho = iValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TCPConnection::ProcessReceivedData(char* errbuf) {
|
|
||||||
if (errbuf)
|
|
||||||
errbuf[0] = 0;
|
|
||||||
if (!recvbuf)
|
|
||||||
return true;
|
|
||||||
#if TCPN_DEBUG_Console >= 4
|
|
||||||
if (recvbuf_used) {
|
|
||||||
std::cout << "Starting Processing: recvbuf=" << recvbuf_used << std::endl;
|
|
||||||
DumpPacket(recvbuf, recvbuf_used);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
for (int i=0; i < recvbuf_used; i++) {
|
|
||||||
if (GetEcho() && i >= recvbuf_echo) {
|
|
||||||
Send(&recvbuf[i], 1);
|
|
||||||
recvbuf_echo = i + 1;
|
|
||||||
}
|
|
||||||
switch(recvbuf[i]) {
|
|
||||||
case 0: { // 0 is the code for clear buffer
|
|
||||||
if (i==0) {
|
|
||||||
recvbuf_used--;
|
|
||||||
recvbuf_echo--;
|
|
||||||
memmove(recvbuf, &recvbuf[1], recvbuf_used);
|
|
||||||
i = -1;
|
|
||||||
} else {
|
|
||||||
if (i == recvbuf_used) {
|
|
||||||
safe_delete_array(recvbuf);
|
|
||||||
i = -1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
uchar* tmpdel = recvbuf;
|
|
||||||
recvbuf = new uchar[recvbuf_size];
|
|
||||||
memcpy(recvbuf, &tmpdel[i+1], recvbuf_used-i);
|
|
||||||
recvbuf_used -= i + 1;
|
|
||||||
recvbuf_echo -= i + 1;
|
|
||||||
safe_delete_array(tmpdel);
|
|
||||||
i = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#if TCPN_DEBUG_Console >= 5
|
|
||||||
std::cout << "Removed 0x00" << std::endl;
|
|
||||||
if (recvbuf_used) {
|
|
||||||
std::cout << "recvbuf left: " << recvbuf_used << std::endl;
|
|
||||||
DumpPacket(recvbuf, recvbuf_used);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
std::cout << "recbuf left: None" << std::endl;
|
|
||||||
#endif
|
|
||||||
m_previousLineEnd = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 10:
|
|
||||||
case 13: // newline marker
|
|
||||||
{
|
|
||||||
char *line = nullptr;
|
|
||||||
if (i==0) { // empty line
|
|
||||||
if(!m_previousLineEnd) {
|
|
||||||
//char right before this was NOT a CR, report the empty line.
|
|
||||||
line = new char[1];
|
|
||||||
line[0] = '\0';
|
|
||||||
m_previousLineEnd = true;
|
|
||||||
} else {
|
|
||||||
m_previousLineEnd = false;
|
|
||||||
}
|
|
||||||
recvbuf_used--;
|
|
||||||
recvbuf_echo--;
|
|
||||||
memcpy(recvbuf, &recvbuf[1], recvbuf_used);
|
|
||||||
i = -1;
|
|
||||||
} else {
|
|
||||||
line = new char[i+1];
|
|
||||||
memset(line, 0, i+1);
|
|
||||||
memcpy(line, recvbuf, i);
|
|
||||||
#if TCPN_DEBUG_Console >= 3
|
|
||||||
std::cout << "Line Out: " << std::endl;
|
|
||||||
DumpPacket((uchar*) line, i);
|
|
||||||
#endif
|
|
||||||
//line[i] = 0;
|
|
||||||
uchar* tmpdel = recvbuf;
|
|
||||||
recvbuf = new uchar[recvbuf_size];
|
|
||||||
recvbuf_used -= i+1;
|
|
||||||
recvbuf_echo -= i+1;
|
|
||||||
memcpy(recvbuf, &tmpdel[i+1], recvbuf_used);
|
|
||||||
#if TCPN_DEBUG_Console >= 5
|
|
||||||
std::cout << "i+1=" << i+1 << std::endl;
|
|
||||||
if (recvbuf_used) {
|
|
||||||
std::cout << "recvbuf left: " << recvbuf_used << std::endl;
|
|
||||||
DumpPacket(recvbuf, recvbuf_used);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
std::cout << "recbuf left: None" << std::endl;
|
|
||||||
#endif
|
|
||||||
safe_delete_array(tmpdel);
|
|
||||||
i = -1;
|
|
||||||
m_previousLineEnd = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if(line != nullptr) {
|
|
||||||
bool finish_proc = false;
|
|
||||||
finish_proc = LineOutQueuePush(line);
|
|
||||||
if(finish_proc)
|
|
||||||
return(true); //break early as requested by LineOutQueuePush
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 8: // backspace
|
|
||||||
{
|
|
||||||
if (i==0) { // nothin to backspace
|
|
||||||
recvbuf_used--;
|
|
||||||
recvbuf_echo--;
|
|
||||||
memmove(recvbuf, &recvbuf[1], recvbuf_used);
|
|
||||||
i = -1;
|
|
||||||
} else {
|
|
||||||
uchar* tmpdel = recvbuf;
|
|
||||||
recvbuf = new uchar[recvbuf_size];
|
|
||||||
memcpy(recvbuf, tmpdel, i-1);
|
|
||||||
memcpy(&recvbuf[i-1], &tmpdel[i+1], recvbuf_used-i);
|
|
||||||
recvbuf_used -= 2;
|
|
||||||
recvbuf_echo -= 2;
|
|
||||||
safe_delete_array(tmpdel);
|
|
||||||
i -= 2;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
m_previousLineEnd = false;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
m_previousLineEnd = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (recvbuf_used < 0)
|
|
||||||
safe_delete_array(recvbuf);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TCPConnection::SendData(bool &sent_something, char* errbuf) {
|
|
||||||
if (errbuf)
|
|
||||||
errbuf[0] = 0;
|
|
||||||
/************ Get first send packet on queue and send it! ************/
|
|
||||||
uchar* data = 0;
|
|
||||||
int32 size = 0;
|
|
||||||
int status = 0;
|
|
||||||
if (ServerSendQueuePop(&data, &size)) {
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
status = send(connection_socket, (const char *) data, size, 0);
|
|
||||||
#else
|
|
||||||
status = send(connection_socket, data, size, MSG_NOSIGNAL);
|
|
||||||
if(errno==EPIPE) status = SOCKET_ERROR;
|
|
||||||
#endif
|
|
||||||
if (status >= 1) {
|
|
||||||
#if TCPN_LOG_RAW_DATA_OUT >= 1
|
|
||||||
struct in_addr in;
|
|
||||||
in.s_addr = GetrIP();
|
|
||||||
CoutTimestamp(true);
|
|
||||||
std::cout << ": Wrote " << status << " bytes to network. " << inet_ntoa(in) << ":" << GetrPort();
|
|
||||||
std::cout << std::endl;
|
|
||||||
#if TCPN_LOG_RAW_DATA_OUT == 2
|
|
||||||
int32 tmp = status;
|
|
||||||
if (tmp > 32)
|
|
||||||
tmp = 32;
|
|
||||||
DumpPacket(data, status);
|
|
||||||
#elif TCPN_LOG_RAW_DATA_OUT >= 3
|
|
||||||
DumpPacket(data, status);
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
sent_something = true;
|
|
||||||
if (status < (signed)size) {
|
|
||||||
#if TCPN_LOG_RAW_DATA_OUT >= 1
|
|
||||||
struct in_addr in;
|
|
||||||
in.s_addr = GetrIP();
|
|
||||||
CoutTimestamp(true);
|
|
||||||
std::cout << ": Pushed " << (size - status) << " bytes back onto the send queue. " << inet_ntoa(in) << ":" << GetrPort();
|
|
||||||
std::cout << std::endl;
|
|
||||||
#endif
|
|
||||||
// If there's network congestion, the number of bytes sent can be less than
|
|
||||||
// what we tried to give it... Push the extra back on the queue for later
|
|
||||||
ServerSendQueuePushFront(&data[status], size - status);
|
|
||||||
}
|
|
||||||
else if (status > (signed)size) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// else if (status == size) {}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ServerSendQueuePushFront(data, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
safe_delete_array(data);
|
|
||||||
if (status == SOCKET_ERROR) {
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
if (WSAGetLastError() != WSAEWOULDBLOCK)
|
|
||||||
#else
|
|
||||||
if (errno != EWOULDBLOCK)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
if (errbuf) {
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::SendData(): send(): Errorcode: %i", WSAGetLastError());
|
|
||||||
#else
|
|
||||||
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::SendData(): send(): Errorcode: %s", strerror(errno));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
//if we get an error while disconnecting, just jump to disconnected
|
|
||||||
MState.lock();
|
|
||||||
if(pState == TCPS_Disconnecting)
|
|
||||||
pState = TCPS_Disconnected;
|
|
||||||
MState.unlock();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ThreadReturnType TCPConnection::TCPConnectionLoop(void* tmp) {
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
|
|
||||||
#endif
|
|
||||||
if (tmp == 0) {
|
|
||||||
THREAD_RETURN(nullptr);
|
|
||||||
}
|
|
||||||
TCPConnection* tcpc = (TCPConnection*) tmp;
|
|
||||||
#ifndef WIN32
|
|
||||||
_log(COMMON__THREADS, "Starting TCPConnectionLoop with thread ID %d", pthread_self());
|
|
||||||
#endif
|
|
||||||
tcpc->MLoopRunning.lock();
|
|
||||||
while (tcpc->RunLoop()) {
|
|
||||||
Sleep(LOOP_GRANULARITY);
|
|
||||||
if (!tcpc->ConnectReady()) {
|
|
||||||
if (!tcpc->Process()) {
|
|
||||||
//the processing loop has detecting an error..
|
|
||||||
//we want to drop the link immediately, so we clear buffers too.
|
|
||||||
tcpc->ClearBuffers();
|
|
||||||
tcpc->Disconnect();
|
|
||||||
}
|
|
||||||
Sleep(1);
|
|
||||||
}
|
|
||||||
else if (tcpc->GetAsyncConnect()) {
|
|
||||||
if (tcpc->charAsyncConnect)
|
|
||||||
tcpc->Connect(tcpc->charAsyncConnect, tcpc->GetrPort());
|
|
||||||
else
|
|
||||||
tcpc->ConnectIP(tcpc->GetrIP(), tcpc->GetrPort());
|
|
||||||
tcpc->SetAsyncConnect(false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
Sleep(10); //nothing to do.
|
|
||||||
}
|
|
||||||
tcpc->MLoopRunning.unlock();
|
|
||||||
|
|
||||||
#ifndef WIN32
|
|
||||||
_log(COMMON__THREADS, "Ending TCPConnectionLoop with thread ID %d", pthread_self());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
THREAD_RETURN(nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TCPConnection::RunLoop() {
|
|
||||||
bool ret;
|
|
||||||
MRunLoop.lock();
|
|
||||||
ret = pRunLoop;
|
|
||||||
MRunLoop.unlock();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,176 +0,0 @@
|
|||||||
/* EQEMu: Everquest Server Emulator
|
|
||||||
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
|
||||||
|
|
||||||
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; version 2 of the License.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
||||||
are required to give you total support for your newly bought product;
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
#ifndef TCP_CONNECTION_H
|
|
||||||
#define TCP_CONNECTION_H
|
|
||||||
/*
|
|
||||||
Parent classes for interserver TCP Communication.
|
|
||||||
-Quagmire
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
#define snprintf _snprintf
|
|
||||||
#define strncasecmp _strnicmp
|
|
||||||
#define strcasecmp _stricmp
|
|
||||||
|
|
||||||
#include <process.h>
|
|
||||||
#else
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <netdb.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#define INVALID_SOCKET -1
|
|
||||||
#define SOCKET_ERROR -1
|
|
||||||
#include "unix.h"
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "types.h"
|
|
||||||
#include "Mutex.h"
|
|
||||||
#include "queue.h"
|
|
||||||
#include "MiscFunctions.h"
|
|
||||||
|
|
||||||
class BaseTCPServer;
|
|
||||||
class ServerPacket;
|
|
||||||
|
|
||||||
#define TCPConnection_ErrorBufferSize 1024
|
|
||||||
#define MaxTCPReceiveBuffferSize 524288
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef DEF_eConnectionType
|
|
||||||
#define DEF_eConnectionType
|
|
||||||
enum eConnectionType {Incomming, Outgoing};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
class TCPConnection {
|
|
||||||
protected:
|
|
||||||
typedef enum {
|
|
||||||
TCPS_Ready = 0,
|
|
||||||
TCPS_Connecting = 1,
|
|
||||||
TCPS_Connected = 100,
|
|
||||||
TCPS_Disconnecting = 200, //I do not know the difference between Disconnecting and Closing
|
|
||||||
TCPS_Disconnected = 201,
|
|
||||||
TCPS_Closing = 250,
|
|
||||||
TCPS_Error = 255
|
|
||||||
} State_t;
|
|
||||||
|
|
||||||
public:
|
|
||||||
//socket created by a server (incoming)
|
|
||||||
TCPConnection(uint32 ID, SOCKET iSock, uint32 irIP, uint16 irPort);
|
|
||||||
//socket created to connect to a server (outgoing)
|
|
||||||
TCPConnection(); // for outgoing connections
|
|
||||||
|
|
||||||
virtual ~TCPConnection();
|
|
||||||
|
|
||||||
// Functions for outgoing connections
|
|
||||||
bool Connect(const char* irAddress, uint16 irPort, char* errbuf = 0);
|
|
||||||
virtual bool ConnectIP(uint32 irIP, uint16 irPort, char* errbuf = 0);
|
|
||||||
void AsyncConnect(const char* irAddress, uint16 irPort);
|
|
||||||
void AsyncConnect(uint32 irIP, uint16 irPort);
|
|
||||||
virtual void Disconnect();
|
|
||||||
|
|
||||||
bool Send(const uchar* data, int32 size);
|
|
||||||
|
|
||||||
char* PopLine(); //returns ownership of allocated byte array
|
|
||||||
inline uint32 GetrIP() const { return rIP; }
|
|
||||||
inline uint16 GetrPort() const { return rPort; }
|
|
||||||
virtual State_t GetState() const;
|
|
||||||
inline bool Connected() const { return (GetState() == TCPS_Connected); }
|
|
||||||
bool ConnectReady() const;
|
|
||||||
void Free(); // Inform TCPServer that this connection object is no longer referanced
|
|
||||||
|
|
||||||
inline uint32 GetID() const { return id; }
|
|
||||||
|
|
||||||
bool GetEcho();
|
|
||||||
void SetEcho(bool iValue);
|
|
||||||
bool GetSockName(char *host, uint16 *port);
|
|
||||||
|
|
||||||
//should only be used by TCPServer<T>:
|
|
||||||
bool CheckNetActive();
|
|
||||||
inline bool IsFree() const { return pFree; }
|
|
||||||
virtual bool Process();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
friend class BaseTCPServer;
|
|
||||||
void SetState(State_t iState);
|
|
||||||
|
|
||||||
static ThreadReturnType TCPConnectionLoop(void* tmp);
|
|
||||||
// SOCKET sock;
|
|
||||||
bool RunLoop();
|
|
||||||
Mutex MLoopRunning;
|
|
||||||
Mutex MAsyncConnect;
|
|
||||||
bool GetAsyncConnect();
|
|
||||||
bool SetAsyncConnect(bool iValue);
|
|
||||||
char* charAsyncConnect;
|
|
||||||
bool pAsyncConnect; //this flag should really be turned into a state instead.
|
|
||||||
|
|
||||||
virtual bool ProcessReceivedData(char* errbuf = 0);
|
|
||||||
virtual bool SendData(bool &sent_something, char* errbuf = 0);
|
|
||||||
virtual bool RecvData(char* errbuf = 0);
|
|
||||||
|
|
||||||
virtual void ClearBuffers();
|
|
||||||
|
|
||||||
|
|
||||||
bool m_previousLineEnd;
|
|
||||||
|
|
||||||
eConnectionType ConnectionType;
|
|
||||||
Mutex MRunLoop;
|
|
||||||
bool pRunLoop;
|
|
||||||
|
|
||||||
SOCKET connection_socket;
|
|
||||||
uint32 id;
|
|
||||||
uint32 rIP;
|
|
||||||
uint16 rPort; // host byte order
|
|
||||||
bool pFree;
|
|
||||||
|
|
||||||
mutable Mutex MState;
|
|
||||||
State_t pState;
|
|
||||||
|
|
||||||
//text based line out queue.
|
|
||||||
Mutex MLineOutQueue;
|
|
||||||
virtual bool LineOutQueuePush(char* line); //this is really kinda a hack for the transition to packet mode. Returns true to stop processing the output.
|
|
||||||
MyQueue<char> LineOutQueue;
|
|
||||||
|
|
||||||
uchar* recvbuf;
|
|
||||||
int32 recvbuf_size;
|
|
||||||
int32 recvbuf_used;
|
|
||||||
|
|
||||||
int32 recvbuf_echo;
|
|
||||||
volatile bool pEcho;
|
|
||||||
|
|
||||||
Mutex MSendQueue;
|
|
||||||
uchar* sendbuf;
|
|
||||||
int32 sendbuf_size;
|
|
||||||
int32 sendbuf_used;
|
|
||||||
bool ServerSendQueuePop(uchar** data, int32* size);
|
|
||||||
bool ServerSendQueuePopForce(uchar** data, int32* size); //does a lock() instead of a trylock()
|
|
||||||
void ServerSendQueuePushEnd(const uchar* data, int32 size);
|
|
||||||
void ServerSendQueuePushEnd(uchar** data, int32 size);
|
|
||||||
void ServerSendQueuePushFront(uchar* data, int32 size);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void FinishDisconnect();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@@ -1,229 +0,0 @@
|
|||||||
#include "debug.h"
|
|
||||||
#include "TCPServer.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
#include <process.h>
|
|
||||||
#else
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#define INVALID_SOCKET -1
|
|
||||||
#define SOCKET_ERROR -1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define SERVER_LOOP_GRANULARITY 3 //# of ms between checking our socket/queues
|
|
||||||
|
|
||||||
BaseTCPServer::BaseTCPServer(uint16 in_port) {
|
|
||||||
NextID = 1;
|
|
||||||
pPort = in_port;
|
|
||||||
sock = 0;
|
|
||||||
pRunLoop = true;
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
_beginthread(BaseTCPServer::TCPServerLoop, 0, this);
|
|
||||||
#else
|
|
||||||
pthread_t thread;
|
|
||||||
pthread_create(&thread, nullptr, &BaseTCPServer::TCPServerLoop, this);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseTCPServer::~BaseTCPServer() {
|
|
||||||
StopLoopAndWait();
|
|
||||||
}
|
|
||||||
|
|
||||||
void BaseTCPServer::StopLoopAndWait() {
|
|
||||||
MRunLoop.lock();
|
|
||||||
if(pRunLoop) {
|
|
||||||
pRunLoop = false;
|
|
||||||
MRunLoop.unlock();
|
|
||||||
//wait for loop to stop.
|
|
||||||
MLoopRunning.lock();
|
|
||||||
MLoopRunning.unlock();
|
|
||||||
} else {
|
|
||||||
MRunLoop.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BaseTCPServer::RunLoop() {
|
|
||||||
bool ret;
|
|
||||||
MRunLoop.lock();
|
|
||||||
ret = pRunLoop;
|
|
||||||
MRunLoop.unlock();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ThreadReturnType BaseTCPServer::TCPServerLoop(void* tmp) {
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
|
|
||||||
#endif
|
|
||||||
if (tmp == 0) {
|
|
||||||
THREAD_RETURN(nullptr);
|
|
||||||
}
|
|
||||||
BaseTCPServer* tcps = (BaseTCPServer*) tmp;
|
|
||||||
|
|
||||||
#ifndef WIN32
|
|
||||||
_log(COMMON__THREADS, "Starting TCPServerLoop with thread ID %d", pthread_self());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
tcps->MLoopRunning.lock();
|
|
||||||
while (tcps->RunLoop()) {
|
|
||||||
Sleep(SERVER_LOOP_GRANULARITY);
|
|
||||||
tcps->Process();
|
|
||||||
}
|
|
||||||
tcps->MLoopRunning.unlock();
|
|
||||||
|
|
||||||
#ifndef WIN32
|
|
||||||
_log(COMMON__THREADS, "Ending TCPServerLoop with thread ID %d", pthread_self());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
THREAD_RETURN(nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BaseTCPServer::Process() {
|
|
||||||
ListenNewConnections();
|
|
||||||
}
|
|
||||||
|
|
||||||
void BaseTCPServer::ListenNewConnections() {
|
|
||||||
SOCKET tmpsock;
|
|
||||||
struct sockaddr_in from;
|
|
||||||
struct in_addr in;
|
|
||||||
unsigned int fromlen;
|
|
||||||
unsigned short port;
|
|
||||||
|
|
||||||
from.sin_family = AF_INET;
|
|
||||||
fromlen = sizeof(from);
|
|
||||||
LockMutex lock(&MSock);
|
|
||||||
#ifndef DARWIN // Corysia - On OSX, 0 is a valid fd.
|
|
||||||
if (!sock)
|
|
||||||
return;
|
|
||||||
#else
|
|
||||||
if (sock == -1) return;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Check for pending connects
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
unsigned long nonblocking = 1;
|
|
||||||
while ((tmpsock = accept(sock, (struct sockaddr*) &from, (int *) &fromlen)) != INVALID_SOCKET) {
|
|
||||||
ioctlsocket (tmpsock, FIONBIO, &nonblocking);
|
|
||||||
#else
|
|
||||||
#ifdef __CYGWIN__
|
|
||||||
while ((tmpsock = accept(sock, (struct sockaddr *) &from, (int *) &fromlen)) != INVALID_SOCKET) {
|
|
||||||
#else
|
|
||||||
while ((tmpsock = accept(sock, (struct sockaddr*) &from, &fromlen)) != INVALID_SOCKET) {
|
|
||||||
#endif
|
|
||||||
fcntl(tmpsock, F_SETFL, O_NONBLOCK);
|
|
||||||
#endif
|
|
||||||
int bufsize = 64 * 1024; // 64kbyte recieve buffer, up from default of 8k
|
|
||||||
setsockopt(tmpsock, SOL_SOCKET, SO_RCVBUF, (char*) &bufsize, sizeof(bufsize));
|
|
||||||
port = from.sin_port;
|
|
||||||
in.s_addr = from.sin_addr.s_addr;
|
|
||||||
|
|
||||||
// New TCP connection, this must consume the socket.
|
|
||||||
CreateNewConnection(GetNextID(), tmpsock, in.s_addr, ntohs(from.sin_port));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BaseTCPServer::Open(uint16 in_port, char* errbuf) {
|
|
||||||
if (errbuf)
|
|
||||||
errbuf[0] = 0;
|
|
||||||
LockMutex lock(&MSock);
|
|
||||||
if (sock != 0) {
|
|
||||||
if (errbuf)
|
|
||||||
snprintf(errbuf, TCPServer_ErrorBufferSize, "Listening socket already open");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (in_port != 0) {
|
|
||||||
pPort = in_port;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
SOCKADDR_IN address;
|
|
||||||
unsigned long nonblocking = 1;
|
|
||||||
#else
|
|
||||||
struct sockaddr_in address;
|
|
||||||
#endif
|
|
||||||
int reuse_addr = 1;
|
|
||||||
|
|
||||||
// Setup internet address information.
|
|
||||||
// This is used with the bind() call
|
|
||||||
memset((char *) &address, 0, sizeof(address));
|
|
||||||
address.sin_family = AF_INET;
|
|
||||||
address.sin_port = htons(pPort);
|
|
||||||
address.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
||||||
|
|
||||||
// Setting up TCP port for new TCP connections
|
|
||||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
||||||
if (sock == INVALID_SOCKET) {
|
|
||||||
if (errbuf)
|
|
||||||
snprintf(errbuf, TCPServer_ErrorBufferSize, "socket(): INVALID_SOCKET");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Quag: dont think following is good stuff for TCP, good for UDP
|
|
||||||
// Mis: SO_REUSEADDR shouldn't be a problem for tcp--allows you to restart
|
|
||||||
// without waiting for conns in TIME_WAIT to die
|
|
||||||
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse_addr, sizeof(reuse_addr));
|
|
||||||
|
|
||||||
|
|
||||||
if (bind(sock, (struct sockaddr *) &address, sizeof(address)) < 0) {
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
closesocket(sock);
|
|
||||||
#else
|
|
||||||
close(sock);
|
|
||||||
#endif
|
|
||||||
sock = 0;
|
|
||||||
if (errbuf)
|
|
||||||
sprintf(errbuf, "bind(): <0");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int bufsize = 64 * 1024; // 64kbyte recieve buffer, up from default of 8k
|
|
||||||
setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*) &bufsize, sizeof(bufsize));
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
ioctlsocket (sock, FIONBIO, &nonblocking);
|
|
||||||
#else
|
|
||||||
fcntl(sock, F_SETFL, O_NONBLOCK);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (listen(sock, SOMAXCONN) == SOCKET_ERROR) {
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
closesocket(sock);
|
|
||||||
if (errbuf)
|
|
||||||
snprintf(errbuf, TCPServer_ErrorBufferSize, "listen() failed, Error: %d", WSAGetLastError());
|
|
||||||
#else
|
|
||||||
close(sock);
|
|
||||||
if (errbuf)
|
|
||||||
snprintf(errbuf, TCPServer_ErrorBufferSize, "listen() failed, Error: %s", strerror(errno));
|
|
||||||
#endif
|
|
||||||
sock = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BaseTCPServer::Close() {
|
|
||||||
StopLoopAndWait();
|
|
||||||
|
|
||||||
LockMutex lock(&MSock);
|
|
||||||
if (sock) {
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
closesocket(sock);
|
|
||||||
#else
|
|
||||||
close(sock);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
sock = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BaseTCPServer::IsOpen() {
|
|
||||||
MSock.lock();
|
|
||||||
bool ret = (bool) (sock != 0);
|
|
||||||
MSock.unlock();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,135 +0,0 @@
|
|||||||
#ifndef TCPSERVER_H_
|
|
||||||
#define TCPSERVER_H_
|
|
||||||
|
|
||||||
#include "types.h"
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <queue>
|
|
||||||
|
|
||||||
#define TCPServer_ErrorBufferSize 1024
|
|
||||||
|
|
||||||
//this is the non-connection type specific server.
|
|
||||||
class BaseTCPServer {
|
|
||||||
public:
|
|
||||||
BaseTCPServer(uint16 iPort = 0);
|
|
||||||
virtual ~BaseTCPServer();
|
|
||||||
|
|
||||||
bool Open(uint16 iPort = 0, char* errbuf = 0); // opens the port
|
|
||||||
void Close(); // closes the port
|
|
||||||
bool IsOpen();
|
|
||||||
inline uint16 GetPort() { return pPort; }
|
|
||||||
inline uint32 GetNextID() { return NextID++; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
static ThreadReturnType TCPServerLoop(void* tmp);
|
|
||||||
|
|
||||||
//factory method:
|
|
||||||
virtual void CreateNewConnection(uint32 ID, SOCKET in_socket, uint32 irIP, uint16 irPort) = 0;
|
|
||||||
|
|
||||||
|
|
||||||
virtual void Process();
|
|
||||||
bool RunLoop();
|
|
||||||
Mutex MLoopRunning;
|
|
||||||
|
|
||||||
void StopLoopAndWait();
|
|
||||||
|
|
||||||
void ListenNewConnections();
|
|
||||||
|
|
||||||
uint32 NextID;
|
|
||||||
|
|
||||||
Mutex MRunLoop;
|
|
||||||
bool pRunLoop;
|
|
||||||
|
|
||||||
Mutex MSock;
|
|
||||||
SOCKET sock;
|
|
||||||
uint16 pPort;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
class TCPServer : public BaseTCPServer {
|
|
||||||
protected:
|
|
||||||
typedef typename std::vector<T *> vstore;
|
|
||||||
typedef typename std::vector<T *>::iterator vitr;
|
|
||||||
public:
|
|
||||||
TCPServer(uint16 iPort = 0)
|
|
||||||
: BaseTCPServer(iPort) {
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~TCPServer() {
|
|
||||||
StopLoopAndWait();
|
|
||||||
|
|
||||||
//im not sure what the right thing to do here is...
|
|
||||||
//we are freeing a connection which somebody likely has a pointer to..
|
|
||||||
//but, we really shouldent ever get called anyhow..
|
|
||||||
vitr cur, end;
|
|
||||||
cur = m_list.begin();
|
|
||||||
end = m_list.end();
|
|
||||||
for(; cur != end; ++cur) {
|
|
||||||
delete *cur;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
T * NewQueuePop() {
|
|
||||||
T * ret = nullptr;
|
|
||||||
MNewQueue.lock();
|
|
||||||
if(!m_NewQueue.empty()) {
|
|
||||||
ret = m_NewQueue.front();
|
|
||||||
m_NewQueue.pop();
|
|
||||||
}
|
|
||||||
MNewQueue.unlock();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void Process() {
|
|
||||||
BaseTCPServer::Process();
|
|
||||||
|
|
||||||
vitr cur;
|
|
||||||
cur = m_list.begin();
|
|
||||||
while(cur != m_list.end()) {
|
|
||||||
T *data = *cur;
|
|
||||||
if (data->IsFree() && (!data->CheckNetActive())) {
|
|
||||||
#if EQN_DEBUG >= 4
|
|
||||||
std::cout << "TCPConnection Connection deleted." << std::endl;
|
|
||||||
#endif
|
|
||||||
delete data;
|
|
||||||
cur = m_list.erase(cur);
|
|
||||||
} else {
|
|
||||||
if (!data->Process())
|
|
||||||
data->Disconnect();
|
|
||||||
++cur;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddConnection(T *con) {
|
|
||||||
m_list.push_back(con);
|
|
||||||
MNewQueue.lock();
|
|
||||||
m_NewQueue.push(con);
|
|
||||||
MNewQueue.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
//queue of new connections, for the app to pull from
|
|
||||||
Mutex MNewQueue;
|
|
||||||
std::queue<T *> m_NewQueue;
|
|
||||||
|
|
||||||
vstore m_list;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif /*TCPSERVER_H_*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
/* EQEMu: Everquest Server Emulator
|
|
||||||
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
|
|
||||||
|
|
||||||
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; version 2 of the License.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
||||||
are required to give you total support for your newly bought product;
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
#include "debug.h"
|
|
||||||
#include "XMLParser.h"
|
|
||||||
|
|
||||||
XMLParser::XMLParser() {
|
|
||||||
ParseOkay = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool XMLParser::ParseFile(const char *file, const char *root_ele) {
|
|
||||||
std::map<std::string,ElementHandler>::iterator handler;
|
|
||||||
TiXmlDocument doc( file );
|
|
||||||
if(!doc.LoadFile()) {
|
|
||||||
printf("Unable to load '%s': %s\n", file, doc.ErrorDesc());
|
|
||||||
return(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
TiXmlElement *root = doc.FirstChildElement( root_ele );
|
|
||||||
if(root == nullptr) {
|
|
||||||
printf("Unable to find root '%s' in %s\n",root_ele, file);
|
|
||||||
return(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
ParseOkay=true;
|
|
||||||
|
|
||||||
TiXmlNode *main_element = nullptr;
|
|
||||||
while( (main_element = root->IterateChildren( main_element )) ) {
|
|
||||||
if(main_element->Type() != TiXmlNode::ELEMENT)
|
|
||||||
continue; //skip crap we dont care about
|
|
||||||
TiXmlElement *ele = (TiXmlElement *) main_element;
|
|
||||||
|
|
||||||
handler=Handlers.find(ele->Value());
|
|
||||||
if (handler!=Handlers.end() && handler->second) {
|
|
||||||
ElementHandler h=handler->second;
|
|
||||||
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
* This is kinda a sketchy operation here, since all of these
|
|
||||||
* element handler methods will be functions in child classes.
|
|
||||||
* This essentially causes us to do an un-checkable (and hence
|
|
||||||
* un-handle-properly-able) cast down to the child class. This
|
|
||||||
* WILL BREAK if any children classes do multiple inheritance.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
(this->*h)(ele);
|
|
||||||
} else {
|
|
||||||
//unhandled element.... do nothing for now
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return(ParseOkay);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *XMLParser::ParseTextBlock(TiXmlNode *within, const char *name, bool optional) {
|
|
||||||
TiXmlElement * txt = within->FirstChildElement(name);
|
|
||||||
if(txt == nullptr) {
|
|
||||||
if(!optional) {
|
|
||||||
printf("Unable to find a '%s' element on %s element at line %d\n", name, within->Value(), within->Row());
|
|
||||||
ParseOkay=false;
|
|
||||||
}
|
|
||||||
return(nullptr);
|
|
||||||
}
|
|
||||||
TiXmlNode *contents = txt->FirstChild();
|
|
||||||
if(contents == nullptr || contents->Type() != TiXmlNode::TEXT) {
|
|
||||||
if(!optional)
|
|
||||||
printf("Node '%s' was expected to be a text element in %s element at line %d\n", name, txt->Value(), txt->Row());
|
|
||||||
return(nullptr);
|
|
||||||
}
|
|
||||||
return(contents->Value());
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *XMLParser::GetText(TiXmlNode *within, bool optional) {
|
|
||||||
TiXmlNode *contents = within->FirstChild();
|
|
||||||
if(contents == nullptr || contents->Type() != TiXmlNode::TEXT) {
|
|
||||||
if(!optional) {
|
|
||||||
printf("Node was expected to be a text element in %s element at line %d\n", within->Value(), within->Row());
|
|
||||||
ParseOkay=false;
|
|
||||||
}
|
|
||||||
return(nullptr);
|
|
||||||
}
|
|
||||||
return(contents->Value());
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
/* EQEMu: Everquest Server Emulator
|
|
||||||
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
|
|
||||||
|
|
||||||
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; version 2 of the License.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
||||||
are required to give you total support for your newly bought product;
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
#ifndef XMLParser_H
|
|
||||||
#define XMLParser_H
|
|
||||||
|
|
||||||
#include "debug.h"
|
|
||||||
#include "tinyxml/tinyxml.h"
|
|
||||||
#include "../common/types.h"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
/*
|
|
||||||
* See note in XMLParser::ParseFile() before inheriting this class.
|
|
||||||
*/
|
|
||||||
class XMLParser {
|
|
||||||
public:
|
|
||||||
typedef void (XMLParser::*ElementHandler)(TiXmlElement *ele);
|
|
||||||
|
|
||||||
XMLParser();
|
|
||||||
virtual ~XMLParser() {}
|
|
||||||
|
|
||||||
bool ParseFile(const char *file, const char *root_ele);
|
|
||||||
bool ParseStatus() const { return ParseOkay; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
const char *ParseTextBlock(TiXmlNode *within, const char *name, bool optional = false);
|
|
||||||
const char *GetText(TiXmlNode *within, bool optional = false);
|
|
||||||
|
|
||||||
std::map<std::string,ElementHandler> Handlers;
|
|
||||||
|
|
||||||
bool ParseOkay;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@@ -1,490 +0,0 @@
|
|||||||
#include "../common/types.h"
|
|
||||||
|
|
||||||
inline const char* StaticGetZoneName(uint32 zoneID) {
|
|
||||||
// @merth: I did the following query to retrieve these (following by a simple find/replace)
|
|
||||||
// select concat('case ', zoneidnumber), concat(short_name, '";') from zone order by zoneidnumber;
|
|
||||||
switch (zoneID) {
|
|
||||||
case 1: return "qeynos";
|
|
||||||
case 2: return "qeynos2";
|
|
||||||
case 3: return "qrg";
|
|
||||||
case 4: return "qeytoqrg";
|
|
||||||
case 5: return "highpass";
|
|
||||||
case 6: return "highkeep";
|
|
||||||
case 8: return "freportn";
|
|
||||||
case 9: return "freportw";
|
|
||||||
case 10: return "freporte";
|
|
||||||
case 11: return "runnyeye";
|
|
||||||
case 12: return "qey2hh1";
|
|
||||||
case 13: return "northkarana";
|
|
||||||
case 14: return "southkarana";
|
|
||||||
case 15: return "eastkarana";
|
|
||||||
case 16: return "beholder";
|
|
||||||
case 17: return "blackburrow";
|
|
||||||
case 18: return "paw";
|
|
||||||
case 19: return "rivervale";
|
|
||||||
case 20: return "kithicor";
|
|
||||||
case 21: return "commons";
|
|
||||||
case 22: return "ecommons";
|
|
||||||
case 23: return "erudnint";
|
|
||||||
case 24: return "erudnext";
|
|
||||||
case 25: return "nektulos";
|
|
||||||
case 26: return "cshome";
|
|
||||||
case 27: return "lavastorm";
|
|
||||||
case 28: return "nektropos";
|
|
||||||
case 29: return "halas";
|
|
||||||
case 30: return "everfrost";
|
|
||||||
case 31: return "soldunga";
|
|
||||||
case 32: return "soldungb";
|
|
||||||
case 33: return "misty";
|
|
||||||
case 34: return "nro";
|
|
||||||
case 35: return "sro";
|
|
||||||
case 36: return "befallen";
|
|
||||||
case 37: return "oasis";
|
|
||||||
case 38: return "tox";
|
|
||||||
case 39: return "hole";
|
|
||||||
case 40: return "neriaka";
|
|
||||||
case 41: return "neriakb";
|
|
||||||
case 42: return "neriakc";
|
|
||||||
case 43: return "neriakd";
|
|
||||||
case 44: return "najena";
|
|
||||||
case 45: return "qcat";
|
|
||||||
case 46: return "innothule";
|
|
||||||
case 47: return "feerrott";
|
|
||||||
case 48: return "cazicthule";
|
|
||||||
case 49: return "oggok";
|
|
||||||
case 50: return "rathemtn";
|
|
||||||
case 51: return "lakerathe";
|
|
||||||
case 52: return "grobb";
|
|
||||||
case 53: return "aviak";
|
|
||||||
case 54: return "gfaydark";
|
|
||||||
case 55: return "akanon";
|
|
||||||
case 56: return "steamfont";
|
|
||||||
case 57: return "lfaydark";
|
|
||||||
case 58: return "crushbone";
|
|
||||||
case 59: return "mistmoore";
|
|
||||||
case 60: return "kaladima";
|
|
||||||
case 61: return "felwithea";
|
|
||||||
case 62: return "felwitheb";
|
|
||||||
case 63: return "unrest";
|
|
||||||
case 64: return "kedge";
|
|
||||||
case 65: return "guktop";
|
|
||||||
case 66: return "gukbottom";
|
|
||||||
case 67: return "kaladimb";
|
|
||||||
case 68: return "butcher";
|
|
||||||
case 69: return "oot";
|
|
||||||
case 70: return "cauldron";
|
|
||||||
case 71: return "airplane";
|
|
||||||
case 72: return "fearplane";
|
|
||||||
case 73: return "permafrost";
|
|
||||||
case 74: return "kerraridge";
|
|
||||||
case 75: return "paineel";
|
|
||||||
case 76: return "hateplane";
|
|
||||||
case 77: return "arena";
|
|
||||||
case 78: return "fieldofbone";
|
|
||||||
case 79: return "warslikswood";
|
|
||||||
case 80: return "soltemple";
|
|
||||||
case 81: return "droga";
|
|
||||||
case 82: return "cabwest";
|
|
||||||
case 83: return "swampofnohope";
|
|
||||||
case 84: return "firiona";
|
|
||||||
case 85: return "lakeofillomen";
|
|
||||||
case 86: return "dreadlands";
|
|
||||||
case 87: return "burningwood";
|
|
||||||
case 88: return "kaesora";
|
|
||||||
case 89: return "sebilis";
|
|
||||||
case 90: return "citymist";
|
|
||||||
case 91: return "skyfire";
|
|
||||||
case 92: return "frontiermtns";
|
|
||||||
case 93: return "overthere";
|
|
||||||
case 94: return "emeraldjungle";
|
|
||||||
case 95: return "trakanon";
|
|
||||||
case 96: return "timorous";
|
|
||||||
case 97: return "kurn";
|
|
||||||
case 98: return "erudsxing";
|
|
||||||
case 100: return "stonebrunt";
|
|
||||||
case 101: return "warrens";
|
|
||||||
case 102: return "karnor";
|
|
||||||
case 103: return "chardok";
|
|
||||||
case 104: return "dalnir";
|
|
||||||
case 105: return "charasis";
|
|
||||||
case 106: return "cabeast";
|
|
||||||
case 107: return "nurga";
|
|
||||||
case 108: return "veeshan";
|
|
||||||
case 109: return "veksar";
|
|
||||||
case 110: return "iceclad";
|
|
||||||
case 111: return "frozenshadow";
|
|
||||||
case 112: return "velketor";
|
|
||||||
case 113: return "kael";
|
|
||||||
case 114: return "skyshrine";
|
|
||||||
case 115: return "thurgadina";
|
|
||||||
case 116: return "eastwastes";
|
|
||||||
case 117: return "cobaltscar";
|
|
||||||
case 118: return "greatdivide";
|
|
||||||
case 119: return "wakening";
|
|
||||||
case 120: return "westwastes";
|
|
||||||
case 121: return "crystal";
|
|
||||||
case 123: return "necropolis";
|
|
||||||
case 124: return "templeveeshan";
|
|
||||||
case 125: return "sirens";
|
|
||||||
case 126: return "mischiefplane";
|
|
||||||
case 127: return "growthplane";
|
|
||||||
case 128: return "sleeper";
|
|
||||||
case 129: return "thurgadinb";
|
|
||||||
case 130: return "erudsxing2";
|
|
||||||
case 150: return "shadowhaven";
|
|
||||||
case 151: return "bazaar";
|
|
||||||
case 152: return "nexus";
|
|
||||||
case 153: return "echo";
|
|
||||||
case 154: return "acrylia";
|
|
||||||
case 155: return "sharvahl";
|
|
||||||
case 156: return "paludal";
|
|
||||||
case 157: return "fungusgrove";
|
|
||||||
case 158: return "vexthal";
|
|
||||||
case 159: return "sseru";
|
|
||||||
case 160: return "katta";
|
|
||||||
case 161: return "netherbian";
|
|
||||||
case 162: return "ssratemple";
|
|
||||||
case 163: return "griegsend";
|
|
||||||
case 164: return "thedeep";
|
|
||||||
case 165: return "shadeweaver";
|
|
||||||
case 166: return "hollowshade";
|
|
||||||
case 167: return "grimling";
|
|
||||||
case 168: return "mseru";
|
|
||||||
case 169: return "letalis";
|
|
||||||
case 170: return "twilight";
|
|
||||||
case 171: return "thegrey";
|
|
||||||
case 172: return "tenebrous";
|
|
||||||
case 173: return "maiden";
|
|
||||||
case 174: return "dawnshroud";
|
|
||||||
case 175: return "scarlet";
|
|
||||||
case 176: return "umbral";
|
|
||||||
case 179: return "akheva";
|
|
||||||
case 180: return "arena2";
|
|
||||||
case 181: return "jaggedpine";
|
|
||||||
case 182: return "nedaria";
|
|
||||||
case 183: return "tutorial";
|
|
||||||
case 184: return "load";
|
|
||||||
case 185: return "load2";
|
|
||||||
case 186: return "hateplaneb";
|
|
||||||
case 187: return "shadowrest";
|
|
||||||
case 188: return "tutoriala";
|
|
||||||
case 189: return "tutorialb";
|
|
||||||
case 190: return "clz";
|
|
||||||
case 200: return "codecay";
|
|
||||||
case 201: return "pojustice";
|
|
||||||
case 202: return "poknowledge";
|
|
||||||
case 203: return "potranquility";
|
|
||||||
case 204: return "ponightmare";
|
|
||||||
case 205: return "podisease";
|
|
||||||
case 206: return "poinnovation";
|
|
||||||
case 207: return "potorment";
|
|
||||||
case 208: return "povalor";
|
|
||||||
case 209: return "bothunder";
|
|
||||||
case 210: return "postorms";
|
|
||||||
case 211: return "hohonora";
|
|
||||||
case 212: return "solrotower";
|
|
||||||
case 213: return "powar";
|
|
||||||
case 214: return "potactics";
|
|
||||||
case 215: return "poair";
|
|
||||||
case 216: return "powater";
|
|
||||||
case 217: return "pofire";
|
|
||||||
case 218: return "poeartha";
|
|
||||||
case 219: return "potimea";
|
|
||||||
case 220: return "hohonorb";
|
|
||||||
case 221: return "nightmareb";
|
|
||||||
case 222: return "poearthb";
|
|
||||||
case 223: return "potimeb";
|
|
||||||
case 224: return "gunthak";
|
|
||||||
case 225: return "dulak";
|
|
||||||
case 226: return "torgiran";
|
|
||||||
case 227: return "nadox";
|
|
||||||
case 228: return "hatesfury";
|
|
||||||
case 229: return "guka";
|
|
||||||
case 230: return "ruja";
|
|
||||||
case 231: return "taka";
|
|
||||||
case 232: return "mira";
|
|
||||||
case 233: return "mmca";
|
|
||||||
case 234: return "gukb";
|
|
||||||
case 235: return "rujb";
|
|
||||||
case 236: return "takb";
|
|
||||||
case 237: return "mirb";
|
|
||||||
case 238: return "mmcb";
|
|
||||||
case 239: return "gukc";
|
|
||||||
case 240: return "rujc";
|
|
||||||
case 241: return "takc";
|
|
||||||
case 242: return "mirc";
|
|
||||||
case 243: return "mmcc";
|
|
||||||
case 244: return "gukd";
|
|
||||||
case 245: return "rujd";
|
|
||||||
case 246: return "takd";
|
|
||||||
case 247: return "mird";
|
|
||||||
case 248: return "mmcd";
|
|
||||||
case 249: return "guke";
|
|
||||||
case 250: return "ruje";
|
|
||||||
case 251: return "take";
|
|
||||||
case 252: return "mire";
|
|
||||||
case 253: return "mmce";
|
|
||||||
case 254: return "gukf";
|
|
||||||
case 255: return "rujf";
|
|
||||||
case 256: return "takf";
|
|
||||||
case 257: return "mirf";
|
|
||||||
case 258: return "mmcf";
|
|
||||||
case 259: return "gukg";
|
|
||||||
case 260: return "rujg";
|
|
||||||
case 261: return "takg";
|
|
||||||
case 262: return "mirg";
|
|
||||||
case 263: return "mmcg";
|
|
||||||
case 264: return "gukh";
|
|
||||||
case 265: return "rujh";
|
|
||||||
case 266: return "takh";
|
|
||||||
case 267: return "mirh";
|
|
||||||
case 268: return "mmch";
|
|
||||||
case 269: return "ruji";
|
|
||||||
case 270: return "taki";
|
|
||||||
case 271: return "miri";
|
|
||||||
case 272: return "mmci";
|
|
||||||
case 273: return "rujj";
|
|
||||||
case 274: return "takj";
|
|
||||||
case 275: return "mirj";
|
|
||||||
case 276: return "mmcj";
|
|
||||||
case 277: return "chardokb";
|
|
||||||
case 278: return "soldungc";
|
|
||||||
case 279: return "abysmal";
|
|
||||||
case 280: return "natimbi";
|
|
||||||
case 281: return "qinimi";
|
|
||||||
case 282: return "riwwi";
|
|
||||||
case 283: return "barindu";
|
|
||||||
case 284: return "ferubi";
|
|
||||||
case 285: return "snpool";
|
|
||||||
case 286: return "snlair";
|
|
||||||
case 287: return "snplant";
|
|
||||||
case 288: return "sncrematory";
|
|
||||||
case 289: return "tipt";
|
|
||||||
case 290: return "vxed";
|
|
||||||
case 291: return "yxtta";
|
|
||||||
case 292: return "uqua";
|
|
||||||
case 293: return "kodtaz";
|
|
||||||
case 294: return "ikkinz";
|
|
||||||
case 295: return "qvic";
|
|
||||||
case 296: return "inktuta";
|
|
||||||
case 297: return "txevu";
|
|
||||||
case 298: return "tacvi";
|
|
||||||
case 299: return "qvicb";
|
|
||||||
case 300: return "wallofslaughter";
|
|
||||||
case 301: return "bloodfields";
|
|
||||||
case 302: return "draniksscar";
|
|
||||||
case 303: return "causeway";
|
|
||||||
case 304: return "chambersa";
|
|
||||||
case 305: return "chambersb";
|
|
||||||
case 306: return "chambersc";
|
|
||||||
case 307: return "chambersd";
|
|
||||||
case 308: return "chamberse";
|
|
||||||
case 309: return "chambersf";
|
|
||||||
case 316: return "provinggrounds";
|
|
||||||
case 317: return "anguish";
|
|
||||||
case 318: return "dranikhollowsa";
|
|
||||||
case 319: return "dranikhollowsb";
|
|
||||||
case 320: return "dranikhollowsc";
|
|
||||||
case 328: return "dranikcatacombsa";
|
|
||||||
case 329: return "dranikcatacombsb";
|
|
||||||
case 330: return "dranikcatacombsc";
|
|
||||||
case 331: return "draniksewersa";
|
|
||||||
case 332: return "draniksewersb";
|
|
||||||
case 333: return "draniksewersc";
|
|
||||||
case 334: return "riftseekers";
|
|
||||||
case 335: return "harbingers";
|
|
||||||
case 336: return "dranik";
|
|
||||||
case 337: return "broodlands";
|
|
||||||
case 338: return "stillmoona";
|
|
||||||
case 339: return "stillmoonb";
|
|
||||||
case 340: return "thundercrest";
|
|
||||||
case 341: return "delvea";
|
|
||||||
case 342: return "delveb";
|
|
||||||
case 343: return "thenest";
|
|
||||||
case 344: return "guildlobby";
|
|
||||||
case 345: return "guildhall";
|
|
||||||
case 346: return "barter";
|
|
||||||
case 347: return "illsalin";
|
|
||||||
case 348: return "illsalina";
|
|
||||||
case 349: return "illsalinb";
|
|
||||||
case 350: return "illsalinc";
|
|
||||||
case 351: return "dreadspire";
|
|
||||||
case 354: return "drachnidhive";
|
|
||||||
case 355: return "drachnidhivea";
|
|
||||||
case 356: return "drachnidhiveb";
|
|
||||||
case 357: return "drachnidhivec";
|
|
||||||
case 358: return "westkorlach";
|
|
||||||
case 359: return "westkorlacha";
|
|
||||||
case 360: return "westkorlachb";
|
|
||||||
case 361: return "westkorlachc";
|
|
||||||
case 362: return "eastkorlach";
|
|
||||||
case 363: return "eastkorlacha";
|
|
||||||
case 364: return "shadowspine";
|
|
||||||
case 365: return "corathus";
|
|
||||||
case 366: return "corathusa";
|
|
||||||
case 367: return "corathusb";
|
|
||||||
case 368: return "nektulosa";
|
|
||||||
case 369: return "arcstone";
|
|
||||||
case 370: return "relic";
|
|
||||||
case 371: return "skylance";
|
|
||||||
case 372: return "devastation";
|
|
||||||
case 373: return "devastationa";
|
|
||||||
case 374: return "rage";
|
|
||||||
case 375: return "ragea";
|
|
||||||
case 376: return "takishruins";
|
|
||||||
case 377: return "takishruinsa";
|
|
||||||
case 378: return "elddar";
|
|
||||||
case 379: return "elddara";
|
|
||||||
case 380: return "theater";
|
|
||||||
case 381: return "theatera";
|
|
||||||
case 382: return "freeporteast";
|
|
||||||
case 383: return "freeportwest";
|
|
||||||
case 384: return "freeportsewers";
|
|
||||||
case 385: return "freeportacademy";
|
|
||||||
case 386: return "freeporttemple";
|
|
||||||
case 387: return "freeportmilitia";
|
|
||||||
case 388: return "freeportarena";
|
|
||||||
case 389: return "freeportcityhall";
|
|
||||||
case 390: return "freeporttheater";
|
|
||||||
case 391: return "freeporthall";
|
|
||||||
case 392: return "northro";
|
|
||||||
case 393: return "southro";
|
|
||||||
case 394: return "crescent";
|
|
||||||
case 395: return "moors";
|
|
||||||
case 396: return "stonehive";
|
|
||||||
case 397: return "mesa";
|
|
||||||
case 398: return "roost";
|
|
||||||
case 399: return "steppes";
|
|
||||||
case 400: return "icefall";
|
|
||||||
case 401: return "valdeholm";
|
|
||||||
case 402: return "frostcrypt";
|
|
||||||
case 403: return "sunderock";
|
|
||||||
case 404: return "vergalid";
|
|
||||||
case 405: return "direwind";
|
|
||||||
case 406: return "ashengate";
|
|
||||||
case 407: return "highpasshold";
|
|
||||||
case 408: return "commonlands";
|
|
||||||
case 409: return "oceanoftears";
|
|
||||||
case 410: return "kithforest";
|
|
||||||
case 411: return "befallenb";
|
|
||||||
case 412: return "highpasskeep";
|
|
||||||
case 413: return "innothuleb";
|
|
||||||
case 414: return "toxxulia";
|
|
||||||
case 415: return "mistythicket";
|
|
||||||
case 416: return "kattacastrum";
|
|
||||||
case 417: return "thalassius";
|
|
||||||
case 418: return "atiiki";
|
|
||||||
case 419: return "zhisza";
|
|
||||||
case 420: return "silyssar";
|
|
||||||
case 421: return "solteris";
|
|
||||||
case 422: return "barren";
|
|
||||||
case 423: return "buriedsea";
|
|
||||||
case 424: return "jardelshook";
|
|
||||||
case 425: return "monkeyrock";
|
|
||||||
case 426: return "suncrest";
|
|
||||||
case 427: return "deadbone";
|
|
||||||
case 428: return "blacksail";
|
|
||||||
case 429: return "maidensgrave";
|
|
||||||
case 430: return "redfeather";
|
|
||||||
case 431: return "shipmvp";
|
|
||||||
case 432: return "shipmvu";
|
|
||||||
case 433: return "shippvu";
|
|
||||||
case 434: return "shipuvu";
|
|
||||||
case 435: return "shipmvm";
|
|
||||||
case 436: return "mechanotus";
|
|
||||||
case 437: return "mansion";
|
|
||||||
case 438: return "steamfactory";
|
|
||||||
case 439: return "shipworkshop";
|
|
||||||
case 440: return "gyrospireb";
|
|
||||||
case 441: return "gyrospirez";
|
|
||||||
case 442: return "dragonscale";
|
|
||||||
case 443: return "lopingplains";
|
|
||||||
case 444: return "hillsofshade";
|
|
||||||
case 445: return "bloodmoon";
|
|
||||||
case 446: return "crystallos";
|
|
||||||
case 447: return "guardian";
|
|
||||||
case 448: return "steamfontmts";
|
|
||||||
case 449: return "cryptofshade";
|
|
||||||
case 451: return "dragonscaleb";
|
|
||||||
case 452: return "oldfieldofbone";
|
|
||||||
case 453: return "oldkaesoraa";
|
|
||||||
case 454: return "oldkaesorab";
|
|
||||||
case 455: return "oldkurn";
|
|
||||||
case 456: return "oldkithicor";
|
|
||||||
case 457: return "oldcommons";
|
|
||||||
case 458: return "oldhighpass";
|
|
||||||
case 459: return "thevoida";
|
|
||||||
case 460: return "thevoidb";
|
|
||||||
case 461: return "thevoidc";
|
|
||||||
case 462: return "thevoidd";
|
|
||||||
case 463: return "thevoide";
|
|
||||||
case 464: return "thevoidf";
|
|
||||||
case 465: return "thevoidg";
|
|
||||||
case 466: return "oceangreenhills";
|
|
||||||
case 467: return "oceangreenvillage";
|
|
||||||
case 468: return "oldblackburrow";
|
|
||||||
case 469: return "bertoxtemple";
|
|
||||||
case 470: return "discord";
|
|
||||||
case 471: return "discordtower";
|
|
||||||
case 472: return "oldbloodfield";
|
|
||||||
case 473: return "precipiceofwar";
|
|
||||||
case 474: return "olddranik";
|
|
||||||
case 475: return "toskirakk";
|
|
||||||
case 476: return "korascian";
|
|
||||||
case 477: return "rathechamber";
|
|
||||||
case 480: return "brellsrest";
|
|
||||||
case 481: return "fungalforest";
|
|
||||||
case 482: return "underquarry";
|
|
||||||
case 483: return "coolingchamber";
|
|
||||||
case 484: return "shiningcity";
|
|
||||||
case 485: return "arthicrex";
|
|
||||||
case 486: return "foundation";
|
|
||||||
case 487: return "lichencreep";
|
|
||||||
case 488: return "pellucid";
|
|
||||||
case 489: return "stonesnake";
|
|
||||||
case 490: return "brellstemple";
|
|
||||||
case 491: return "convorteum";
|
|
||||||
case 492: return "brellsarena";
|
|
||||||
case 493: return "weddingchapel";
|
|
||||||
case 494: return "weddingchapeldark";
|
|
||||||
case 495: return "dragoncrypt";
|
|
||||||
case 700: return "feerrott2";
|
|
||||||
case 701: return "thulehouse1";
|
|
||||||
case 702: return "thulehouse2";
|
|
||||||
case 703: return "housegarden";
|
|
||||||
case 704: return "thulelibrary";
|
|
||||||
case 705: return "well";
|
|
||||||
case 706: return "fallen";
|
|
||||||
case 707: return "morellcastle";
|
|
||||||
case 708: return "somnium";
|
|
||||||
case 709: return "alkabormare";
|
|
||||||
case 710: return "miragulmare";
|
|
||||||
case 711: return "thuledream";
|
|
||||||
case 712: return "neighborhood";
|
|
||||||
case 724: return "argath";
|
|
||||||
case 725: return "arelis";
|
|
||||||
case 726: return "sarithcity";
|
|
||||||
case 727: return "rubak";
|
|
||||||
case 728: return "beastdomain";
|
|
||||||
case 729: return "resplendent";
|
|
||||||
case 730: return "pillarsalra";
|
|
||||||
case 731: return "windsong";
|
|
||||||
case 732: return "cityofbronze";
|
|
||||||
case 733: return "sepulcher";
|
|
||||||
case 734: return "eastsepulcher";
|
|
||||||
case 735: return "westsepulcher";
|
|
||||||
case 752: return "shardslanding";
|
|
||||||
case 753: return "xorbb";
|
|
||||||
case 754: return "kaelshard";
|
|
||||||
case 755: return "eastwastesshard";
|
|
||||||
case 756: return "crystalshard";
|
|
||||||
case 757: return "breedinggrounds";
|
|
||||||
case 758: return "eviltree";
|
|
||||||
case 759: return "grelleth";
|
|
||||||
case 760: return "chapterhouse";
|
|
||||||
case 996: return "arttest";
|
|
||||||
case 998: return "fhalls";
|
|
||||||
case 999: return "apprentice";
|
|
||||||
}
|
|
||||||
return "UNKNWN";
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
/* EQEMu: Everquest Server Emulator
|
|
||||||
Copyright (C) 2001-2013 EQEMu Development Team (http://eqemulator.net)
|
|
||||||
|
|
||||||
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; version 2 of the License.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
||||||
are required to give you total support for your newly bought product;
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __EQEMU_COMMON_BASE_DATA_H
|
|
||||||
#define __EQEMU_COMMON_BASE_DATA_H
|
|
||||||
|
|
||||||
struct BaseDataStruct
|
|
||||||
{
|
|
||||||
double base_hp;
|
|
||||||
double base_mana;
|
|
||||||
double base_end;
|
|
||||||
double unk1;
|
|
||||||
double unk2;
|
|
||||||
double hp_factor;
|
|
||||||
double mana_factor;
|
|
||||||
double endurance_factor;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
/* EQEMu: Everquest Server Emulator
|
|
||||||
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
|
||||||
|
|
||||||
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; version 2 of the License.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
||||||
are required to give you total support for your newly bought product;
|
|
||||||
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, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
#ifndef BODYTYPES_H
|
|
||||||
#define BODYTYPES_H
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
BT_Humanoid = 1,
|
|
||||||
BT_Lycanthrope = 2,
|
|
||||||
BT_Undead = 3,
|
|
||||||
BT_Giant = 4,
|
|
||||||
BT_Construct = 5,
|
|
||||||
BT_Extraplanar = 6,
|
|
||||||
BT_Magical = 7, //this name might be a bit off,
|
|
||||||
BT_SummonedUndead = 8,
|
|
||||||
BT_RaidGiant = 9,
|
|
||||||
// ...
|
|
||||||
BT_NoTarget = 11, //no name, can't target this bodytype
|
|
||||||
BT_Vampire = 12,
|
|
||||||
BT_Atenha_Ra = 13,
|
|
||||||
BT_Greater_Akheva = 14,
|
|
||||||
BT_Khati_Sha = 15,
|
|
||||||
BT_Seru = 16, //not confirmed....
|
|
||||||
BT_Zek = 19,
|
|
||||||
BT_Luggald = 20,
|
|
||||||
BT_Animal = 21,
|
|
||||||
BT_Insect = 22,
|
|
||||||
BT_Monster = 23,
|
|
||||||
BT_Summoned = 24, //Elemental?
|
|
||||||
BT_Plant = 25,
|
|
||||||
BT_Dragon = 26,
|
|
||||||
BT_Summoned2 = 27,
|
|
||||||
BT_Summoned3 = 28,
|
|
||||||
//29
|
|
||||||
BT_VeliousDragon = 30, //might not be a tight set
|
|
||||||
// ...
|
|
||||||
BT_Dragon3 = 32,
|
|
||||||
BT_Boxes = 33,
|
|
||||||
BT_Muramite = 34, //tribal dudes
|
|
||||||
// ...
|
|
||||||
BT_NoTarget2 = 60,
|
|
||||||
// ...
|
|
||||||
BT_SwarmPet = 63, //is this valid, or made up?
|
|
||||||
// ...
|
|
||||||
BT_InvisMan = 66, //no name, seen on 'InvisMan', can be /targeted
|
|
||||||
BT_Special = 67
|
|
||||||
} bodyType;
|
|
||||||
/* bodytypes above 64 make the mob not show up */
|
|
||||||
|
|
||||||
#endif
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user