diff --git a/.travis.yml b/.travis.yml
index 74e5701ae..9eda6fca6 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,15 +3,23 @@ compiler: gcc
sudo: false
addons:
apt:
+ sources:
+ - ubuntu-toolchain-r-test
packages:
+ - gcc-4.8
+ - g++-4.8
- libmysqlclient-dev
- libperl-dev
- libboost-dev
- liblua5.1-0-dev
- zlib1g-dev
+ - uuid-dev
+ - libssl-dev
+install:
+ - if [ "$CXX" = "g++" ]; then export CXX="g++-4.8" CC="gcc-4.8"; fi
script:
- - cmake -G "Unix Makefiles" -DEQEMU_BUILD_TESTS=ON -DEQEMU_ENABLE_BOTS=ON
- - make -j8
+ - cmake -G "Unix Makefiles" -DEQEMU_BUILD_TESTS=ON -DEQEMU_ENABLE_BOTS=ON -DEQEMU_BUILD_LOGIN=ON
+ - make -j2
- ./bin/tests
branches:
only:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ec126b241..b1d644b70 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -64,10 +64,26 @@ IF(MSVC)
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")
+ SET(SODIUM_INCLUDE_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/include")
+ IF(MSVC_VERSION GREATER 1800)
+ SET(SODIUM_LIBRARY_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/x64/Release/v140/dynamic")
+ ELSEIF(MSVC_VERSION EQUAL 1800)
+ SET(SODIUM_LIBRARY_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/x64/Release/v120/dynamic")
+ ELSE()
+ SET(SODIUM_LIBRARY_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/x64/Release/v110/dynamic")
+ ENDIF()
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")
+ SET(SODIUM_INCLUDE_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/include")
+ IF(MSVC_VERSION GREATER 1800)
+ SET(SODIUM_LIBRARY_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/Win32/Release/v140/dynamic")
+ ELSEIF(MSVC_VERSION EQUAL 1800)
+ SET(SODIUM_LIBRARY_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/Win32/Release/v120/dynamic")
+ ELSE()
+ SET(SODIUM_LIBRARY_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/Win32/Release/v110/dynamic")
+ ENDIF()
ENDIF(CMAKE_CL_64)
#disable CRT warnings on windows cause they're annoying as shit and we use C functions everywhere
@@ -254,6 +270,7 @@ 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_HC "Build the headless client." OFF)
OPTION(EQEMU_BUILD_TESTS "Build utility tests." OFF)
OPTION(EQEMU_BUILD_PERL "Build Perl parser." ON)
OPTION(EQEMU_BUILD_LUA "Build Lua parser." ON)
@@ -315,6 +332,30 @@ IF(EQEMU_BUILD_PERL)
INCLUDE_DIRECTORIES(SYSTEM "${PERL_INCLUDE_PATH}")
ENDIF(EQEMU_BUILD_PERL)
+SET(SERVER_LIBS common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} ${ZLIB_LIBRARY} libuv fmt)
+
+FIND_PACKAGE(Sodium REQUIRED)
+IF(SODIUM_FOUND)
+ OPTION(EQEMU_ENABLE_SECURITY "Use Encryption For TCP Connections" ON)
+ IF(EQEMU_ENABLE_SECURITY)
+ INCLUDE_DIRECTORIES(SYSTEM "${SODIUM_INCLUDE_DIRS}")
+ ADD_DEFINITIONS(-DENABLE_SECURITY)
+ SET(SERVER_LIBS ${SERVER_LIBS} ${SODIUM_LIBRARIES})
+ ENDIF()
+ENDIF()
+
+IF(WIN32)
+ SET(SERVER_LIBS ${SERVER_LIBS} "ws2_32" "psapi" "iphlpapi" "userenv")
+ENDIF()
+
+IF(UNIX)
+ SET(SERVER_LIBS ${SERVER_LIBS} ${CMAKE_DL_LIBS} "z" "m" "pthread")
+ IF(NOT DARWIN)
+ SET(SERVER_LIBS ${SERVER_LIBS} "rt")
+ ENDIF()
+ SET(SERVER_LIBS ${SERVER_LIBS} "uuid")
+ENDIF()
+
IF(EQEMU_BUILD_LUA)
FIND_PACKAGE(EQLua51 REQUIRED)
SET(Boost_USE_STATIC_LIBS OFF)
@@ -323,7 +364,8 @@ IF(EQEMU_BUILD_LUA)
SET(BOOST_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/boost")
FIND_PACKAGE(Boost REQUIRED)
- INCLUDE_DIRECTORIES(SYSTEM "${LUA_INCLUDE_DIR}" "${Boost_INCLUDE_DIRS}" "luabind")
+ INCLUDE_DIRECTORIES(SYSTEM "${LUA_INCLUDE_DIR}" "${Boost_INCLUDE_DIRS}")
+ INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/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)
@@ -331,15 +373,18 @@ IF(EQEMU_BUILD_LUA)
ENDIF(EQEMU_SANITIZE_LUA_LIBS)
ENDIF(EQEMU_BUILD_LUA)
-INCLUDE_DIRECTORIES(SYSTEM "${ZLIB_INCLUDE_DIRS}" "${MySQL_INCLUDE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/common/glm")
+INCLUDE_DIRECTORIES(SYSTEM "${ZLIB_INCLUDE_DIRS}")
+INCLUDE_DIRECTORIES(SYSTEM "${MySQL_INCLUDE_DIR}")
+INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/common/glm")
+INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/cereal")
+INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/libuv/include" )
+INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/libuv/src")
+INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/format")
-IF(EQEMU_BUILD_LUA)
- ADD_SUBDIRECTORY(luabind)
-ENDIF(EQEMU_BUILD_LUA)
-
-IF(EQEMU_BUILD_SERVER OR EQEMU_BUILD_LOGIN OR EQEMU_BUILD_TESTS)
+IF(EQEMU_BUILD_SERVER OR EQEMU_BUILD_LOGIN OR EQEMU_BUILD_TESTS OR EQEMU_BUILD_HC)
ADD_SUBDIRECTORY(common)
-ENDIF(EQEMU_BUILD_SERVER OR EQEMU_BUILD_LOGIN OR EQEMU_BUILD_TESTS)
+ ADD_SUBDIRECTORY(libs)
+ENDIF(EQEMU_BUILD_SERVER OR EQEMU_BUILD_LOGIN OR EQEMU_BUILD_TESTS OR EQEMU_BUILD_HC)
IF(EQEMU_BUILD_SERVER)
ADD_SUBDIRECTORY(shared_memory)
ADD_SUBDIRECTORY(world)
@@ -352,6 +397,10 @@ IF(EQEMU_BUILD_LOGIN)
ADD_SUBDIRECTORY(loginserver)
ENDIF(EQEMU_BUILD_LOGIN)
+IF(EQEMU_BUILD_HC)
+ ADD_SUBDIRECTORY(hc)
+ENDIF(EQEMU_BUILD_HC)
+
IF(EQEMU_BUILD_TESTS)
ADD_SUBDIRECTORY(tests)
ENDIF(EQEMU_BUILD_TESTS)
diff --git a/changelog.txt b/changelog.txt
index 7386c7602..8edf925b0 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,5 +1,27 @@
EQEMu Changelog (Started on Sept 24, 2003 15:50)
-------------------------------------------------------
+== 4/16/2017 ==
+KLS: Merge eqstream branch
+ -UDP client stack completely rewritten should both have better throughput and recover better (peq has had far fewer reports of desyncs).
+ -TCP Server to Server connection stack completely rewritten.
+ -Server connections reconnect much more reliably and quickly now.
+ -Now supports optional packet encryption via libsodium (https://download.libsodium.org/doc/).
+ -Protocol behind the tcp connections has changed (see breaking changes section).
+ -API significantly changed and should be easier to write new servers or handlers for.
+ -Telnet console connection has been separated out from the current port (see breaking changes section).
+ -Because of changes to the TCP stack, lsreconnect and echo have been disabled.
+ -The server tic rate has been changed to be approx 30 fps from 500+ fps.
+ -Changed how missiles and movement were calculated slightly to account for this (Missiles in particular are not perfect but close enough).
+
+ -Breaking changes:
+ -Users who use the cmake install feature should be aware that the install directory is now %cmake_install_dir%/bin instead of just %cmake_install_dir%/
+ -To support new features such as encryption the underlying protocol had to change... however some servers such as the public login server will be slow to change so we've included a compatibility layer for legacy login connections:
+ -You should add 1 to the login section of your configuration file when connecting to a server that is using the old protocol.
+ -The central eqemu login server uses the old protocol and probably will for the forseeable future so if your server is connecting to it be sure to add that tag to your configuration file in that section.
+ -Telnet no longer uses the same port as the Server to Server connection and because of this the tcp tag no longer has any effect on telnet connections.
+ -To enable telnet you need to add a telnet tag in the world section of configuration such as:
+
+
== 4/1/2017 ==
Akkadius: Cleaned up some of the NPC to NPC aggro code, only do aggro checks to other NPC's when the NPC is flagged for it
Akkadius: [Performance] Reworked how all log calls are made in the source
diff --git a/client_files/export/CMakeLists.txt b/client_files/export/CMakeLists.txt
index 6d0807e01..c24a01865 100644
--- a/client_files/export/CMakeLists.txt
+++ b/client_files/export/CMakeLists.txt
@@ -9,28 +9,8 @@ SET(export_headers
ADD_EXECUTABLE(export_client_files ${export_sources} ${export_headers})
-INSTALL(TARGETS export_client_files RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX})
+INSTALL(TARGETS export_client_files RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
-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)
+TARGET_LINK_LIBRARIES(export_client_files ${SERVER_LIBS})
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
diff --git a/client_files/import/CMakeLists.txt b/client_files/import/CMakeLists.txt
index 59e1a0ac4..0f779497c 100644
--- a/client_files/import/CMakeLists.txt
+++ b/client_files/import/CMakeLists.txt
@@ -9,28 +9,8 @@ SET(import_headers
ADD_EXECUTABLE(import_client_files ${import_sources} ${import_headers})
-INSTALL(TARGETS import_client_files RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX})
+INSTALL(TARGETS import_client_files RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
-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)
+TARGET_LINK_LIBRARIES(import_client_files ${SERVER_LIBS})
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
diff --git a/cmake/FindSodium.cmake b/cmake/FindSodium.cmake
new file mode 100644
index 000000000..3c5ae3467
--- /dev/null
+++ b/cmake/FindSodium.cmake
@@ -0,0 +1,30 @@
+if (NOT MSVC)
+include(FindPkgConfig)
+pkg_check_modules(PC_SODIUM "libsodium")
+if (NOT PC_SODIUM_FOUND)
+ pkg_check_modules(PC_SODIUM "sodium")
+endif (NOT PC_SODIUM_FOUND)
+if (PC_SODIUM_FOUND)
+ set(SODIUM_INCLUDE_HINTS ${PC_SODIUM_INCLUDE_DIRS} ${PC_SODIUM_INCLUDE_DIRS}/*)
+ set(SODIUM_LIBRARY_HINTS ${PC_SODIUM_LIBRARY_DIRS} ${PC_SODIUM_LIBRARY_DIRS}/*)
+endif()
+endif (NOT MSVC)
+
+# some libraries install the headers is a subdirectory of the include dir
+# returned by pkg-config, so use a wildcard match to improve chances of finding
+# headers and libraries.
+find_path(
+ SODIUM_INCLUDE_DIRS
+ NAMES sodium.h
+ HINTS ${SODIUM_INCLUDE_HINTS}
+)
+
+find_library(
+ SODIUM_LIBRARIES
+ NAMES libsodium sodium
+ HINTS ${SODIUM_LIBRARY_HINTS}
+)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(SODIUM DEFAULT_MSG SODIUM_LIBRARIES SODIUM_INCLUDE_DIRS)
+mark_as_advanced(SODIUM_FOUND SODIUM_LIBRARIES SODIUM_INCLUDE_DIRS)
diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt
index cecb47d12..06486d2db 100644
--- a/common/CMakeLists.txt
+++ b/common/CMakeLists.txt
@@ -16,8 +16,6 @@ SET(common_sources
emu_legacy.cpp
emu_limits.cpp
emu_opcodes.cpp
- emu_tcp_connection.cpp
- emu_tcp_server.cpp
emu_versions.cpp
eqdb.cpp
eqdb_res.cpp
@@ -26,11 +24,10 @@ SET(common_sources
eqemu_logsys.cpp
eq_limits.cpp
eq_packet.cpp
- eq_stream.cpp
- eq_stream_factory.cpp
eq_stream_ident.cpp
eq_stream_proxy.cpp
eqtime.cpp
+ event_sub.cpp
extprofile.cpp
faction.cpp
guild_base.cpp
@@ -40,6 +37,7 @@ SET(common_sources
ipc_mutex.cpp
item_data.cpp
item_instance.cpp
+ json_config.cpp
light_source.cpp
md5.cpp
memory_buffer.cpp
@@ -68,15 +66,25 @@ SET(common_sources
spdat.cpp
string_util.cpp
struct_strategy.cpp
- tcp_connection.cpp
- tcp_server.cpp
textures.cpp
- timeoutmgr.cpp
timer.cpp
unix.cpp
- worldconn.cpp
xml_parser.cpp
platform.cpp
+ event/event_loop.cpp
+ json/jsoncpp.cpp
+ net/console_server.cpp
+ net/console_server_connection.cpp
+ net/crc32.cpp
+ net/daybreak_connection.cpp
+ net/eqstream.cpp
+ net/packet.cpp
+ net/servertalk_client_connection.cpp
+ net/servertalk_legacy_client_connection.cpp
+ net/servertalk_server.cpp
+ net/servertalk_server_connection.cpp
+ net/tcp_connection.cpp
+ net/tcp_server.cpp
patches/patches.cpp
patches/sod.cpp
patches/sod_limits.cpp
@@ -90,22 +98,12 @@ SET(common_sources
patches/titanium_limits.cpp
patches/uf.cpp
patches/uf_limits.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
+ util/uuid.cpp
)
SET(common_headers
@@ -127,8 +125,6 @@ SET(common_headers
emu_limits.h
emu_opcodes.h
emu_oplist.h
- emu_tcp_connection.h
- emu_tcp_server.h
emu_versions.h
eq_constants.h
eq_packet_structs.h
@@ -140,15 +136,13 @@ SET(common_headers
eqemu_logsys.h
eq_limits.h
eq_packet.h
- eq_stream.h
- eq_stream_factory.h
eq_stream_ident.h
eq_stream_intf.h
eq_stream_locator.h
eq_stream_proxy.h
- eq_stream_type.h
eqtime.h
errmsg.h
+ event_sub.h
extprofile.h
faction.h
features.h
@@ -163,6 +157,7 @@ SET(common_headers
item_data.h
item_fieldlist.h
item_instance.h
+ json_config.h
languages.h
light_source.h
linked_list.h
@@ -201,19 +196,35 @@ SET(common_headers
spdat.h
string_util.h
struct_strategy.h
- tcp_basic_server.h
- tcp_connection.h
- tcp_server.h
textures.h
- timeoutmgr.h
timer.h
types.h
unix.h
useperl.h
version.h
- worldconn.h
xml_parser.h
zone_numbers.h
+ event/background_task.h
+ event/event_loop.h
+ event/timer.h
+ json/json.h
+ json/json-forwards.h
+ net/console_server.h
+ net/console_server_connection.h
+ net/crc32.h
+ net/daybreak_connection.h
+ net/daybreak_structs.h
+ net/dns.h
+ net/endian.h
+ net/eqstream.h
+ net/packet.h
+ net/servertalk_client_connection.h
+ net/servertalk_legacy_client_connection.h
+ net/servertalk_common.h
+ net/servertalk_server.h
+ net/servertalk_server_connection.h
+ net/tcp_connection.h
+ net/tcp_server.h
patches/patches.h
patches/sod.h
patches/sod_limits.h
@@ -242,21 +253,57 @@ SET(common_headers
patches/uf_limits.h
patches/uf_ops.h
patches/uf_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
+ util/memory_stream.h
+ util/uuid.h
+)
+
+SOURCE_GROUP(Event FILES
+ event/background_task.h
+ event/event_loop.cpp
+ event/event_loop.h
+ event/timer.h
+)
+
+SOURCE_GROUP(Json FILES
+ json/json.h
+ json/jsoncpp.cpp
+ json/json-forwards.h
+)
+
+SOURCE_GROUP(Net FILES
+ net/console_server.cpp
+ net/console_server.h
+ net/console_server_connection.cpp
+ net/console_server_connection.h
+ net/crc32.cpp
+ net/crc32.h
+ net/daybreak_connection.cpp
+ net/daybreak_connection.h
+ net/daybreak_structs.h
+ net/dns.h
+ net/endian.h
+ net/eqmq.cpp
+ net/eqmq.h
+ net/eqstream.cpp
+ net/eqstream.h
+ net/packet.cpp
+ net/packet.h
+ net/servertalk_client_connection.cpp
+ net/servertalk_client_connection.h
+ net/servertalk_legacy_client_connection.cpp
+ net/servertalk_legacy_client_connection.h
+ net/servertalk_common.h
+ net/servertalk_server.cpp
+ net/servertalk_server.h
+ net/servertalk_server_connection.cpp
+ net/servertalk_server_connection.h
+ net/tcp_connection.cpp
+ net/tcp_connection.h
+ net/tcp_server.cpp
+ net/tcp_server.h
)
SOURCE_GROUP(Patches FILES
@@ -303,32 +350,6 @@ SOURCE_GROUP(Patches FILES
patches/uf_limits.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
@@ -343,12 +364,17 @@ SOURCE_GROUP(TinyXML FILES
tinyxml/tinyxmlparser.cpp
)
+SOURCE_GROUP(Util FILES
+ util/memory_stream.h
+ util/uuid.cpp
+ util/uuid.h
+)
+
INCLUDE_DIRECTORIES(Patches SocketLib StackWalker TinyXML)
ADD_LIBRARY(common ${common_sources} ${common_headers})
IF(UNIX)
- ADD_DEFINITIONS(-fPIC)
SET_SOURCE_FILES_PROPERTIES("SocketLib/Mime.cpp" PROPERTY COMPILE_FLAGS -Wno-unused-result)
SET_SOURCE_FILES_PROPERTIES("patches/sod.cpp" "patches/sof.cpp" "patches/rof.cpp" "patches/rof2.cpp" "patches/uf.cpp" PROPERTIES COMPILE_FLAGS -O0)
ENDIF(UNIX)
diff --git a/common/bodytypes.h b/common/bodytypes.h
index 804506e7a..fd64b1825 100644
--- a/common/bodytypes.h
+++ b/common/bodytypes.h
@@ -35,6 +35,7 @@ typedef enum {
BT_Greater_Akheva = 14,
BT_Khati_Sha = 15,
BT_Seru = 16, //not confirmed....
+ BT_Draz_Nurakk = 18,
BT_Zek = 19,
BT_Luggald = 20,
BT_Animal = 21,
diff --git a/common/emu_tcp_connection.cpp b/common/emu_tcp_connection.cpp
deleted file mode 100644
index 0a0444c69..000000000
--- a/common/emu_tcp_connection.cpp
+++ /dev/null
@@ -1,818 +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/global_define.h"
-
-#include
-#include
-
-#include "emu_tcp_connection.h"
-#include "emu_tcp_server.h"
-#include "../common/servertalk.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 = Incoming;
- 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
- auto 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) {
- auto 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 {
- auto 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 {
- auto 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 != Incoming) {
- 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 != Incoming) {
- SendNetErrorPacket("New RelayClient: illegal on outgoing connection");
- break;
- }
- auto 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 == Incoming) {
- 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()) {
- auto 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);
-}
-
diff --git a/common/emu_tcp_connection.h b/common/emu_tcp_connection.h
deleted file mode 100644
index 7f4d0710b..000000000
--- a/common/emu_tcp_connection.h
+++ /dev/null
@@ -1,104 +0,0 @@
-#ifndef EmuTCPCONNECTION_H_
-#define EmuTCPCONNECTION_H_
-
-#include "tcp_connection.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 ServerPacket;
-
-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 InModeQueue;
-
- //output queue...
- MyQueue OutQueue;
- Mutex MOutQueueLock;
-};
-
-#endif /*EmuTCPCONNECTION_H_*/
-
-
-
diff --git a/common/emu_tcp_server.cpp b/common/emu_tcp_server.cpp
deleted file mode 100644
index 00a241859..000000000
--- a/common/emu_tcp_server.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-#include "global_define.h"
-#include "emu_tcp_server.h"
-#include "emu_tcp_connection.h"
-
-EmuTCPServer::EmuTCPServer(uint16 iPort, bool iOldFormat)
-: TCPServer(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::Process();
-}
-
-void EmuTCPServer::CreateNewConnection(uint32 ID, SOCKET in_socket, uint32 irIP, uint16 irPort)
-{
- auto 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);
-}
-
diff --git a/common/emu_tcp_server.h b/common/emu_tcp_server.h
deleted file mode 100644
index 8941812ad..000000000
--- a/common/emu_tcp_server.h
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef EmuTCPSERVER_H_
-#define EmuTCPSERVER_H_
-
-#include "tcp_server.h"
-
-class EmuTCPConnection;
-struct EmuTCPNetPacket_Struct;
-class ServerPacket;
-
-class EmuTCPServer : public TCPServer {
-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::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 m_InQueue;
-};
-#endif /*EmuTCPSERVER_H_*/
diff --git a/common/eq_packet.cpp b/common/eq_packet.cpp
index d7e607d77..f5c08a301 100644
--- a/common/eq_packet.cpp
+++ b/common/eq_packet.cpp
@@ -132,7 +132,7 @@ 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);
+ sprintf(buffer, "[OpCode %s(0x%04x) Size=%u]",OpcodeManager::EmuToName(emu_opcode), GetProtocolOpcode(), size);
#endif
}
diff --git a/common/eq_packet.h b/common/eq_packet.h
index 94c8a1e10..1fea3b9d1 100644
--- a/common/eq_packet.h
+++ b/common/eq_packet.h
@@ -115,11 +115,14 @@ public:
virtual void DumpRawHeader(uint16 seq=0xffff, FILE *to = stdout) const;
virtual void DumpRawHeaderNoTime(uint16 seq=0xffff, FILE *to = stdout) const;
- uint16 GetOpcodeBypass() { return opcode_bypass; }
+ uint16 GetOpcodeBypass() const { return opcode_bypass; }
void SetOpcodeBypass(uint16 v) { opcode_bypass = v; }
+ uint16 GetProtocolOpcode() const { return protocol_opcode; }
+ void SetProtocolOpcode(uint16 v) { protocol_opcode = v; }
protected:
+ uint16 protocol_opcode;
uint8 app_opcode_size;
uint16 opcode_bypass;
private:
diff --git a/common/eq_stream.cpp b/common/eq_stream.cpp
index 5ae6c15f1..96b816b1f 100644
--- a/common/eq_stream.cpp
+++ b/common/eq_stream.cpp
@@ -529,7 +529,7 @@ void EQStream::FastQueuePacket(EQApplicationPacket **p, bool ack_req)
if(pack->GetOpcodeBypass() != 0) {
opcode = pack->GetOpcodeBypass();
} else {
- opcode = (*OpMgr)->EmuToEQ(pack->emu_opcode);
+ opcode = (*OpMgr)->EmuToEQ(pack->GetOpcode());
}
if (!ack_req) {
diff --git a/common/eq_stream.h b/common/eq_stream.h
index d5e78c085..6f43cc337 100644
--- a/common/eq_stream.h
+++ b/common/eq_stream.h
@@ -241,7 +241,7 @@ class EQStream : public EQStreamInterface {
virtual bool CheckState(EQStreamState state) { return GetState() == state; }
virtual std::string Describe() const { return("Direct EQStream"); }
- void SetOpcodeManager(OpcodeManager **opm) { OpMgr = opm; }
+ virtual void SetOpcodeManager(OpcodeManager **opm) { OpMgr = opm; }
void CheckTimeout(uint32 now, uint32 timeout=30);
bool HasOutgoingData();
@@ -250,13 +250,13 @@ class EQStream : public EQStreamInterface {
void Write(int eq_fd);
// whether or not the stream has been assigned (we passed our stream match)
- void SetActive(bool val) { streamactive = val; }
+ virtual void SetActive(bool val) { streamactive = val; }
//
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; }
+ virtual EQStreamState GetState() { EQStreamState s; MState.lock(); s=State; MState.unlock(); return s; }
static SeqOrder CompareSequence(uint16 expected_seq , uint16 seq);
@@ -306,19 +306,7 @@ class EQStream : public EQStreamInterface {
const uint64 GetPacketsReceived() { return received_packet_count; }
//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);
+ virtual MatchState CheckSignature(const Signature *sig);
};
diff --git a/common/eq_stream_ident.cpp b/common/eq_stream_ident.cpp
index 83cd11133..5706bbced 100644
--- a/common/eq_stream_ident.cpp
+++ b/common/eq_stream_ident.cpp
@@ -4,7 +4,7 @@
#include "eqemu_logsys.h"
#include "eq_stream_ident.h"
#include "eq_stream_proxy.h"
-
+#include "misc.h"
EQStreamIdentifier::~EQStreamIdentifier() {
while(!m_identified.empty()) {
@@ -26,7 +26,7 @@ EQStreamIdentifier::~EQStreamIdentifier() {
}
}
-void EQStreamIdentifier::RegisterPatch(const EQStream::Signature &sig, const char *name, OpcodeManager ** opcodes, const StructStrategy *structs) {
+void EQStreamIdentifier::RegisterPatch(const EQStreamInterface::Signature &sig, const char *name, OpcodeManager ** opcodes, const StructStrategy *structs) {
auto p = new Patch;
p->signature = sig;
p->name = name;
@@ -46,9 +46,9 @@ void EQStreamIdentifier::Process() {
//first see if this stream has expired
if(r.expire.Check(false)) {
- //this stream has failed to match any pattern in our timeframe.
- Log(Logs::General, Logs::Netcode, "[IDENTIFY] Unable to identify stream from %s:%d before timeout.", long2ip(r.stream->GetRemoteIP()).c_str(), ntohs(r.stream->GetRemotePort()));
- r.stream->ReleaseFromUse();
+ Log(Logs::General, Logs::Netcode, "[IDENTIFY] Unable to identify stream from %s:%d before timeout.", r.stream->GetRemoteAddr().c_str(), ntohs(r.stream->GetRemotePort()));
+ r.stream->Close();
+
cur = m_streams.erase(cur);
continue;
}
@@ -98,14 +98,14 @@ void EQStreamIdentifier::Process() {
Patch *p = *curp;
//ask the stream to see if it matches the supplied signature
- EQStream::MatchState res = r.stream->CheckSignature(&p->signature);
+ EQStreamInterface::MatchState res = r.stream->CheckSignature(&p->signature);
switch(res) {
- case EQStream::MatchNotReady:
+ case EQStreamInterface::MatchNotReady:
//the stream has not received enough packets to compare with this signature
// Log.LogDebugType(Logs::General, Logs::Netcode, "[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: {
+ case EQStreamInterface::MatchSuccessful: {
//yay, a match.
Log(Logs::General, Logs::Netcode, "[IDENTIFY] Identified stream %s:%d with signature %s", long2ip(r.stream->GetRemoteIP()).c_str(), ntohs(r.stream->GetRemotePort()), p->name.c_str());
@@ -120,7 +120,7 @@ void EQStreamIdentifier::Process() {
found_one = true;
break;
}
- case EQStream::MatchFailed:
+ case EQStreamInterface::MatchFailed:
//do nothing...
Log(Logs::General, Logs::Netcode, "[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;
@@ -144,7 +144,7 @@ void EQStreamIdentifier::Process() {
} //end foreach stream
}
-void EQStreamIdentifier::AddStream(std::shared_ptr &eqs) {
+void EQStreamIdentifier::AddStream(std::shared_ptr eqs) {
m_streams.push_back(Record(eqs));
eqs = nullptr;
}
@@ -157,7 +157,7 @@ EQStreamInterface *EQStreamIdentifier::PopIdentified() {
return(res);
}
-EQStreamIdentifier::Record::Record(std::shared_ptr s)
+EQStreamIdentifier::Record::Record(std::shared_ptr s)
: stream(std::move(s)),
expire(STREAM_IDENT_WAIT_MS)
{
diff --git a/common/eq_stream_ident.h b/common/eq_stream_ident.h
index 3b6a63ed9..483d48372 100644
--- a/common/eq_stream_ident.h
+++ b/common/eq_stream_ident.h
@@ -1,13 +1,13 @@
#ifndef EQSTREAMIDENT_H_
#define EQSTREAMIDENT_H_
-#include "eq_stream.h"
+#include "eq_stream_intf.h"
#include "timer.h"
#include
#include
#include
-#define STREAM_IDENT_WAIT_MS 10000
+#define STREAM_IDENT_WAIT_MS 30000
class OpcodeManager;
class StructStrategy;
@@ -18,11 +18,11 @@ public:
~EQStreamIdentifier();
//registration interface.
- void RegisterPatch(const EQStream::Signature &sig, const char *name, OpcodeManager ** opcodes, const StructStrategy *structs);
+ void RegisterPatch(const EQStreamInterface::Signature &sig, const char *name, OpcodeManager ** opcodes, const StructStrategy *structs);
//main processing interface
void Process();
- void AddStream(std::shared_ptr &eqs);
+ void AddStream(std::shared_ptr eqs);
EQStreamInterface *PopIdentified();
protected:
@@ -31,7 +31,7 @@ protected:
class Patch {
public:
std::string name;
- EQStream::Signature signature;
+ EQStreamInterface::Signature signature;
OpcodeManager ** opcodes;
const StructStrategy *structs;
};
@@ -40,8 +40,8 @@ protected:
//pending streams..
class Record {
public:
- Record(std::shared_ptr s);
- std::shared_ptr stream; //we own this
+ Record(std::shared_ptr s);
+ std::shared_ptr stream; //we own this
Timer expire;
};
std::vector m_streams; //we own these objects, and the streams contained in them.
diff --git a/common/eq_stream_intf.h b/common/eq_stream_intf.h
index 917a13a86..c65ae9348 100644
--- a/common/eq_stream_intf.h
+++ b/common/eq_stream_intf.h
@@ -5,6 +5,7 @@
#include
#include "emu_versions.h"
+#include "eq_packet.h"
typedef enum {
ESTABLISHED,
@@ -15,21 +16,40 @@ typedef enum {
} EQStreamState;
class EQApplicationPacket;
+class OpcodeManager;
class EQStreamInterface {
public:
virtual ~EQStreamInterface() {}
+ 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;
+
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 std::string GetRemoteAddr() const = 0;
virtual uint32 GetRemoteIP() const = 0;
virtual uint16 GetRemotePort() const = 0;
virtual bool CheckState(EQStreamState state) = 0;
virtual std::string Describe() const = 0;
+ virtual void SetActive(bool val) { }
+ virtual MatchState CheckSignature(const Signature *sig) { return MatchFailed; }
+ virtual EQStreamState GetState() = 0;
+ virtual void SetOpcodeManager(OpcodeManager **opm) = 0;
virtual const uint32 GetBytesSent() const { return 0; }
virtual const uint32 GetBytesRecieved() const { return 0; }
diff --git a/common/eq_stream_proxy.cpp b/common/eq_stream_proxy.cpp
index 0c41988e4..7fb4c9432 100644
--- a/common/eq_stream_proxy.cpp
+++ b/common/eq_stream_proxy.cpp
@@ -1,11 +1,10 @@
#include "global_define.h"
#include "eq_stream_proxy.h"
-#include "eq_stream.h"
#include "struct_strategy.h"
-EQStreamProxy::EQStreamProxy(std::shared_ptr &stream, const StructStrategy *structs, OpcodeManager **opcodes)
+EQStreamProxy::EQStreamProxy(std::shared_ptr &stream, const StructStrategy *structs, OpcodeManager **opcodes)
: m_stream(stream),
m_structs(structs),
m_opcodes(opcodes)
@@ -26,6 +25,16 @@ const EQEmu::versions::ClientVersion EQStreamProxy::ClientVersion() const
return m_structs->ClientVersion();
}
+EQStreamState EQStreamProxy::GetState()
+{
+ return m_stream->GetState();
+}
+
+void EQStreamProxy::SetOpcodeManager(OpcodeManager **opm)
+{
+ return m_stream->SetOpcodeManager(opm);
+}
+
void EQStreamProxy::QueuePacket(const EQApplicationPacket *p, bool ack_req) {
if(p == nullptr)
return;
@@ -54,6 +63,10 @@ void EQStreamProxy::Close() {
m_stream->Close();
}
+std::string EQStreamProxy::GetRemoteAddr() const {
+ return(m_stream->GetRemoteAddr());
+}
+
uint32 EQStreamProxy::GetRemoteIP() const {
return(m_stream->GetRemoteIP());
}
diff --git a/common/eq_stream_proxy.h b/common/eq_stream_proxy.h
index def543b34..5e01c8cf0 100644
--- a/common/eq_stream_proxy.h
+++ b/common/eq_stream_proxy.h
@@ -4,7 +4,6 @@
#include "types.h"
#include "eq_stream_intf.h"
-#include "eq_stream.h"
#include
class StructStrategy;
@@ -14,7 +13,7 @@ class EQApplicationPacket;
class EQStreamProxy : public EQStreamInterface {
public:
//takes ownership of the stream.
- EQStreamProxy(std::shared_ptr &stream, const StructStrategy *structs, OpcodeManager **opcodes);
+ EQStreamProxy(std::shared_ptr &stream, const StructStrategy *structs, OpcodeManager **opcodes);
virtual ~EQStreamProxy();
//EQStreamInterface:
@@ -22,6 +21,7 @@ public:
virtual void FastQueuePacket(EQApplicationPacket **p, bool ack_req=true);
virtual EQApplicationPacket *PopPacket();
virtual void Close();
+ virtual std::string GetRemoteAddr() const;
virtual uint32 GetRemoteIP() const;
virtual uint16 GetRemotePort() const;
virtual void ReleaseFromUse();
@@ -29,6 +29,8 @@ public:
virtual bool CheckState(EQStreamState state);
virtual std::string Describe() const;
virtual const EQEmu::versions::ClientVersion ClientVersion() const;
+ virtual EQStreamState GetState();
+ virtual void SetOpcodeManager(OpcodeManager **opm);
virtual const uint32 GetBytesSent() const;
virtual const uint32 GetBytesRecieved() const;
@@ -36,8 +38,8 @@ public:
virtual const uint32 GetBytesRecvPerSecond() const;
protected:
- std::shared_ptr const m_stream; //we own this stream object.
- const StructStrategy *const m_structs; //we do not own this object.
+ std::shared_ptr 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.
diff --git a/common/eqemu_config.cpp b/common/eqemu_config.cpp
index 900b83787..96980f834 100644
--- a/common/eqemu_config.cpp
+++ b/common/eqemu_config.cpp
@@ -66,6 +66,10 @@ void EQEmuConfig::do_world(TiXmlElement *ele)
if (text) {
LoginPort = atoi(text);
}
+ text = ParseTextBlock(sub_ele, "legacy", true);
+ if (text) {
+ LoginLegacy = atoi(text) > 0 ? true : false;
+ }
text = ParseTextBlock(sub_ele, "account", true);
if (text) {
LoginAccount = text;
@@ -89,6 +93,10 @@ void EQEmuConfig::do_world(TiXmlElement *ele)
if (text) {
loginconfig->LoginPort = atoi(text);
}
+ text = ParseTextBlock(sub_ele, "legacy", true);
+ if (text) {
+ loginconfig->LoginLegacy = atoi(text) > 0 ? true : false;
+ }
text = ParseTextBlock(sub_ele, "account", true);
if (text) {
loginconfig->LoginAccount = text;
@@ -117,11 +125,24 @@ void EQEmuConfig::do_world(TiXmlElement *ele)
if (text) {
WorldTCPPort = atoi(text);
}
- text = sub_ele->Attribute("telnet");
- if (text && !strcasecmp(text, "enabled")) {
+ }
+
+ sub_ele = ele->FirstChildElement("telnet");
+ if (sub_ele != nullptr) {
+ text = sub_ele->Attribute("ip");
+ if (text) {
+ TelnetIP = text;
+ }
+ text = sub_ele->Attribute("port");
+ if (text) {
+ TelnetTCPPort = atoi(text);
+ }
+ text = sub_ele->Attribute("enabled");
+ if (text && !strcasecmp(text, "true")) {
TelnetEnabled = true;
}
}
+
// Get the element
sub_ele = ele->FirstChildElement("http");
if (sub_ele != nullptr) {
@@ -370,6 +391,9 @@ std::string EQEmuConfig::GetByName(const std::string &var_name) const
if (var_name == "LoginPort") {
return (itoa(LoginPort));
}
+ if (var_name == "LoginLegacy") {
+ return (itoa(LoginLegacy ? 1 : 0));
+ }
if (var_name == "Locked") {
return (Locked ? "true" : "false");
}
@@ -379,6 +403,12 @@ std::string EQEmuConfig::GetByName(const std::string &var_name) const
if (var_name == "WorldIP") {
return (WorldIP);
}
+ if (var_name == "TelnetTCPPort") {
+ return (itoa(TelnetTCPPort));
+ }
+ if (var_name == "TelnetIP") {
+ return (TelnetIP);
+ }
if (var_name == "TelnetEnabled") {
return (TelnetEnabled ? "true" : "false");
}
@@ -495,9 +525,12 @@ void EQEmuConfig::Dump() const
std::cout << "LoginAccount = " << LoginAccount << std::endl;
std::cout << "LoginPassword = " << LoginPassword << std::endl;
std::cout << "LoginPort = " << LoginPort << std::endl;
+ std::cout << "LoginLegacy = " << LoginLegacy << std::endl;
std::cout << "Locked = " << Locked << std::endl;
std::cout << "WorldTCPPort = " << WorldTCPPort << std::endl;
std::cout << "WorldIP = " << WorldIP << std::endl;
+ std::cout << "TelnetTCPPort = " << TelnetTCPPort << std::endl;
+ std::cout << "TelnetIP = " << TelnetIP << std::endl;
std::cout << "TelnetEnabled = " << TelnetEnabled << std::endl;
std::cout << "WorldHTTPPort = " << WorldHTTPPort << std::endl;
std::cout << "WorldHTTPMimeFile = " << WorldHTTPMimeFile << std::endl;
diff --git a/common/eqemu_config.h b/common/eqemu_config.h
index 58b1bee9b..0f51f550f 100644
--- a/common/eqemu_config.h
+++ b/common/eqemu_config.h
@@ -26,6 +26,7 @@ struct LoginConfig {
std::string LoginAccount;
std::string LoginPassword;
uint16 LoginPort;
+ bool LoginLegacy;
};
class EQEmuConfig : public XMLParser
@@ -42,11 +43,14 @@ class EQEmuConfig : public XMLParser
std::string LoginAccount;
std::string LoginPassword;
uint16 LoginPort;
+ bool LoginLegacy;
uint32 LoginCount;
LinkedList loginlist;
bool Locked;
uint16 WorldTCPPort;
std::string WorldIP;
+ uint16 TelnetTCPPort;
+ std::string TelnetIP;
bool TelnetEnabled;
int32 MaxClients;
bool WorldHTTPEnabled;
@@ -127,11 +131,13 @@ class EQEmuConfig : public XMLParser
#include "eqemu_config_elements.h"
// Set sane defaults
// Login server
- LoginHost = "eqemulator.net";
+ LoginHost = "login.eqemulator.net";
LoginPort = 5998;
+ LoginLegacy = false;
// World
Locked = false;
WorldTCPPort = 9000;
+ TelnetTCPPort = 9001;
TelnetEnabled = false;
WorldHTTPEnabled = false;
WorldHTTPPort = 9080;
@@ -186,6 +192,7 @@ class EQEmuConfig : public XMLParser
DefaultStatus = 0;
// For where zones need to connect to.
WorldIP = "127.0.0.1";
+ TelnetIP = "127.0.0.1";
// Dynamics to start
//DynamicCount=5;
MaxClients = -1;
diff --git a/common/eqemu_logsys.cpp b/common/eqemu_logsys.cpp
index f3bbe2527..a14a27a1b 100644
--- a/common/eqemu_logsys.cpp
+++ b/common/eqemu_logsys.cpp
@@ -103,6 +103,7 @@ void EQEmuLogSys::LoadLogSettingsDefaults()
log_settings[Logs::Crash].log_to_console = Logs::General;
log_settings[Logs::MySQLError].log_to_console = Logs::General;
log_settings[Logs::Login_Server].log_to_console = Logs::General;
+ log_settings[Logs::Headless_Client].log_to_console = Logs::General;
/* Set Category enabled status on defaults */
log_settings[Logs::World_Server].is_category_enabled = 1;
@@ -128,6 +129,8 @@ void EQEmuLogSys::LoadLogSettingsDefaults()
platform_file_name = "login";
else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformLaunch)
platform_file_name = "launcher";
+ else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformHC)
+ platform_file_name = "hc";
}
std::string EQEmuLogSys::FormatOutMessageString(uint16 log_category, const std::string &in_message)
diff --git a/common/eqemu_logsys.h b/common/eqemu_logsys.h
index 71a270322..ed821831a 100644
--- a/common/eqemu_logsys.h
+++ b/common/eqemu_logsys.h
@@ -20,11 +20,11 @@
#ifndef EQEMU_LOGSYS_H
#define EQEMU_LOGSYS_H
+#include
#include
#include
#include
#include
-
#include "types.h"
namespace Logs {
@@ -85,6 +85,7 @@ enum LogCategory {
Client_Server_Packet_With_Dump,
Login_Server,
Client_Login,
+ Headless_Client,
MaxCategoryID /* Don't Remove this*/
};
@@ -143,6 +144,11 @@ static const char* LogCategoryName[LogCategory::MaxCategoryID] = {
LogSys.Out(debug_level, log_category, message, ##__VA_ARGS__);\
} while (0)
+#define LogF(debug_level, log_category, message, ...) do {\
+ if (LogSys.log_settings[log_category].is_category_enabled == 1)\
+ LogSys.OutF(debug_level, log_category, message, ##__VA_ARGS__);\
+} while (0)
+
class EQEmuLogSys {
public:
EQEmuLogSys();
@@ -164,6 +170,13 @@ public:
void SetCurrentTimeStamp(char* time_stamp); /* Used in file logs to prepend a timestamp entry for logs */
void StartFileLogs(const std::string &log_name = ""); /* Used to declare the processes file log and to keep it open for later use */
+ template
+ void OutF(Logs::DebugLevel debug_level, uint16 log_category, const char *fmt, const Args&... args)
+ {
+ std::string log_str = fmt::format(fmt, args...);
+ Out(debug_level, log_category, log_str);
+ }
+
/*
LogSettings Struct
@@ -204,9 +217,9 @@ private:
uint16 GetWindowsConsoleColorFromCategory(uint16 log_category); /* Windows console color messages mapped by category */
- void ProcessConsoleMessage(uint16 debug_level, uint16 log_category, const std::string &message); /* ProcessConsoleMessage called via Log.Out */
- void ProcessGMSay(uint16 debug_level, uint16 log_category, const std::string &message); /* ProcessGMSay called via Log.Out */
- void ProcessLogWrite(uint16 debug_level, uint16 log_category, const std::string &message); /* ProcessLogWrite called via Log.Out */
+ void ProcessConsoleMessage(uint16 debug_level, uint16 log_category, const std::string &message); /* ProcessConsoleMessage called via Log */
+ void ProcessGMSay(uint16 debug_level, uint16 log_category, const std::string &message); /* ProcessGMSay called via Log */
+ void ProcessLogWrite(uint16 debug_level, uint16 log_category, const std::string &message); /* ProcessLogWrite called via Log */
};
extern EQEmuLogSys LogSys;
diff --git a/common/event/background_task.h b/common/event/background_task.h
new file mode 100644
index 000000000..8082abaf3
--- /dev/null
+++ b/common/event/background_task.h
@@ -0,0 +1,39 @@
+#pragma once
+#include
+#include "event_loop.h"
+
+namespace EQ {
+ class BackgroundTask
+ {
+ public:
+ typedef std::function BackgroundTaskFunction;
+ struct BackgroundTaskBaton
+ {
+ BackgroundTaskFunction fn;
+ BackgroundTaskFunction on_finish;
+ };
+
+ BackgroundTask(BackgroundTaskFunction fn, BackgroundTaskFunction on_finish) {
+ uv_work_t *m_work = new uv_work_t;
+ memset(m_work, 0, sizeof(uv_work_t));
+ BackgroundTaskBaton *baton = new BackgroundTaskBaton();
+ baton->fn = fn;
+ baton->on_finish = on_finish;
+
+ m_work->data = baton;
+ uv_queue_work(EventLoop::Get().Handle(), m_work, [](uv_work_t* req) {
+ BackgroundTaskBaton *baton = (BackgroundTaskBaton*)req->data;
+ baton->fn();
+ }, [](uv_work_t* req, int status) {
+ BackgroundTaskBaton *baton = (BackgroundTaskBaton*)req->data;
+ baton->on_finish();
+ delete baton;
+ delete req;
+ });
+ }
+
+ ~BackgroundTask() {
+
+ }
+ };
+}
diff --git a/common/event/event_loop.cpp b/common/event/event_loop.cpp
new file mode 100644
index 000000000..e69de29bb
diff --git a/common/event/event_loop.h b/common/event/event_loop.h
new file mode 100644
index 000000000..e65b0fb08
--- /dev/null
+++ b/common/event/event_loop.h
@@ -0,0 +1,37 @@
+#pragma once
+#include
+#include
+#include
+
+namespace EQ
+{
+ class EventLoop
+ {
+ public:
+ static EventLoop &Get() {
+ static EventLoop inst;
+ return inst;
+ }
+
+ ~EventLoop() {
+ uv_loop_close(&m_loop);
+ }
+
+ void Process() {
+ uv_run(&m_loop, UV_RUN_NOWAIT);
+ }
+
+ uv_loop_t* Handle() { return &m_loop; }
+
+ private:
+ EventLoop() {
+ memset(&m_loop, 0, sizeof(uv_loop_t));
+ uv_loop_init(&m_loop);
+ }
+
+ EventLoop(const EventLoop&);
+ EventLoop& operator=(const EventLoop&);
+
+ uv_loop_t m_loop;
+ };
+}
diff --git a/common/event/timer.h b/common/event/timer.h
new file mode 100644
index 000000000..e71459630
--- /dev/null
+++ b/common/event/timer.h
@@ -0,0 +1,67 @@
+#pragma once
+#include
+#include "event_loop.h"
+
+namespace EQ {
+ class Timer
+ {
+ public:
+ Timer(std::function cb)
+ {
+ m_timer = nullptr;
+ m_cb = cb;
+ }
+
+ Timer(uint64_t duration_ms, bool repeats, std::function cb)
+ {
+ m_timer = nullptr;
+ m_cb = cb;
+ Start(duration_ms, repeats);
+ }
+
+ ~Timer()
+ {
+ Stop();
+ }
+
+ void Start(uint64_t duration_ms, bool repeats) {
+ auto loop = EventLoop::Get().Handle();
+ if (!m_timer) {
+ m_timer = new uv_timer_t;
+ memset(m_timer, 0, sizeof(uv_timer_t));
+ uv_timer_init(loop, m_timer);
+ m_timer->data = this;
+
+ if (repeats) {
+ uv_timer_start(m_timer, [](uv_timer_t *handle) {
+ Timer *t = (Timer*)handle->data;
+ t->Execute();
+ }, duration_ms, duration_ms);
+ }
+ else {
+ uv_timer_start(m_timer, [](uv_timer_t *handle) {
+ Timer *t = (Timer*)handle->data;
+ t->Stop();
+ t->Execute();
+ }, duration_ms, 0);
+ }
+ }
+ }
+
+ void Stop() {
+ if (m_timer) {
+ uv_close((uv_handle_t*)m_timer, [](uv_handle_t* handle) {
+ delete handle;
+ });
+ m_timer = nullptr;
+ }
+ }
+ private:
+ void Execute() {
+ m_cb(this);
+ }
+
+ uv_timer_t *m_timer;
+ std::function m_cb;
+ };
+}
diff --git a/common/event_sub.cpp b/common/event_sub.cpp
new file mode 100644
index 000000000..d8c772df1
--- /dev/null
+++ b/common/event_sub.cpp
@@ -0,0 +1,22 @@
+#include "event_sub.h"
+#include
+
+void EventSubscriptionWatcher::Subscribe(const std::string &event_name)
+{
+ m_subs[event_name] = 1;
+}
+
+void EventSubscriptionWatcher::Unsubscribe(const std::string &event_name)
+{
+ m_subs[event_name] = 0;
+}
+
+bool EventSubscriptionWatcher::IsSubscribed(const std::string &event_name) const
+{
+ auto iter = m_subs.find(event_name);
+ if (iter != m_subs.end()) {
+ return iter->second;
+ }
+
+ return false;
+}
diff --git a/common/event_sub.h b/common/event_sub.h
new file mode 100644
index 000000000..71b90f338
--- /dev/null
+++ b/common/event_sub.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#include
+
+class EventSubscriptionWatcher
+{
+public:
+ ~EventSubscriptionWatcher();
+
+ void Subscribe(const std::string &event_name);
+ void Unsubscribe(const std::string &event_name);
+ bool IsSubscribed(const std::string &event_name) const;
+
+ static EventSubscriptionWatcher *Get() {
+ static EventSubscriptionWatcher* inst = nullptr;
+ if(!inst) {
+ inst = new EventSubscriptionWatcher();
+ }
+
+ return inst;
+ }
+private:
+ EventSubscriptionWatcher() { }
+ EventSubscriptionWatcher(const EventSubscriptionWatcher&);
+ EventSubscriptionWatcher& operator=(const EventSubscriptionWatcher&);
+
+ std::unordered_map m_subs;
+};
diff --git a/common/features.h b/common/features.h
index 7e347db6d..550c3fa7b 100644
--- a/common/features.h
+++ b/common/features.h
@@ -160,7 +160,6 @@ enum { //timer settings, all in milliseconds
ClientProximity_interval = 150,
CombatEventTimer_expire = 12000,
Tribute_duration = 600000,
- ZoneTimerResolution = 3, //sleep time between zone main loop runs (milliseconds)
FeignMemoryDuration = 120000, // Duration player must feign death to clear zonewide agro.
EnragedTimer = 360000,
EnragedDurationTimer = 10000
diff --git a/common/json/json-forwards.h b/common/json/json-forwards.h
new file mode 100644
index 000000000..342438995
--- /dev/null
+++ b/common/json/json-forwards.h
@@ -0,0 +1,330 @@
+/// Json-cpp amalgated forward header (http://jsoncpp.sourceforge.net/).
+/// It is intended to be used with #include "json/json-forwards.h"
+/// This header provides forward declaration for all JsonCpp types.
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: LICENSE
+// //////////////////////////////////////////////////////////////////////
+
+/*
+The JsonCpp library's source code, including accompanying documentation,
+tests and demonstration applications, are licensed under the following
+conditions...
+
+The author (Baptiste Lepilleur) explicitly disclaims copyright in all
+jurisdictions which recognize such a disclaimer. In such jurisdictions,
+this software is released into the Public Domain.
+
+In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
+2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is
+released under the terms of the MIT License (see below).
+
+In jurisdictions which recognize Public Domain property, the user of this
+software may choose to accept it either as 1) Public Domain, 2) under the
+conditions of the MIT License (see below), or 3) under the terms of dual
+Public Domain/MIT License conditions described here, as they choose.
+
+The MIT License is about as close to Public Domain as a license can get, and is
+described in clear, concise terms at:
+
+ http://en.wikipedia.org/wiki/MIT_License
+
+The full text of the MIT License follows:
+
+========================================================================
+Copyright (c) 2007-2010 Baptiste Lepilleur
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use, copy,
+modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+========================================================================
+(END LICENSE TEXT)
+
+The MIT license is compatible with both the GPL and commercial
+software, affording one all of the rights of Public Domain with the
+minor nuisance of being required to keep the above copyright notice
+and license text in the source code. Note also that by accepting the
+Public Domain "license" you can re-license your copy using whatever
+license you like.
+
+*/
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: LICENSE
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+#ifndef JSON_FORWARD_AMALGATED_H_INCLUDED
+# define JSON_FORWARD_AMALGATED_H_INCLUDED
+/// If defined, indicates that the source file is amalgated
+/// to prevent private header inclusion.
+#define JSON_IS_AMALGAMATION
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/config.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef JSON_CONFIG_H_INCLUDED
+#define JSON_CONFIG_H_INCLUDED
+#include
+#include //typedef String
+#include //typedef int64_t, uint64_t
+
+/// If defined, indicates that json library is embedded in CppTL library.
+//# define JSON_IN_CPPTL 1
+
+/// If defined, indicates that json may leverage CppTL library
+//# define JSON_USE_CPPTL 1
+/// If defined, indicates that cpptl vector based map should be used instead of
+/// std::map
+/// as Value container.
+//# define JSON_USE_CPPTL_SMALLMAP 1
+
+// If non-zero, the library uses exceptions to report bad input instead of C
+// assertion macros. The default is to use exceptions.
+#ifndef JSON_USE_EXCEPTION
+#define JSON_USE_EXCEPTION 1
+#endif
+
+/// If defined, indicates that the source file is amalgated
+/// to prevent private header inclusion.
+/// Remarks: it is automatically defined in the generated amalgated header.
+// #define JSON_IS_AMALGAMATION
+
+#ifdef JSON_IN_CPPTL
+#include
+#ifndef JSON_USE_CPPTL
+#define JSON_USE_CPPTL 1
+#endif
+#endif
+
+#ifdef JSON_IN_CPPTL
+#define JSON_API CPPTL_API
+#elif defined(JSON_DLL_BUILD)
+#if defined(_MSC_VER) || defined(__MINGW32__)
+#define JSON_API __declspec(dllexport)
+#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
+#endif // if defined(_MSC_VER)
+#elif defined(JSON_DLL)
+#if defined(_MSC_VER) || defined(__MINGW32__)
+#define JSON_API __declspec(dllimport)
+#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
+#endif // if defined(_MSC_VER)
+#endif // ifdef JSON_IN_CPPTL
+#if !defined(JSON_API)
+#define JSON_API
+#endif
+
+// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for
+// integer
+// Storages, and 64 bits integer support is disabled.
+// #define JSON_NO_INT64 1
+
+#if defined(_MSC_VER) // MSVC
+# if _MSC_VER <= 1200 // MSVC 6
+ // Microsoft Visual Studio 6 only support conversion from __int64 to double
+ // (no conversion from unsigned __int64).
+# define JSON_USE_INT64_DOUBLE_CONVERSION 1
+ // Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255'
+ // characters in the debug information)
+ // All projects I've ever seen with VS6 were using this globally (not bothering
+ // with pragma push/pop).
+# pragma warning(disable : 4786)
+# endif // MSVC 6
+
+# if _MSC_VER >= 1500 // MSVC 2008
+ /// Indicates that the following function is deprecated.
+# define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
+# endif
+
+#endif // defined(_MSC_VER)
+
+// In c++11 the override keyword allows you to explicity define that a function
+// is intended to override the base-class version. This makes the code more
+// managable and fixes a set of common hard-to-find bugs.
+#if __cplusplus >= 201103L
+# define JSONCPP_OVERRIDE override
+# define JSONCPP_NOEXCEPT noexcept
+#elif defined(_MSC_VER) && _MSC_VER > 1600 && _MSC_VER < 1900
+# define JSONCPP_OVERRIDE override
+# define JSONCPP_NOEXCEPT throw()
+#elif defined(_MSC_VER) && _MSC_VER >= 1900
+# define JSONCPP_OVERRIDE override
+# define JSONCPP_NOEXCEPT noexcept
+#else
+# define JSONCPP_OVERRIDE
+# define JSONCPP_NOEXCEPT throw()
+#endif
+
+#ifndef JSON_HAS_RVALUE_REFERENCES
+
+#if defined(_MSC_VER) && _MSC_VER >= 1600 // MSVC >= 2010
+#define JSON_HAS_RVALUE_REFERENCES 1
+#endif // MSVC >= 2010
+
+#ifdef __clang__
+#if __has_feature(cxx_rvalue_references)
+#define JSON_HAS_RVALUE_REFERENCES 1
+#endif // has_feature
+
+#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc)
+#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L)
+#define JSON_HAS_RVALUE_REFERENCES 1
+#endif // GXX_EXPERIMENTAL
+
+#endif // __clang__ || __GNUC__
+
+#endif // not defined JSON_HAS_RVALUE_REFERENCES
+
+#ifndef JSON_HAS_RVALUE_REFERENCES
+#define JSON_HAS_RVALUE_REFERENCES 0
+#endif
+
+#ifdef __clang__
+#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc)
+# if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
+# define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message)))
+# elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
+# define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__))
+# endif // GNUC version
+#endif // __clang__ || __GNUC__
+
+#if !defined(JSONCPP_DEPRECATED)
+#define JSONCPP_DEPRECATED(message)
+#endif // if !defined(JSONCPP_DEPRECATED)
+
+#if __GNUC__ >= 6
+# define JSON_USE_INT64_DOUBLE_CONVERSION 1
+#endif
+
+#if !defined(JSON_IS_AMALGAMATION)
+
+# include "version.h"
+
+# if JSONCPP_USING_SECURE_MEMORY
+# include "allocator.h" //typedef Allocator
+# endif
+
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+namespace Json {
+typedef int Int;
+typedef unsigned int UInt;
+#if defined(JSON_NO_INT64)
+typedef int LargestInt;
+typedef unsigned int LargestUInt;
+#undef JSON_HAS_INT64
+#else // if defined(JSON_NO_INT64)
+// For Microsoft Visual use specific types as long long is not supported
+#if defined(_MSC_VER) // Microsoft Visual Studio
+typedef __int64 Int64;
+typedef unsigned __int64 UInt64;
+#else // if defined(_MSC_VER) // Other platforms, use long long
+typedef int64_t Int64;
+typedef uint64_t UInt64;
+#endif // if defined(_MSC_VER)
+typedef Int64 LargestInt;
+typedef UInt64 LargestUInt;
+#define JSON_HAS_INT64
+#endif // if defined(JSON_NO_INT64)
+#if JSONCPP_USING_SECURE_MEMORY
+#define JSONCPP_STRING std::basic_string, Json::SecureAllocator >
+#define JSONCPP_OSTRINGSTREAM std::basic_ostringstream, Json::SecureAllocator >
+#define JSONCPP_OSTREAM std::basic_ostream>
+#define JSONCPP_ISTRINGSTREAM std::basic_istringstream, Json::SecureAllocator >
+#define JSONCPP_ISTREAM std::istream
+#else
+#define JSONCPP_STRING std::string
+#define JSONCPP_OSTRINGSTREAM std::ostringstream
+#define JSONCPP_OSTREAM std::ostream
+#define JSONCPP_ISTRINGSTREAM std::istringstream
+#define JSONCPP_ISTREAM std::istream
+#endif // if JSONCPP_USING_SECURE_MEMORY
+} // end namespace Json
+
+#endif // JSON_CONFIG_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/config.h
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/forwards.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef JSON_FORWARDS_H_INCLUDED
+#define JSON_FORWARDS_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "config.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+namespace Json {
+
+// writer.h
+class FastWriter;
+class StyledWriter;
+
+// reader.h
+class Reader;
+
+// features.h
+class Features;
+
+// value.h
+typedef unsigned int ArrayIndex;
+class StaticString;
+class Path;
+class PathArgument;
+class Value;
+class ValueIteratorBase;
+class ValueIterator;
+class ValueConstIterator;
+
+} // namespace Json
+
+#endif // JSON_FORWARDS_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/forwards.h
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+#endif //ifndef JSON_FORWARD_AMALGATED_H_INCLUDED
diff --git a/common/json/json.h b/common/json/json.h
new file mode 100644
index 000000000..02a31f4a0
--- /dev/null
+++ b/common/json/json.h
@@ -0,0 +1,2161 @@
+/// Json-cpp amalgated header (http://jsoncpp.sourceforge.net/).
+/// It is intended to be used with #include "json/json.h"
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: LICENSE
+// //////////////////////////////////////////////////////////////////////
+
+/*
+The JsonCpp library's source code, including accompanying documentation,
+tests and demonstration applications, are licensed under the following
+conditions...
+
+The author (Baptiste Lepilleur) explicitly disclaims copyright in all
+jurisdictions which recognize such a disclaimer. In such jurisdictions,
+this software is released into the Public Domain.
+
+In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
+2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is
+released under the terms of the MIT License (see below).
+
+In jurisdictions which recognize Public Domain property, the user of this
+software may choose to accept it either as 1) Public Domain, 2) under the
+conditions of the MIT License (see below), or 3) under the terms of dual
+Public Domain/MIT License conditions described here, as they choose.
+
+The MIT License is about as close to Public Domain as a license can get, and is
+described in clear, concise terms at:
+
+ http://en.wikipedia.org/wiki/MIT_License
+
+The full text of the MIT License follows:
+
+========================================================================
+Copyright (c) 2007-2010 Baptiste Lepilleur
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use, copy,
+modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+========================================================================
+(END LICENSE TEXT)
+
+The MIT license is compatible with both the GPL and commercial
+software, affording one all of the rights of Public Domain with the
+minor nuisance of being required to keep the above copyright notice
+and license text in the source code. Note also that by accepting the
+Public Domain "license" you can re-license your copy using whatever
+license you like.
+
+*/
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: LICENSE
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+#ifndef JSON_AMALGATED_H_INCLUDED
+# define JSON_AMALGATED_H_INCLUDED
+/// If defined, indicates that the source file is amalgated
+/// to prevent private header inclusion.
+#define JSON_IS_AMALGAMATION
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/version.h
+// //////////////////////////////////////////////////////////////////////
+
+// DO NOT EDIT. This file (and "version") is generated by CMake.
+// Run CMake configure step to update it.
+#ifndef JSON_VERSION_H_INCLUDED
+# define JSON_VERSION_H_INCLUDED
+
+# define JSONCPP_VERSION_STRING "1.8.0"
+# define JSONCPP_VERSION_MAJOR 1
+# define JSONCPP_VERSION_MINOR 8
+# define JSONCPP_VERSION_PATCH 0
+# define JSONCPP_VERSION_QUALIFIER
+# define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8))
+
+#ifdef JSONCPP_USING_SECURE_MEMORY
+#undef JSONCPP_USING_SECURE_MEMORY
+#endif
+#define JSONCPP_USING_SECURE_MEMORY 0
+// If non-zero, the library zeroes any memory that it has allocated before
+// it frees its memory.
+
+#endif // JSON_VERSION_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/version.h
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/config.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef JSON_CONFIG_H_INCLUDED
+#define JSON_CONFIG_H_INCLUDED
+#include
+#include //typedef String
+#include //typedef int64_t, uint64_t
+
+/// If defined, indicates that json library is embedded in CppTL library.
+//# define JSON_IN_CPPTL 1
+
+/// If defined, indicates that json may leverage CppTL library
+//# define JSON_USE_CPPTL 1
+/// If defined, indicates that cpptl vector based map should be used instead of
+/// std::map
+/// as Value container.
+//# define JSON_USE_CPPTL_SMALLMAP 1
+
+// If non-zero, the library uses exceptions to report bad input instead of C
+// assertion macros. The default is to use exceptions.
+#ifndef JSON_USE_EXCEPTION
+#define JSON_USE_EXCEPTION 1
+#endif
+
+/// If defined, indicates that the source file is amalgated
+/// to prevent private header inclusion.
+/// Remarks: it is automatically defined in the generated amalgated header.
+// #define JSON_IS_AMALGAMATION
+
+#ifdef JSON_IN_CPPTL
+#include
+#ifndef JSON_USE_CPPTL
+#define JSON_USE_CPPTL 1
+#endif
+#endif
+
+#ifdef JSON_IN_CPPTL
+#define JSON_API CPPTL_API
+#elif defined(JSON_DLL_BUILD)
+#if defined(_MSC_VER) || defined(__MINGW32__)
+#define JSON_API __declspec(dllexport)
+#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
+#endif // if defined(_MSC_VER)
+#elif defined(JSON_DLL)
+#if defined(_MSC_VER) || defined(__MINGW32__)
+#define JSON_API __declspec(dllimport)
+#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
+#endif // if defined(_MSC_VER)
+#endif // ifdef JSON_IN_CPPTL
+#if !defined(JSON_API)
+#define JSON_API
+#endif
+
+// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for
+// integer
+// Storages, and 64 bits integer support is disabled.
+// #define JSON_NO_INT64 1
+
+#if defined(_MSC_VER) // MSVC
+# if _MSC_VER <= 1200 // MSVC 6
+ // Microsoft Visual Studio 6 only support conversion from __int64 to double
+ // (no conversion from unsigned __int64).
+# define JSON_USE_INT64_DOUBLE_CONVERSION 1
+ // Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255'
+ // characters in the debug information)
+ // All projects I've ever seen with VS6 were using this globally (not bothering
+ // with pragma push/pop).
+# pragma warning(disable : 4786)
+# endif // MSVC 6
+
+# if _MSC_VER >= 1500 // MSVC 2008
+ /// Indicates that the following function is deprecated.
+# define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
+# endif
+
+#endif // defined(_MSC_VER)
+
+// In c++11 the override keyword allows you to explicity define that a function
+// is intended to override the base-class version. This makes the code more
+// managable and fixes a set of common hard-to-find bugs.
+#if __cplusplus >= 201103L
+# define JSONCPP_OVERRIDE override
+# define JSONCPP_NOEXCEPT noexcept
+#elif defined(_MSC_VER) && _MSC_VER > 1600 && _MSC_VER < 1900
+# define JSONCPP_OVERRIDE override
+# define JSONCPP_NOEXCEPT throw()
+#elif defined(_MSC_VER) && _MSC_VER >= 1900
+# define JSONCPP_OVERRIDE override
+# define JSONCPP_NOEXCEPT noexcept
+#else
+# define JSONCPP_OVERRIDE
+# define JSONCPP_NOEXCEPT throw()
+#endif
+
+#ifndef JSON_HAS_RVALUE_REFERENCES
+
+#if defined(_MSC_VER) && _MSC_VER >= 1600 // MSVC >= 2010
+#define JSON_HAS_RVALUE_REFERENCES 1
+#endif // MSVC >= 2010
+
+#ifdef __clang__
+#if __has_feature(cxx_rvalue_references)
+#define JSON_HAS_RVALUE_REFERENCES 1
+#endif // has_feature
+
+#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc)
+#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L)
+#define JSON_HAS_RVALUE_REFERENCES 1
+#endif // GXX_EXPERIMENTAL
+
+#endif // __clang__ || __GNUC__
+
+#endif // not defined JSON_HAS_RVALUE_REFERENCES
+
+#ifndef JSON_HAS_RVALUE_REFERENCES
+#define JSON_HAS_RVALUE_REFERENCES 0
+#endif
+
+#ifdef __clang__
+#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc)
+# if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
+# define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message)))
+# elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
+# define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__))
+# endif // GNUC version
+#endif // __clang__ || __GNUC__
+
+#if !defined(JSONCPP_DEPRECATED)
+#define JSONCPP_DEPRECATED(message)
+#endif // if !defined(JSONCPP_DEPRECATED)
+
+#if __GNUC__ >= 6
+# define JSON_USE_INT64_DOUBLE_CONVERSION 1
+#endif
+
+#if !defined(JSON_IS_AMALGAMATION)
+
+# include "version.h"
+
+# if JSONCPP_USING_SECURE_MEMORY
+# include "allocator.h" //typedef Allocator
+# endif
+
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+namespace Json {
+typedef int Int;
+typedef unsigned int UInt;
+#if defined(JSON_NO_INT64)
+typedef int LargestInt;
+typedef unsigned int LargestUInt;
+#undef JSON_HAS_INT64
+#else // if defined(JSON_NO_INT64)
+// For Microsoft Visual use specific types as long long is not supported
+#if defined(_MSC_VER) // Microsoft Visual Studio
+typedef __int64 Int64;
+typedef unsigned __int64 UInt64;
+#else // if defined(_MSC_VER) // Other platforms, use long long
+typedef int64_t Int64;
+typedef uint64_t UInt64;
+#endif // if defined(_MSC_VER)
+typedef Int64 LargestInt;
+typedef UInt64 LargestUInt;
+#define JSON_HAS_INT64
+#endif // if defined(JSON_NO_INT64)
+#if JSONCPP_USING_SECURE_MEMORY
+#define JSONCPP_STRING std::basic_string, Json::SecureAllocator >
+#define JSONCPP_OSTRINGSTREAM std::basic_ostringstream, Json::SecureAllocator >
+#define JSONCPP_OSTREAM std::basic_ostream>
+#define JSONCPP_ISTRINGSTREAM std::basic_istringstream, Json::SecureAllocator >
+#define JSONCPP_ISTREAM std::istream
+#else
+#define JSONCPP_STRING std::string
+#define JSONCPP_OSTRINGSTREAM std::ostringstream
+#define JSONCPP_OSTREAM std::ostream
+#define JSONCPP_ISTRINGSTREAM std::istringstream
+#define JSONCPP_ISTREAM std::istream
+#endif // if JSONCPP_USING_SECURE_MEMORY
+} // end namespace Json
+
+#endif // JSON_CONFIG_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/config.h
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/forwards.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef JSON_FORWARDS_H_INCLUDED
+#define JSON_FORWARDS_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "config.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+namespace Json {
+
+// writer.h
+class FastWriter;
+class StyledWriter;
+
+// reader.h
+class Reader;
+
+// features.h
+class Features;
+
+// value.h
+typedef unsigned int ArrayIndex;
+class StaticString;
+class Path;
+class PathArgument;
+class Value;
+class ValueIteratorBase;
+class ValueIterator;
+class ValueConstIterator;
+
+} // namespace Json
+
+#endif // JSON_FORWARDS_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/forwards.h
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/features.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef CPPTL_JSON_FEATURES_H_INCLUDED
+#define CPPTL_JSON_FEATURES_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "forwards.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+#pragma pack(push, 8)
+
+namespace Json {
+
+/** \brief Configuration passed to reader and writer.
+ * This configuration object can be used to force the Reader or Writer
+ * to behave in a standard conforming way.
+ */
+class JSON_API Features {
+public:
+ /** \brief A configuration that allows all features and assumes all strings
+ * are UTF-8.
+ * - C & C++ comments are allowed
+ * - Root object can be any JSON value
+ * - Assumes Value strings are encoded in UTF-8
+ */
+ static Features all();
+
+ /** \brief A configuration that is strictly compatible with the JSON
+ * specification.
+ * - Comments are forbidden.
+ * - Root object must be either an array or an object value.
+ * - Assumes Value strings are encoded in UTF-8
+ */
+ static Features strictMode();
+
+ /** \brief Initialize the configuration like JsonConfig::allFeatures;
+ */
+ Features();
+
+ /// \c true if comments are allowed. Default: \c true.
+ bool allowComments_;
+
+ /// \c true if root must be either an array or an object value. Default: \c
+ /// false.
+ bool strictRoot_;
+
+ /// \c true if dropped null placeholders are allowed. Default: \c false.
+ bool allowDroppedNullPlaceholders_;
+
+ /// \c true if numeric object key are allowed. Default: \c false.
+ bool allowNumericKeys_;
+};
+
+} // namespace Json
+
+#pragma pack(pop)
+
+#endif // CPPTL_JSON_FEATURES_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/features.h
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/value.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef CPPTL_JSON_H_INCLUDED
+#define CPPTL_JSON_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "forwards.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+#include
+#include
+#include
+
+#ifndef JSON_USE_CPPTL_SMALLMAP
+#include