svn -> git Migration

This commit is contained in:
KimLS 2013-02-16 16:14:39 -08:00
parent 88c9715fb0
commit da7347f76f
1174 changed files with 445622 additions and 0 deletions

164
CMakeLists.txt Normal file
View File

@ -0,0 +1,164 @@
#EQEmu Cmake
#We set a fairly new version (as of 2013) because I found finding perl was a bit... buggy on older ones
#Can change this if you really want but you should upgrade!
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
#FindMySQL is located here so lets make it so CMake can find it
SET(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/" ${CMAKE_MODULE_PATH})
#For checking includes
INCLUDE (CheckIncludeFiles)
#Our project name is EQEmu
PROJECT(EQEmu)
#Default build type is set to RelWithDebInfo for generators that honor that like makefiles
IF(NOT CMAKE_BUILD_TYPE)
SET(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build." FORCE)
ENDIF(NOT CMAKE_BUILD_TYPE)
#Add our various windows definitions
IF(MSVC OR MINGW)
ADD_DEFINITIONS(-D_WINDOWS)
IF(CMAKE_CL_64)
ADD_DEFINITIONS(-DWIN64)
ELSE(CMAKE_CL_64)
ADD_DEFINITIONS(-DWIN32)
ENDIF(CMAKE_CL_64)
ENDIF(MSVC OR MINGW)
IF(MSVC)
#Set our default locations for zlib/mysql based on x86/x64
IF(CMAKE_CL_64)
SET(ZLIB_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/zlib_x64")
SET(MYSQL_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/mysql_x64")
ELSE(CMAKE_CL_64)
SET(ZLIB_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/zlib_x86")
SET(MYSQL_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/mysql_x86")
ENDIF(CMAKE_CL_64)
#disable CRT warnings on windows cause they're annoying as shit and we use C functions everywhere
OPTION(EQEMU_DISABLE_CRT_SECURE_WARNINGS "Disable Secure CRT Warnings" ON)
IF(EQEMU_DISABLE_CRT_SECURE_WARNINGS)
ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS)
ENDIF(EQEMU_DISABLE_CRT_SECURE_WARNINGS)
#fast FP if you'd like it
OPTION(EQEMU_FAST_FLOATINGPOINT "Use MSVC /fp:fast option" ON)
IF(EQEMU_FAST_FLOATINGPOINT)
ADD_DEFINITIONS(/fp:fast)
ENDIF(EQEMU_FAST_FLOATINGPOINT)
#crash logging currently only works on windows x86/x64
OPTION(EQEMU_ENABLE_CRASH_LOGGING "Enable crash logging" ON)
IF(EQEMU_ENABLE_CRASH_LOGGING)
ADD_DEFINITIONS(-DCRASH_LOGGING)
ENDIF(EQEMU_ENABLE_CRASH_LOGGING)
#Disable safe SEH or not?
OPTION(EQEMU_DISABLE_SAFESEH "Disable Safe SEH (Needed for Strawberry Perl)" OFF)
IF(EQEMU_DISABLE_SAFESEH)
SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} /SAFESEH:NO")
SET(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "${CMAKE_EXE_LINKER_FLAGS_MINSIZEREL} /SAFESEH:NO")
SET(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /SAFESEH:NO")
SET(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} /SAFESEH:NO")
SET(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} /SAFESEH:NO")
SET(CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL "${CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL} /SAFESEH:NO")
SET(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /SAFESEH:NO")
SET(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO} /SAFESEH:NO")
SET(CMAKE_MODULE_LINKER_FLAGS_DEBUG "${CMAKE_MODULE_LINKER_FLAGS_DEBUG} /SAFESEH:NO")
SET(CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL "${CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL} /SAFESEH:NO")
SET(CMAKE_MODULE_LINKER_FLAGS_RELEASE "${CMAKE_MODULE_LINKER_FLAGS_RELEASE} /SAFESEH:NO")
SET(CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO} /SAFESEH:NO")
ENDIF(EQEMU_DISABLE_SAFESEH)
#We want to compile /MT not /MD so we change that
FOREACH(flag_var CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_RELWITHDEBINFO CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELEASE CMAKE_C_FLAGS_RELWITHDEBINFO)
IF(${flag_var} MATCHES "/MD")
STRING(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
ENDIF(${flag_var} MATCHES "/MD")
ENDFOREACH(flag_var)
ELSE(MSVC)
#Normally set by perl but we don't use the perl flags anymore so we set it.
ADD_DEFINITIONS(-DHAS_UNION_SEMUN)
ENDIF(MSVC)
#use stdint.h types if they exist for this platform (we have to guess otherwise)
CHECK_INCLUDE_FILES(stdint.h HAVE_STDINT_H)
IF(HAVE_STDINT_H)
ADD_DEFINITIONS(-DEQEMU_USE_STDINT)
ENDIF(HAVE_STDINT_H)
#debug level, 5 is default. Most people wont ever change this but it's there if you want to
SET(EQEMU_DEBUG_LEVEL 5 CACHE STRING "EQEmu debug level:
0 - Quiet mode Errors to file Status and Normal ignored
1 - Status and Normal to console, Errors to logfile
2 - Status, Normal, and Error to console and logfile
3 - Light debug release errors and status
4 - Moderate debug release errors and status
5 - Maximum debug release errors and status
10 - More errors than you ever wanted to see"
)
#Bots are a compile time option so on/off
OPTION(EQEMU_ENABLE_BOTS "Enable Bots" OFF)
IF(EQEMU_ENABLE_BOTS)
ADD_DEFINITIONS(-DBOTS)
ENDIF(EQEMU_ENABLE_BOTS)
#What to build
OPTION(EQEMU_BUILD_SERVER "Build the game server." ON)
OPTION(EQEMU_BUILD_LOGIN "Build the login server." OFF)
OPTION(EQEMU_BUILD_AZONE "Build azone utility." OFF)
OPTION(EQEMU_BUILD_TESTS "Build utility tests." OFF)
IF(UNIX)
#Whether to build cleanipc or not (probably a good idea if you build server)
OPTION(EQEMU_BUILD_CLEANIPC "Build cleanipc." ON)
#Use C++11 stuff, support for this is still it infancy
OPTION(EQEMU_CPP_ELEVEN "Enable C++11 extentions in g++" OFF)
IF(EQEMU_CPP_ELEVEN)
ADD_DEFINITIONS(-std=c++0x)
ENDIF(EQEMU_CPP_ELEVEN)
ENDIF(UNIX)
#Various definitions
ADD_DEFINITIONS(-DEMBPERL)
ADD_DEFINITIONS(-DEMBPERL_PLUGIN)
ADD_DEFINITIONS(-DEQDEBUG=${EQEMU_DEBUG_LEVEL})
ADD_DEFINITIONS(-DSHAREMEM)
ADD_DEFINITIONS(-DINVERSEXY)
ADD_DEFINITIONS(-DFIELD_ITEMS)
ADD_DEFINITIONS(-DMAP_DIR="./Maps")
#Find everything we need
FIND_PACKAGE(ZLIB REQUIRED)
FIND_PACKAGE(MySQL REQUIRED)
FIND_PACKAGE(PerlLibs REQUIRED)
INCLUDE_DIRECTORIES("${ZLIB_INCLUDE_DIRS}" "${PERL_INCLUDE_PATH}" "${MySQL_INCLUDE_DIR}")
IF(EQEMU_BUILD_SERVER OR EQEMU_BUILD_LOGIN OR EQEMU_BUILD_TESTS)
ADD_SUBDIRECTORY(common)
ENDIF(EQEMU_BUILD_SERVER OR EQEMU_BUILD_LOGIN OR EQEMU_BUILD_TESTS)
IF(EQEMU_BUILD_SERVER)
ADD_SUBDIRECTORY(EMuShareMem)
ADD_SUBDIRECTORY(world)
ADD_SUBDIRECTORY(zone)
ADD_SUBDIRECTORY(ucs)
ADD_SUBDIRECTORY(queryserv)
ADD_SUBDIRECTORY(eqlaunch)
ENDIF(EQEMU_BUILD_SERVER)
IF(EQEMU_BUILD_LOGIN)
ADD_SUBDIRECTORY(loginserver)
ENDIF(EQEMU_BUILD_LOGIN)
IF(EQEMU_BUILD_AZONE OR EQEMU_BUILD_CLEANIPC)
ADD_SUBDIRECTORY(utils)
ENDIF(EQEMU_BUILD_AZONE OR EQEMU_BUILD_CLEANIPC)
IF(EQEMU_BUILD_TESTS)
# Testing framework not quite ready for prime time.
# ADD_SUBDIRECTORY(tests)
ENDIF(EQEMU_BUILD_TESTS)

View File

@ -0,0 +1,46 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
SET(sharedmem_src
DLLMain.cpp
Doors.cpp
Items.cpp
Loot.cpp
MMF.cpp
MMFMutex.cpp
NPCFactionLists.cpp
Opcodes.cpp
SkillCaps.cpp
Spells.cpp
)
SET(sharedmem_headers
Doors.h
Items.h
Loot.h
MMF.h
MMFMutex.h
NPCFactionLists.h
Opcodes.h
SkillCaps.h
Spells.h
)
SET(EQEMU_MAX_ITEMS 300000 CACHE STRING "Maxium number of items to load into memory. Make sure this is bigger than the total number of items in the server database")
SET(EQEMU_MAX_DOORS 30000 CACHE STRING "Maxium number of doors to load into memory. Make sure this is bigger than the total number of doors in the server database")
SET(EQEMU_MAX_FACTIONLIST_IDS 50000 CACHE STRING "Maxium number of FactionList IDs to load into memory. Make sure this is bigger than the total number of FactionList IDs in the server database")
ADD_DEFINITIONS(-DMMF_EQMAX_ITEMS=${EQEMU_MAX_ITEMS})
ADD_DEFINITIONS(-DMMF_MAX_Door_ID=${EQEMU_MAX_DOORS})
ADD_DEFINITIONS(-DMMF_MAX_NPCFactionList_ID=${EQEMU_MAX_FACTIONLIST_IDS})
ADD_LIBRARY(EMuShareMem SHARED ${sharedmem_src} ${sharedmem_headers})
TARGET_LINK_LIBRARIES(EMuShareMem Common)
IF(UNIX)
TARGET_LINK_LIBRARIES(EMuShareMem "dl")
TARGET_LINK_LIBRARIES(EMuShareMem "m")
TARGET_LINK_LIBRARIES(EMuShareMem "rt")
TARGET_LINK_LIBRARIES(EMuShareMem "pthread")
ENDIF(UNIX)
SET(LIBRARY_OUTPUT_PATH ../Bin)

37
EMuShareMem/DLLMain.cpp Normal file
View File

@ -0,0 +1,37 @@
/*
EMuShareMem.dll
by Quagmire
Released under GPL
This DLL's purpose it to hold a single shared copy of items, npctypes, spells, and other
stuff that's normally cached in memory, thus allowing all processes on the server to share
one copy of the data, greatly reducing the amount of RAM used.
*/
#ifdef _WINDOWS
#include <windows.h>
void CloseMemShare();
BOOL WINAPI DllMain(
HINSTANCE hinstDLL, // handle to DLL module
DWORD fdwReason, // reason for calling function
LPVOID lpReserved ) // reserved
{
// Perform actions based on the reason for calling.
switch( fdwReason )
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH: {
break;
}
case DLL_THREAD_DETACH: {
break;
}
case DLL_PROCESS_DETACH: {
break;
}
}
return TRUE; // Successful DLL_PROCESS_ATTACH.
}
#endif //WIN32

136
EMuShareMem/Doors.cpp Normal file
View File

@ -0,0 +1,136 @@
#include "../common/debug.h"
#ifdef _WINDOWS
#include <windows.h>
#else
#include "../common/unix.h"
#endif
#include <memory.h>
#include <iostream>
using namespace std;
#include "Doors.h"
#include "../common/timer.h"
#include "MMF.h"
MMF DoorsMMF;
const MMFDoors_Struct* MMFDoorsData = 0;
MMFDoors_Struct* MMFDoorsData_Writable = 0;
#ifdef _WINDOWS
extern "C" __declspec(dllexport) const Door* GetDoor(uint32 id) {
return pGetDoor(id);
};
extern "C" __declspec(dllexport) bool AddDoor(uint32 id, const Door* door) {
return pAddDoor(id, door);
};
extern "C" __declspec(dllexport) bool DLLLoadDoors(CALLBACK_DBLoadDoors cbDBLoadDoors, uint32 iDoorstructSize, int32* iDoorsCount, uint32* iMaxDoorID) {
return pDLLLoadDoors(cbDBLoadDoors, iDoorstructSize, iDoorsCount, iMaxDoorID);
};
#else
extern "C" const Door* GetDoor(uint32 id) {
return pGetDoor(id);
};
extern "C" bool AddDoor(uint32 id, const Door* door) {
return pAddDoor(id, door);
};
extern "C" bool DLLLoadDoors(CALLBACK_DBLoadDoors cbDBLoadDoors, uint32 iDoorstructSize, int32* iDoorsCount, uint32* iMaxDoorID) {
return pDLLLoadDoors(cbDBLoadDoors, iDoorstructSize, iDoorsCount, iMaxDoorID);
};
#endif
bool pAddDoor(uint32 id, const Door* door) {
if (!MMFDoorsData_Writable)
return false;
if (id > MMF_MAX_Door_ID || MMFDoorsData_Writable->NextFreeIndex >= MMFDoorsData_Writable->DoorCount)
return false;
if (MMFDoorsData_Writable->DoorIndex[id] != 0xFFFFFFFF)
return false;
MMFDoorsData_Writable->DoorIndex[id] = MMFDoorsData_Writable->NextFreeIndex++;
memcpy(&MMFDoorsData_Writable->Doors[MMFDoorsData_Writable->DoorIndex[id]], door, sizeof(Door));
return true;
}
bool pDLLLoadDoors(CALLBACK_DBLoadDoors cbDBLoadDoors, uint32 iDoorstructSize, int32* iDoorsCount, uint32* iMaxDoorID) {
if (iDoorstructSize != sizeof(Door)) {
cout << "Error: EMuShareMem: DLLLoadDoors: iDoorstructSize != sizeof(Door)" << endl;
cout << "Door struct has changed, EMuShareMem.dll needs to be recompiled." << endl;
return false;
}
if (*iMaxDoorID > MMF_MAX_Door_ID) {
cout << "Error: EMuShareMem: pDLLLoadDoors: iMaxDoorID > MMF_MAX_Door_ID" << endl;
cout << "You need to increase the define in Doors.h." << endl;
return false;
}
uint32 tmpMemSize = sizeof(MMFDoors_Struct) + 256 + (sizeof(Door) * (*iDoorsCount));
if (DoorsMMF.Open("EQEMuDoors", tmpMemSize)) {
if (DoorsMMF.CanWrite()) {
MMFDoorsData_Writable = (MMFDoors_Struct*) DoorsMMF.GetWriteableHandle();
if (!MMFDoorsData_Writable) {
cout << "Error: EMuShareMem: DLLLoadDoors: !MMFDoorsData_Writable" << endl;
return false;
}
memset(MMFDoorsData_Writable, 0, tmpMemSize);
for(int i=0; i<MMF_MAX_Door_ID; i++)
MMFDoorsData_Writable->DoorIndex[i] = 0xFFFFFFFF;
MMFDoorsData_Writable->MaxDoorID = *iMaxDoorID;
MMFDoorsData_Writable->DoorCount = *iDoorsCount;
// use a callback so the DB functions are done in the main exe
// this way the DLL doesnt have to open a connection to mysql
if (!cbDBLoadDoors(*iDoorsCount, *iMaxDoorID)) {
cout << "Error: EMuShareMem: DLLLoadDoors: !cbDBLoadDoors" << endl;
return false;
}
MMFDoorsData_Writable = 0;
DoorsMMF.SetLoaded();
MMFDoorsData = (const MMFDoors_Struct*) DoorsMMF.GetHandle();
if (!MMFDoorsData) {
cout << "Error: EMuShareMem: DLLLoadDoors: !MMFDoorsData (CanWrite=true)" << endl;
return false;
}
return true;
}
else {
if (!DoorsMMF.IsLoaded()) {
Timer::SetCurrentTime();
uint32 starttime = Timer::GetCurrentTime();
while ((!DoorsMMF.IsLoaded()) && ((Timer::GetCurrentTime() - starttime) < 300000)) {
Sleep(10);
Timer::SetCurrentTime();
}
if (!DoorsMMF.IsLoaded()) {
cout << "Error: EMuShareMem: DLLLoadDoors: !DoorsMMF.IsLoaded() (timeout)" << endl;
return false;
}
}
MMFDoorsData = (const MMFDoors_Struct*) DoorsMMF.GetHandle();
if (!MMFDoorsData) {
cout << "Error: EMuShareMem: DLLLoadDoors: !MMFDoorsData (CanWrite=false)" << endl;
return false;
}
*iMaxDoorID = MMFDoorsData->MaxDoorID;
*iDoorsCount = MMFDoorsData->DoorCount;
return true;
}
}
else {
cout << "Error Loading Doors: Doors.cpp: pDLLLoadDoors: ret == 0" << endl;
return false;
}
return false;
};
const Door* pGetDoor(uint32 id) {
if (MMFDoorsData == 0 || (!DoorsMMF.IsLoaded()) || id > MMF_MAX_Door_ID || MMFDoorsData->DoorIndex[id] == 0xFFFFFFFF)
return 0;
return &MMFDoorsData->Doors[MMFDoorsData->DoorIndex[id]];
}

22
EMuShareMem/Doors.h Normal file
View File

@ -0,0 +1,22 @@
#include "../common/types.h"
#include "../zone/zonedump.h"
#include "../common/EMuShareMem.h"
// MMF_MAX_Door_ID: Make sure this is bigger than the highest Door ID#
#ifndef MMF_MAX_Door_ID
#define MMF_MAX_Door_ID 30000
#endif
// MMF_MAX_Door_MEM: Maxium number of Doors to load into memory. Make sure this is bigger
// than the total number of Doors in the server's database!
struct MMFDoors_Struct {
uint32 MaxDoorID;
uint32 NextFreeIndex;
uint32 DoorCount;
uint32 DoorIndex[MMF_MAX_Door_ID+1];
Door Doors[0];
};
bool pDLLLoadDoors(CALLBACK_DBLoadDoors cbDBLoadDoors, uint32 iDoorstructSize, int32* iDoorsCount, uint32* iMaxDoorID);
bool pAddDoor(uint32 id, const Door* door);
const Door* pGetDoor(uint32 id);

152
EMuShareMem/Items.cpp Normal file
View File

@ -0,0 +1,152 @@
/*
Note: Do NOT change this to load items on an as-needed basis. Since this memory is
accessed from multiple threads, you'd need mutex's all over the place if it was
ever to be modified/updated/added to. The overhead of the mutexes would be alot more
in the long run than the delay in loading.
-Quagmire
*/
#ifdef _WINDOWS
#include <winsock2.h>
#include <windows.h>
#else
#include "../common/unix.h"
#endif
#include <memory.h>
#include <iostream>
using namespace std;
#include "Items.h"
#include "../common/timer.h"
#include "MMF.h"
MMF ItemsMMF;
const MMFItems_Struct* MMFItemsData = 0;
MMFItems_Struct* MMFItemsData_Writable = 0;
DLLFUNC bool AddItem(uint32 id, const Item_Struct* item) {
if (!MMFItemsData_Writable) {
return false;
}
if (id > MMF_EQMAX_ITEMS || MMFItemsData_Writable->NextFreeIndex >= MMFItemsData_Writable->ItemCount) {
return false;
}
if (MMFItemsData_Writable->ItemIndex[id] != 0xFFFF) {
return false;
}
uint32 nextid = MMFItemsData_Writable->NextFreeIndex++;
MMFItemsData_Writable->ItemIndex[id] = nextid;
memcpy(&MMFItemsData_Writable->Items[nextid], item, sizeof(Item_Struct));
return true;
}
DLLFUNC bool DLLLoadItems(CALLBACK_DBLoadItems cbDBLoadItems, uint32 iItemStructSize, int32* iItemCount, uint32* iMaxItemID) {
if (iItemStructSize != sizeof(Item_Struct)) {
cout << "Error: EMuShareMem: DLLLoadItems: iItemStructSize != sizeof(Item_Struct)" << endl;
cout << "Item_Struct has changed, EMuShareMem.dll needs to be recompiled." << endl;
return false;
}
if (*iMaxItemID > MMF_EQMAX_ITEMS) {
cout << "Error: EMuShareMem: pDLLLoadItems: iMaxItemID > MMF_EQMAX_ITEMS" << endl;
cout << "You need to increase the define in Items.h." << endl;
return false;
}
MMFItemsData_Writable = 0;
//Allocate the shared memory for the item structures
uint32 tmpMemSize = sizeof(MMFItems_Struct) + 256 + (sizeof(Item_Struct) * (*iItemCount));
//cout << tmpMemSize << endl;
if (ItemsMMF.Open("EQEMuItems", tmpMemSize)) {
if (ItemsMMF.CanWrite()) {
MMFItemsData_Writable = (MMFItems_Struct*) ItemsMMF.GetWriteableHandle();
if (!MMFItemsData_Writable) {
cout << "Error: EMuShareMem: DLLLoadItems: !MMFItemsData_Writable" << endl;
return false;
}
memset(MMFItemsData_Writable, 0, tmpMemSize);
for(int i=0; i<MMF_EQMAX_ITEMS; i++)
MMFItemsData_Writable->ItemIndex[i] = 0xFFFF;
MMFItemsData_Writable->MaxItemID = *iMaxItemID;
MMFItemsData_Writable->ItemCount = *iItemCount;
//the writable handle has been created, do the load below after we have the
//serialization handle as well.
} else {
if (!ItemsMMF.IsLoaded()) {
Timer::SetCurrentTime();
uint32 starttime = Timer::GetCurrentTime();
while ((!ItemsMMF.IsLoaded()) && ((Timer::GetCurrentTime() - starttime) < 300000)) {
Sleep(10);
Timer::SetCurrentTime();
}
if (!ItemsMMF.IsLoaded()) {
cout << "Error: EMuShareMem: DLLLoadItems: !ItemsMMF.IsLoaded() (timeout)" << endl;
return false;
}
}
MMFItemsData = (const MMFItems_Struct*) ItemsMMF.GetHandle();
if (!MMFItemsData) {
cout << "Error: EMuShareMem: DLLLoadItems: !MMFItemsData (CanWrite=false)" << endl;
return false;
}
*iMaxItemID = MMFItemsData->MaxItemID;
*iItemCount = MMFItemsData->ItemCount;
return true;
}
} else {
cout << "Error Loading Items: Items.cpp: pDLLLoadItems: Open() == false" << endl;
return false;
}
/*
// use a callback so the DB functions are done in the main exe
// this way the DLL doesnt have to open a connection to mysql
if (!cbDBLoadItems(*iItemCount, *iMaxItemID)) {
cout << "Error: EMuShareMem: DLLLoadItems: !cbDBLoadItems" << endl;
return false;
}
*/
// use a callback so the DB functions are done in the main exe
// this way the DLL doesnt have to open a connection to mysql
if (!cbDBLoadItems(*iItemCount, *iMaxItemID)) {
cout << "Error: EMuShareMem: DLLLoadItems: !cbDBLoadItems" << endl;
return false;
}
//Now, Disable the write handle and get the read handle.
//do this for both item struct and serialization data
MMFItemsData_Writable = 0;
ItemsMMF.SetLoaded();
MMFItemsData = (const MMFItems_Struct*) ItemsMMF.GetHandle();
if (!MMFItemsData) {
cout << "Error: EMuShareMem: DLLLoadItems: !MMFItemsData (CanWrite=true)" << endl;
return false;
}
return true;
};
DLLFUNC const Item_Struct* GetItem(uint32 id) {
if (MMFItemsData == 0 || (!ItemsMMF.IsLoaded()) || id > MMF_EQMAX_ITEMS || MMFItemsData->ItemIndex[id] == 0xFFFF)
return 0;
return &MMFItemsData->Items[MMFItemsData->ItemIndex[id]];
}
DLLFUNC const Item_Struct* IterateItems(uint32* NextIndex) {
if (MMFItemsData == 0 || (!ItemsMMF.IsLoaded()) || (*NextIndex) > MMF_EQMAX_ITEMS)
return 0;
do {
if (MMFItemsData->ItemIndex[*NextIndex] != 0xFFFF)
return &MMFItemsData->Items[MMFItemsData->ItemIndex[(*NextIndex)++]];
} while (++(*NextIndex) < MMF_EQMAX_ITEMS);
return 0;
}

23
EMuShareMem/Items.h Normal file
View File

@ -0,0 +1,23 @@
#include "../common/types.h"
#include "../common/eq_packet_structs.h"
#include "../common/EMuShareMem.h"
// MMF_EQMAX_ITEMS: Make sure this is bigger than the highest item ID#
#ifndef MMF_EQMAX_ITEMS
#define MMF_EQMAX_ITEMS 300000
#endif
// MMF_MEMMAX_ITEMS: Maxium number of items to load into memory. Make sure this is bigger
// than the total number of items in the server's database!
struct MMFItems_Struct {
uint32 MaxItemID;
uint32 NextFreeIndex;
uint32 ItemCount;
uint32 ItemIndex[MMF_EQMAX_ITEMS+1];
Item_Struct Items[0];
};
//#define MMF_MAX_ITEMS_MEMSIZE sizeof(MMFItems_Struct) + 256

214
EMuShareMem/Loot.cpp Normal file
View File

@ -0,0 +1,214 @@
#include "../common/debug.h"
#include <memory.h>
#include <iostream>
using namespace std;
#include "Loot.h"
#include "../common/timer.h"
#include "MMF.h"
MMF LootMMF;
const MMFLoot_Struct* MMFLootData = 0;
MMFLoot_Struct* MMFLootData_Writable = 0;
uint32* LootTable;
uint32* LootDrop;
#ifdef _WINDOWS
#define exportfunc extern "C" __declspec(dllexport)
#else
#define exportfunc extern "C"
#endif
exportfunc const LootTable_Struct* GetLootTable(uint32 id) {
return pGetLootTable(id);
};
exportfunc const LootDrop_Struct* GetLootDrop(uint32 id) {
return pGetLootDrop(id);
};
exportfunc bool AddLootTable(uint32 id, const LootTable_Struct* lts) {
return pAddLootTable(id, lts);
};
exportfunc bool AddLootDrop(uint32 id, const LootDrop_Struct* lds) {
return pAddLootDrop(id, lds);
};
exportfunc bool DLLLoadLoot(CALLBACK_DBLoadLoot cbDBLoadLoot,
uint32 iLootTableStructsize, uint32 iLootTableCount, uint32 iMaxLootTable,
uint32 iLootTableEntryStructsize, uint32 iLootTableEntryCount,
uint32 iLootDropStructsize, uint32 iLootDropCount, uint32 iMaxLootDrop,
uint32 iLootDropEntryStructsize, uint32 iLootDropEntryCount
) {
return pDLLLoadLoot(cbDBLoadLoot,
iLootTableStructsize, iLootTableCount, iMaxLootTable,
iLootTableEntryStructsize, iLootTableEntryCount,
iLootDropStructsize, iLootDropCount, iMaxLootDrop,
iLootDropEntryStructsize, iLootDropEntryCount);
};
bool pAddLootTable(uint32 id, const LootTable_Struct* lts) {
if (!MMFLootData_Writable)
return false;
if (id > MMFLootData_Writable->MaxLootTableID)
return false;
if (!LootTable || LootTable[id] != 0)
return false;
uint32 tmp = sizeof(LootTable_Struct) + (sizeof(LootTableEntries_Struct) * lts->NumEntries);
if (MMFLootData_Writable->dataindex + tmp >= MMFLootData_Writable->datamax)
return false;
LootTable[id] = MMFLootData_Writable->dataindex;
memcpy(&MMFLootData_Writable->data[MMFLootData_Writable->dataindex], lts, tmp);
MMFLootData_Writable->dataindex += tmp;
return true;
}
bool pAddLootDrop(uint32 id, const LootDrop_Struct* lds) {
if (!MMFLootData_Writable)
return false;
if (id > MMFLootData_Writable->MaxLootDropID)
return false;
if (!LootDrop || LootDrop[id] != 0)
return false;
uint32 tmp = sizeof(LootDrop_Struct) + (sizeof(LootDropEntries_Struct) * lds->NumEntries);
if (MMFLootData_Writable->dataindex + tmp >= MMFLootData_Writable->datamax)
return false;
LootDrop[id] = MMFLootData_Writable->dataindex;
memcpy(&MMFLootData_Writable->data[MMFLootData_Writable->dataindex], lds, tmp);
MMFLootData_Writable->dataindex += tmp;
return true;
}
bool pDLLLoadLoot(CALLBACK_DBLoadLoot cbDBLoadLoot,
uint32 iLootTableStructsize, uint32 iLootTableCount, uint32 iMaxLootTable,
uint32 iLootTableEntryStructsize, uint32 iLootTableEntryCount,
uint32 iLootDropStructsize, uint32 iLootDropCount, uint32 iMaxLootDrop,
uint32 iLootDropEntryStructsize, uint32 iLootDropEntryCount
) {
#if 0
cout << "iLootTableCount: " << iLootTableCount << endl;
cout << "iMaxLootTable: " << iMaxLootTable << endl;
cout << "iLootTableEntryCount: " << iLootTableEntryCount << endl;
cout << "iLootDropCount: " << iLootDropCount << endl;
cout << "iMaxLootDrop: " << iMaxLootDrop << endl;
cout << "iLootDropEntryCount: " << iLootDropEntryCount << endl;
#endif
if (iLootTableStructsize != sizeof(LootTable_Struct)) {
cout << "Error: EMuShareMem: DLLLoadLoot: iLootTableStructsize != sizeof(LootTable_Struct)" << endl;
cout << "Item_Struct has changed, EMuShareMem.dll needs to be recompiled." << endl;
return false;
}
if (iLootTableEntryStructsize != sizeof(LootTableEntries_Struct)) {
cout << "Error: EMuShareMem: DLLLoadLoot: iLootTableEntryStructsize != sizeof(LootTableEntries_Struct)" << endl;
cout << "Item_Struct has changed, EMuShareMem.dll needs to be recompiled." << endl;
return false;
}
if (iLootDropStructsize != sizeof(LootDrop_Struct)) {
cout << "Error: EMuShareMem: DLLLoadLoot: iLootDropStructsize != sizeof(LootDrop_Struct)" << endl;
cout << "Item_Struct has changed, EMuShareMem.dll needs to be recompiled." << endl;
return false;
}
if (iLootDropEntryStructsize != sizeof(LootDropEntries_Struct)) {
cout << "Error: EMuShareMem: DLLLoadLoot: iLootDropEntryStructsize != sizeof(LootDropEntries_Struct)" << endl;
cout << "Item_Struct has changed, EMuShareMem.dll needs to be recompiled." << endl;
return false;
}
uint32 tmpMemSize = sizeof(MMFLoot_Struct) + 256
+ (sizeof(uint32) * (iMaxLootTable+1))
+ (sizeof(LootTable_Struct) * iLootTableCount) + (sizeof(LootTableEntries_Struct) * iLootTableEntryCount)
+ (sizeof(uint32) * (iMaxLootDrop+1))
+ (sizeof(LootDrop_Struct) * iLootDropCount) + (sizeof(LootDropEntries_Struct) * iLootDropEntryCount)
;
if (LootMMF.Open("EQEMuLoot", tmpMemSize)) {
if (LootMMF.CanWrite()) {
MMFLootData_Writable = (MMFLoot_Struct*) LootMMF.GetWriteableHandle();
if (!MMFLootData_Writable) {
cout << "Error: EMuShareMem: DLLLoadLoot: !MMFLootData_Writable" << endl;
return false;
}
memset(MMFLootData_Writable, 0, tmpMemSize);
MMFLootData_Writable->LootTableCount = iLootTableCount;
MMFLootData_Writable->MaxLootTableID = iMaxLootTable;
MMFLootData_Writable->LootDropCount = iLootDropCount;
MMFLootData_Writable->MaxLootDropID = iMaxLootDrop;
MMFLootData_Writable->datamax = tmpMemSize - sizeof(MMFLoot_Struct);
MMFLootData_Writable->dataindex = 0;
MMFLootData_Writable->LootTableOffset = MMFLootData_Writable->dataindex;
MMFLootData_Writable->dataindex += (sizeof(uint32) * (iMaxLootTable+1));
MMFLootData_Writable->LootDropOffset = MMFLootData_Writable->dataindex;
MMFLootData_Writable->dataindex += (sizeof(uint32) * (iMaxLootDrop+1));
LootTable = (uint32*) &MMFLootData_Writable->data[MMFLootData_Writable->LootTableOffset];
LootDrop = (uint32*) &MMFLootData_Writable->data[MMFLootData_Writable->LootDropOffset];
// use a callback so the DB functions are done in the main exe
// this way the DLL doesnt have to open a connection to mysql
if (!cbDBLoadLoot()) {
cout << "Error: EMuShareMem: DLLLoadLoot: !cbDBLoadLoot" << endl;
return false;
}
MMFLootData_Writable = 0;
LootMMF.SetLoaded();
}
else {
if (!LootMMF.IsLoaded()) {
Timer::SetCurrentTime();
uint32 starttime = Timer::GetCurrentTime();
while ((!LootMMF.IsLoaded()) && ((Timer::GetCurrentTime() - starttime) < 300000)) {
Sleep(10);
Timer::SetCurrentTime();
}
if (!LootMMF.IsLoaded()) {
cout << "Error: EMuShareMem: DLLLoadLoot: !LootMMF.IsLoaded() (timeout)" << endl;
return false;
}
}
}
}
else {
cout << "Error Loading Loot: Loot.cpp: pDLLLoadLoot: Open() == false" << endl;
return false;
}
MMFLootData = (const MMFLoot_Struct*) LootMMF.GetHandle();
if (!MMFLootData) {
cout << "Error: EMuShareMem: DLLLoadLoot: !MMFLootData" << endl;
MMFLootData = 0;
return false;
}
if (MMFLootData->LootTableCount != iLootTableCount
|| MMFLootData->MaxLootTableID != iMaxLootTable
|| MMFLootData->LootDropCount != iLootDropCount
|| MMFLootData->MaxLootDropID != iMaxLootDrop) {
cout << "Error: EMuShareMem: DLLLoadLoot: Count/Max mismatch" << endl;
MMFLootData = 0;
return false;
}
LootTable = (uint32*) &MMFLootData->data[MMFLootData->LootTableOffset];
LootDrop = (uint32*) &MMFLootData->data[MMFLootData->LootDropOffset];
return true;
};
const LootTable_Struct* pGetLootTable(uint32 id) {
if (MMFLootData == 0 || !LootMMF.IsLoaded())
return 0;
if (id > MMFLootData->MaxLootTableID || LootTable[id] == 0)
return 0;
return (LootTable_Struct*) &MMFLootData->data[LootTable[id]];
}
const LootDrop_Struct* pGetLootDrop(uint32 id) {
if (MMFLootData == 0 || !LootMMF.IsLoaded())
return 0;
if (id > MMFLootData->MaxLootDropID || LootDrop[id] == 0)
return 0;
return (LootDrop_Struct*) &MMFLootData->data[LootDrop[id]];
}

29
EMuShareMem/Loot.h Normal file
View File

@ -0,0 +1,29 @@
#include "../common/types.h"
#include "../common/eq_packet_structs.h"
#include "../common/EMuShareMem.h"
#pragma pack(1)
struct MMFLoot_Struct {
bool Loaded;
uint32 MaxLootTableID;
uint32 LootTableCount;
uint32 LootTableOffset;
uint32 MaxLootDropID;
uint32 LootDropCount;
uint32 LootDropOffset;
uint32 datamax;
uint32 dataindex;
uint8 data[0];
};
#pragma pack()
bool pDLLLoadLoot(CALLBACK_DBLoadLoot cbDBLoadLoot,
uint32 iLootTableStructsize, uint32 iLootTableCount, uint32 iMaxLootTable,
uint32 iLootTableEntryStructsize, uint32 iLootTableEntryCount,
uint32 iLootDropStructsize, uint32 iLootDropCount, uint32 iMaxLootDrop,
uint32 iLootDropEntryStructsize, uint32 iLootDropEntryCount
);
bool pAddLootTable(uint32 id, const LootTable_Struct* lts);
bool pAddLootDrop(uint32, const LootDrop_Struct* lds);
const LootTable_Struct* pGetLootTable(uint32 id);
const LootDrop_Struct* pGetLootDrop(uint32 id);

353
EMuShareMem/MMF.cpp Normal file
View File

@ -0,0 +1,353 @@
// start mingw
#ifdef __MINGW32__
#define __try
#define __finally
#endif
// end mingw
#include "MMF.h"
#include <iostream>
using namespace std;
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#ifdef _WINDOWS
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#define strncasecmp _strnicmp
#define strcasecmp _stricmp
#else
#include "MMFMutex.h"
#include "../common/unix.h"
#endif
MMF::MMF() {
SharedMemory = 0;
pCanWrite = false;
#ifdef _WINDOWS
hMapObject = NULL;
lpvMem = 0;
#else
lpvMem = 0;
pMMFMutex = 0;
m_alloc = false;
#endif
}
MMF::~MMF() {
Close();
}
bool MMF::Open(const char* iName, uint32 iSize) {
if (iSize < 1) {
cout << "Error Loading MMF: " << __FILE__ << ":" << __LINE__ << " OpenMMF: iSize < 1" << endl;
return false;
}
if (strlen(iName) < 2) {
cout << "Error Loading MMF: " << __FILE__ << ":" << __LINE__ << " OpenMMF: strlen(iName) < 2" << endl;
return false;
}
char MMFname[200];
memset(MMFname, 0, sizeof(MMFname));
snprintf(MMFname, sizeof(MMFname), "memfilemap_%s", iName);
uint32 tmpSize = sizeof(MMF_Struct) + iSize;
#ifdef _WINDOWS
char MMFMutexName[200];
memset(MMFMutexName, 0, sizeof(MMFMutexName));
snprintf(MMFMutexName, sizeof(MMFMutexName), "MutexToProtectOpenMMF_%s", iName);
HANDLE hMutex;
hMutex = CreateMutex(
NULL, // no security attributes
FALSE, // initially not owned
MMFMutexName); // name of mutex
if (hMutex == NULL) {
cout << "Error Loading MMF: " << __FILE__ << ":" << __LINE__ << " OpenMMF: hMutex == Null" << endl;
return false;
}
DWORD dwWaitResult;
// Request ownership of mutex.
dwWaitResult = WaitForSingleObject(
hMutex, // handle to mutex
2000L); // two-second time-out interval
if (dwWaitResult != WAIT_OBJECT_0) {
// Mutex not aquired, crap out
cout << "Error Loading MMF: " << __FILE__ << ":" << __LINE__ << " OpenMMF: dwWaitResult != WAIT_OBJECT_0" << endl;
return false;
}
// Finally, ready to rock.
bool fInit = false;
__try {
hMapObject = CreateFileMapping(
INVALID_HANDLE_VALUE, // use paging file
NULL, // default security attributes
PAGE_READWRITE, // read/write access
0, // size: high 32-bits
tmpSize, // size: low 32-bits
MMFname); // name of map object
if (hMapObject == NULL) {
cout << "Error Loading MMF: " << __FILE__ << ":" << __LINE__ << " OpenMMF: hMapObject == Null" << endl;
return false;
}
// The first process to attach initializes memory.
fInit = (bool) (GetLastError() != ERROR_ALREADY_EXISTS);
// Get a pointer to the file-mapped shared memory.
lpvMem = MapViewOfFile(
hMapObject, // object to map view of
FILE_MAP_WRITE, // read/write access
0, // high offset: map from
0, // low offset: beginning
0); // default: map entire file
if (lpvMem == NULL) {
cout << "Error Loading MMF: " << __FILE__ << ":" << __LINE__ << " OpenMMF: lpvMem == Null" << endl;
Close();
return false;
}
SharedMemory = (MMF_Struct*) lpvMem;
// Initialize memory if this is the first process.
if (fInit) {
memset(lpvMem, 0, sizeof(MMF_Struct));
pCanWrite = true;
SharedMemory->Loaded = false;
SharedMemory->datasize = iSize;
}
else {
pCanWrite = false;
if (SharedMemory->datasize != iSize) {
cout << "Error Loading MMF: " << __FILE__ << ":" << __LINE__ << " OpenMMF: SharedMemory->datasize != iSize" << endl;
Close();
return false;
}
}
} // end of try block
__finally {
// Clean up the Mutex stuff
if (!ReleaseMutex(hMutex)) {
cout << "Error Loading MMF: " << __FILE__ << ":" << __LINE__ << " OpenMMF: !ReleaseMutex(hMutex)" << endl;
Close();
return false;
}
}
CloseHandle(hMutex);
return true;
#else //else, NOT WINDOWS
int load_share;
//int max_share = 7;
key_t share_key;
switch (MMFname[16]) {
case 'I': load_share = 0; break;
case 'N': load_share = 1; break;
case 'D': load_share = 2; break;
case 'S': load_share = 3; break;
case 'F': load_share = 4; break;
case 'L': load_share = 5; break;
case 'M': load_share = 6; break;
case 'O': load_share = 7; break;
case 'Z': load_share = 8; break;
case 'K': load_share = 9; break;
#ifdef CATCH_CRASH
default:
cerr<<"Failed to load shared memory segment="<<MMFname<<" ("<<MMFname[16]<<")"<<endl;
// malloc some memory here or something fancy
return false; // and make this return true
break;
#else
default: cerr<<"FATAL="<<(char)MMFname[16]<<endl; return false; break;
#endif
}
switch (load_share) {
// Item
case 0: share_key = ftok(".", 'I'); break;
// Npctype
case 1: share_key = ftok(".", 'N'); break;
// Door
case 2: share_key = ftok(".", 'D'); break;
// Spell
case 3: share_key = ftok(".", 'S'); break;
// Faction
case 4: share_key = ftok(".", 'F'); break;
// Loot
case 5: share_key = ftok(".", 'L'); break;
// ??
case 6: share_key = ftok(".", 'M'); break;
// Opcodes
case 7: share_key = ftok(".", 'O'); break;
// Item Serialization
case 8: share_key = ftok(".", 'Z'); break;
// Skills
case 9: share_key = ftok(".", 'K'); break;
// ERROR Fatal
default: cerr<<"Opps!"<<endl; share_key = 0xFF; break;
}
pMMFMutex = new MMFMutex(share_key);
if (!pMMFMutex){
assert(false);
}
//if (!tmpSize) {
int share_id = shmget(share_key, tmpSize, IPC_CREAT|IPC_EXCL|SHM_R|SHM_W);
if ( share_id <= 0) {
share_id = shmget(share_key, tmpSize, IPC_CREAT|IPC_NOWAIT);
if (share_id <= 0) {
shmid_ds mem_size;
share_id = shmget(share_key, 1, IPC_CREAT|IPC_NOWAIT|SHM_R|SHM_W);
if(share_id == -1) {
cerr << "failed to get 0-length shared mem: " << strerror(errno) << endl;
}
if ((lpvMem = shmat(share_id, NULL,SHM_RDONLY)) == (void *)-1) {
cerr << "shmat failed! " << strerror(errno) << endl;
}
if( (shmctl(share_id, IPC_STAT, &mem_size)) == 0){
if (mem_size.shm_segsz != int(tmpSize)){ //comparison between signed and unsigned integer expressions
cout<<"[Warning] requested shared memory of size:"<<tmpSize<<" but that Key is already in use with size:"<< mem_size.shm_segsz<<endl;
shmid_ds mem_users;
if( (shmctl(share_id, IPC_STAT, &mem_users)) == 0 && mem_users.shm_nattch == 1){
cout<<"[Warning] Attempting resize"<<endl;
shmctl(share_id, IPC_RMID, 0);
shmdt(lpvMem);
if ((share_id = shmget(share_key, tmpSize, IPC_CREAT|IPC_EXCL|SHM_R|SHM_W)) <= 0) {
// Failed proceed on malloc
cerr<<"[Error] Failed to resize" << strerror(errno) <<endl;
}
else{
cerr<<"[Error] Resize successful." << endl;
// Success
lpvMem = shmat(share_id, NULL, SHM_R|SHM_W);
memset(lpvMem, 0, sizeof(MMF_Struct));
pCanWrite = true;
SharedMemory = (MMF_Struct*) lpvMem;
SharedMemory->Loaded = false;
SharedMemory->datasize = iSize;
pMMFMutex->Release(this);
delete pMMFMutex;
return true;
}
}
else{
cout<<"[Warning] Resize not possible"<<endl;
}
}
}
// Can not attatch to shared memory we'll malloc it here
if ((lpvMem == 0 || lpvMem == (void *)-1) && (lpvMem = malloc(tmpSize))) {
cout<<"[Warning] Could not attach to shared memory proceeding on isolated memory (share_id <= 0)"<<endl;
// Success!
m_alloc = true;
memset(lpvMem, 0, sizeof(MMF_Struct));
pCanWrite = true;
SharedMemory = (MMF_Struct*) lpvMem;
SharedMemory->datasize = iSize;
SharedMemory->Loaded = false;
pMMFMutex->Release(this);
delete pMMFMutex;
return true;
} else if (!lpvMem){
//LogFile->write(EQEMuLog::Error, "Could not connect to shared memory and allocation of isolated memory failed.");
cout<<"Could not connect to shared memory and allocation of isolated memory failed."<<endl;
pMMFMutex->Release(this);
delete pMMFMutex;
exit(1);
}
pCanWrite = false;
SharedMemory = (MMF_Struct*) lpvMem;
if (SharedMemory->datasize != iSize) {
cerr<<"SharedMemory->datasize("<<SharedMemory->datasize<<") != iSize("<<iSize<<"), We can rebuild him faster better STRONGER!"<<endl;
cerr<<"Or not.. restart all servers on this machine"<<endl;
shmctl(share_id, IPC_RMID, 0);
pMMFMutex->Release(this);
exit(1);
}
pMMFMutex->Release(this);
delete pMMFMutex;
return true;
}
shmid_ds mem_users;
if ((shmctl(share_id, IPC_STAT, &mem_users)) != 0) {
if ((lpvMem = malloc(tmpSize))) {
// Success!
cout<<"[Warning] Could not attach to shared memory proceeding on isolated memory"<<endl;
m_alloc = true;
memset(lpvMem, 0, sizeof(MMF_Struct));
pCanWrite = true;
SharedMemory = (MMF_Struct*) lpvMem;
SharedMemory->datasize = iSize;
SharedMemory->Loaded = false;
pMMFMutex->Release(this);
delete pMMFMutex;
return true;
} else {
//LogFile->write(EQEMuLog::Error, "Could not connect to shared memory and allocation of isolated memory failed.");
cout<<"Could not connect to shared memory and allocation of isolated memory failed."<<endl;
pMMFMutex->Release(this);
delete pMMFMutex;
exit(1);
}
}
lpvMem = shmat(share_id, NULL,SHM_RDONLY);
pCanWrite = false;
SharedMemory = (MMF_Struct*) lpvMem;
//cerr << "lpvMem=" << (int)lpvMem << endl;
if (lpvMem==(void *)-1 || SharedMemory->datasize != iSize) {
cerr<<"SharedMemory->datasize("<<SharedMemory->datasize<<") != iSize("<<iSize<<"), or "<<((void *)lpvMem)<<"==-1, We can rebuild him faster better STRONGER!"<<endl;
cerr<<"Or not.. restart all servers on this machine"<<endl;
shmctl(share_id, IPC_RMID, 0);
pMMFMutex->Release(this);
exit(1);
}
pMMFMutex->Release(this);
delete pMMFMutex;
return true;
}
lpvMem = shmat(share_id, NULL, SHM_R|SHM_W);
memset(lpvMem, 0, sizeof(MMF_Struct));
pCanWrite = true;
SharedMemory = (MMF_Struct*) lpvMem;
SharedMemory->Loaded = false;
SharedMemory->datasize = iSize;
//}
pMMFMutex->Release(this);
delete pMMFMutex;
return true;
#endif //end NOT WINDOWS
}
void MMF::Close() {
SharedMemory = 0;
pCanWrite = false;
#ifdef _WINDOWS
if (lpvMem) {
// Unmap shared memory from the process's address space.
UnmapViewOfFile(lpvMem);
lpvMem = 0;
}
if (hMapObject) {
// Close the process's handle to the file-mapping object.
CloseHandle(hMapObject);
hMapObject = NULL;
}
#else
if (lpvMem) {
if (m_alloc == true)
free(lpvMem);
else
if (shmdt(lpvMem) == -1)
//LogFile->write(EQEMuLog::Error, "Warning something odd happened freeing shared memory");
cout<<"Warning something odd happened freeing shared memory"<<endl;
lpvMem = 0;
}
#endif
}

46
EMuShareMem/MMF.h Normal file
View File

@ -0,0 +1,46 @@
#ifndef MMF_H
#define MMF_H
#include "../common/types.h"
#ifdef _WINDOWS
#include <windows.h>
#else
//#include "MMFMutex.h"
class MMFMutex;
#endif
class MMF {
public:
struct MMF_Struct {
bool Loaded;
uint32 datasize;
uint8 data[0];
};
MMF();
virtual ~MMF();
bool Open(const char* iName, uint32 iSize);
void Close();
const void* GetHandle() { if (IsLoaded()) { return SharedMemory->data; } return 0; }
void* GetWriteableHandle() { if (!IsLoaded() && CanWrite()) { return SharedMemory->data; } return 0; }
inline bool IsOpen() { return (bool) (SharedMemory != 0); }
inline bool IsLoaded() { if (SharedMemory) { return SharedMemory->Loaded; } return false; }
bool SetLoaded() { if (SharedMemory && CanWrite()) { SharedMemory->Loaded = true; return true; } return false; }
inline bool CanWrite() { if (SharedMemory) { return pCanWrite; } return false; }
#ifndef WIN32
bool m_alloc;
#endif
private:
bool pCanWrite;
MMF_Struct* SharedMemory;
#ifdef _WINDOWS
HANDLE hMapObject;
LPVOID lpvMem;
#else
void* lpvMem;
MMFMutex* pMMFMutex;
#endif
};
#endif

126
EMuShareMem/MMFMutex.cpp Normal file
View File

@ -0,0 +1,126 @@
#include "MMFMutex.h"
#ifndef WIN32
MMFMutex::MMFMutex( int key )
{
m_key = key;
if( m_key == 0 )
{
// initialize POSIX semaphore
sem_init( &m_semaphore, 0, 1);
}
else
{
// currently, this thread does not own the semaphore
m_owner = 0;
m_recursive_count = 0;
// try to get an existing semaphore. the access permissions are "full access for everyone"
m_id = semget(m_key, 1, 0x1b6);
if( m_id == -1 )
{
// it doesn't exist yet, try to create a new one
m_id = semget(m_key, 1, IPC_CREAT | 0x1b6);
if( m_id != -1 )
{
// initialize it to 1
semun data;
data.val = 1;
semctl(m_id, 0, SETVAL, data);
}
}
}
}
MMFMutex::~MMFMutex()
{
if( m_key == 0 )
{
sem_destroy(&m_semaphore);
}
else
{
semctl(m_id, 0, IPC_RMID, 0);
}
}
bool MMFMutex::Lock( uint32 dwTimeout )
{
if( m_owner == pthread_self() )
{
m_recursive_count++;
return true;
}
bool bUseTimeout = (dwTimeout != 0);
while(true) {
bool bGotSemaphore = false;
if( m_key == 0 )
{
bGotSemaphore = (sem_trywait(&m_semaphore) == 0);
}
else
{
struct sembuf operations[1];
operations[0].sem_num = 0;
operations[0].sem_op = -1;
operations[0].sem_flg = SEM_UNDO|IPC_NOWAIT;
bGotSemaphore = (semop(m_id, operations, 1) >= 0);
}
if( bGotSemaphore )
{
m_owner = pthread_self();
m_recursive_count = 1;
return true;
}
sleep(1);
if( bUseTimeout )
{
if( dwTimeout > 1000 )
dwTimeout -= 1000;
else
dwTimeout = 0;
if( dwTimeout == 0 )
return false;
}
}
}
void MMFMutex::Release(const MMF* pMMF)
{
if( m_owner != pthread_self() && pMMF->m_alloc != true )
{
//We're supposed to explode here with an assert
//assert(false);
}
else if ( pMMF->m_alloc == true ){
// Just do it nothing is useing but us
return;
}
else if( m_recursive_count > 1 )
{
m_recursive_count--;
}
else
{
if( m_key == 0 )
{
sem_post(&m_semaphore);
}
else
{
struct sembuf operations[1];
operations[0].sem_num = 0;
operations[0].sem_op = 1;
operations[0].sem_flg = SEM_UNDO;
semop(m_id, operations, 1);
}
m_recursive_count = 0;
m_owner = 0;
}
}
#endif //!WIN32

43
EMuShareMem/MMFMutex.h Normal file
View File

@ -0,0 +1,43 @@
#ifndef MMFMUTEX_H
#define MMFMUTEX_H
#ifndef WIN32
#include <sys/types.h> // moved before sys/shm.h for freeBSD
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <pthread.h>
#include <unistd.h>
#include <assert.h>
#include "../common/types.h"
#include "MMF.h"
// the manuals say you have to define this struct your self.
#if !defined FREEBSD || defined __NetBSD__ // for BSDs
union semun
{
int val;
struct semid_ds* buf;
unsigned short int *array;
struct seminfo *__buf;
};
#endif // for freeBSD
class MMFMutex
{
public:
MMFMutex(int iIndex);
virtual ~MMFMutex();
bool Lock( uint32 dwTimeout = 0 );
void Release(const MMF*);
protected:
int m_id;
key_t m_key;
pthread_t m_owner;
sem_t m_semaphore;
int m_recursive_count;
};
#endif //!WIN32
#endif

View File

@ -0,0 +1,178 @@
#include "../common/debug.h"
#ifdef _WINDOWS
#include <windows.h>
#else
#include "../common/unix.h"
#endif
#include <memory.h>
#include <iostream>
using namespace std;
#include "NPCFactionLists.h"
#include "../common/timer.h"
#include "MMF.h"
MMF NPCFactionListsMMF;
const MMFNPCFactionLists_Struct* MMFNPCFactionListsData = 0;
MMFNPCFactionLists_Struct* MMFNPCFactionListsData_Writable = 0;
#ifdef _WINDOWS
extern "C" __declspec(dllexport) const NPCFactionList* GetNPCFactionList(uint32 id) {
return pGetNPCFactionList(id);
};
extern "C" __declspec(dllexport) bool AddNPCFactionList(uint32 id, const NPCFactionList* nfl) {
return pAddNPCFactionList(id, nfl);
};
extern "C" __declspec(dllexport) bool DLLLoadNPCFactionLists(CALLBACK_DBLoadNPCFactionLists cbDBLoadNPCFactionLists, uint32 iNPCFactionListStructSize, int32* iNPCFactionListsCount, uint32* iMaxNPCFactionListID, uint8 iMaxNPCFactions) {
return pDLLLoadNPCFactionLists(cbDBLoadNPCFactionLists, iNPCFactionListStructSize, iNPCFactionListsCount, iMaxNPCFactionListID, iMaxNPCFactions);
};
extern "C" __declspec(dllexport) bool SetNPCFaction(uint32 id, uint32* factionid, int32* factionvalue, int8 *factionnpcvalue, uint8 *factiontemp) {
return pSetNPCFaction(id, factionid, factionvalue, factionnpcvalue, factiontemp);
}
#else
extern "C" const NPCFactionList* GetNPCFactionList(uint32 id) {
return pGetNPCFactionList(id);
};
extern "C" bool AddNPCFactionList(uint32 id, const NPCFactionList* nfl) {
return pAddNPCFactionList(id, nfl);
};
extern "C" bool DLLLoadNPCFactionLists(CALLBACK_DBLoadNPCFactionLists cbDBLoadNPCFactionLists, uint32 iNPCFactionListStructSize, int32* iNPCFactionListsCount, uint32* iMaxNPCFactionListID, uint8 iMaxNPCFactions) {
return pDLLLoadNPCFactionLists(cbDBLoadNPCFactionLists, iNPCFactionListStructSize, iNPCFactionListsCount, iMaxNPCFactionListID, iMaxNPCFactions);
};
extern "C" bool SetNPCFaction(uint32 id, uint32* factionid, int32* factionvalue, int8 *factionnpcvalue, uint8 *factiontemp) {
return pSetNPCFaction(id, factionid, factionvalue, factionnpcvalue, factiontemp);
}
#endif
bool pAddNPCFactionList(uint32 id, const NPCFactionList* nfl) {
if (!MMFNPCFactionListsData_Writable){
if (EQDEBUG>=1) cout<<"[Debug] !MMFNPCFactionListsData_Writable"<<endl;
return false;
}
if (id > MMF_MAX_NPCFactionList_ID || MMFNPCFactionListsData_Writable->NextFreeIndex >= MMFNPCFactionListsData_Writable->NPCFactionListCount){
if (EQDEBUG>=1) cout<<"[Debug] id > MMF_MAX_NPCFactionList_ID || MMFNPCFactionListsData_Writable->NextFreeIndex >= MMFNPCFactionListsData_Writable->NPCFactionListCount"<<endl;
return false;
}
if (MMFNPCFactionListsData_Writable->NPCFactionListIndex[id] != 0xFFFFFFFF){
if (EQDEBUG>=1) cout<<"[Debug] MMFNPCFactionListsData_Writable->NPCFactionListIndex[id] != 0xFFFFFFFF"<<endl;
return false;
}
MMFNPCFactionListsData_Writable->NPCFactionListIndex[id] = MMFNPCFactionListsData_Writable->NextFreeIndex++;
memcpy(&MMFNPCFactionListsData_Writable->NPCFactionLists[MMFNPCFactionListsData_Writable->NPCFactionListIndex[id]], nfl, sizeof(NPCFactionList));
return true;
}
bool pSetNPCFaction(uint32 id, uint32* factionid, int32* factionvalue, int8 *factionnpcvalue, uint8 *factiontemp) {
if (!MMFNPCFactionListsData_Writable) {
if(EQDEBUG>=1) cout<<"[Debug] !MMFNPCFactionListsData_Writable"<<endl;
return false;
}
if (id > MMF_MAX_NPCFactionList_ID) {
if(EQDEBUG>=1) cout<<"[Debug] id > MMF_MAX_NPCFactionList_ID"<<endl;
return false;
}
if (MMFNPCFactionListsData_Writable->NPCFactionListIndex[id] == 0xFFFFFFFF) {
if(EQDEBUG>=1) cout<<"[Debug] MMFNPCFactionListsData_Writable->NPCFactionListIndex[id="<<id<<"] == 0xFFFFFFFF"<<endl;
return false;
}
for (int i=0; i<MAX_NPC_FACTIONS; i++) {
MMFNPCFactionListsData_Writable->NPCFactionLists[MMFNPCFactionListsData_Writable->NPCFactionListIndex[id]].factionid[i] = factionid[i];
MMFNPCFactionListsData_Writable->NPCFactionLists[MMFNPCFactionListsData_Writable->NPCFactionListIndex[id]].factionvalue[i] = factionvalue[i];
MMFNPCFactionListsData_Writable->NPCFactionLists[MMFNPCFactionListsData_Writable->NPCFactionListIndex[id]].factionnpcvalue[i] = factionnpcvalue[i];
MMFNPCFactionListsData_Writable->NPCFactionLists[MMFNPCFactionListsData_Writable->NPCFactionListIndex[id]].factiontemp[i] = factiontemp[i];
}
return true;
}
bool pDLLLoadNPCFactionLists(CALLBACK_DBLoadNPCFactionLists cbDBLoadNPCFactionLists, uint32 iNPCFactionListStructSize, int32* iNPCFactionListsCount, uint32* iMaxNPCFactionListID, uint8 iMaxNPCFactions) {
if (iNPCFactionListStructSize != sizeof(NPCFactionList)) {
cout << "Error: EMuShareMem: DLLLoadNPCFactionLists: iNPCFactionListStructSize != sizeof(NPCFactionList)" << endl;
cout << "NPCFactionList struct has changed, EMuShareMem.dll needs to be recompiled." << endl;
return false;
}
if (iMaxNPCFactions != MAX_NPC_FACTIONS) {
cout << "Error: EMuShareMem: DLLLoadNPCFactionLists: iMaxNPCFactions != MAX_NPC_FACTIONS" << endl;
cout << "NPCFactionList struct has changed, EMuShareMem.dll needs to be recompiled." << endl;
return false;
}
if (*iMaxNPCFactionListID > MMF_MAX_NPCFactionList_ID) {
cout << "Error: EMuShareMem: DLLLoadNPCFactionLists: iMaxNPCFactions > MMF_MAX_NPCFactionList_ID" << endl;
cout << "You need to increase the define in NPCFactionList.h." << endl;
return false;
}
uint32 tmpMemSize = sizeof(MMFNPCFactionLists_Struct) + 256 + (sizeof(NPCFactionList) * (*iNPCFactionListsCount));
if (NPCFactionListsMMF.Open("EQEMuFactionLists", tmpMemSize)) {
// MMFNPCFactionListsData = (const MMFNPCFactionLists_Struct*) NPCFactionListsMMF.GetHandle();
if (NPCFactionListsMMF.CanWrite()) {
MMFNPCFactionListsData_Writable = (MMFNPCFactionLists_Struct*) NPCFactionListsMMF.GetWriteableHandle();
if (!MMFNPCFactionListsData_Writable) {
cout << "Error: EMuShareMem: DLLLoadNPCFactionLists: !MMFNPCFactionListsData_Writable" << endl;
return false;
}
memset(MMFNPCFactionListsData_Writable, 0, tmpMemSize);
for(int i=0; i<MMF_MAX_NPCFactionList_ID; i++)
MMFNPCFactionListsData_Writable->NPCFactionListIndex[i] = 0xFFFFFFFF;
MMFNPCFactionListsData_Writable->MaxNPCFactionListID = *iMaxNPCFactionListID;
MMFNPCFactionListsData_Writable->NPCFactionListCount = *iNPCFactionListsCount;
// use a callback so the DB functions are done in the main exe
// this way the DLL doesnt have to open a connection to mysql
if (!cbDBLoadNPCFactionLists(MMFNPCFactionListsData_Writable->NPCFactionListCount, MMFNPCFactionListsData_Writable->MaxNPCFactionListID)) {
cout << "Error: EMuShareMem: DLLLoadNPCFactionLists: !cbDBLoadNPCFactionLists" << endl;
return false;
}
MMFNPCFactionListsData_Writable = 0;
NPCFactionListsMMF.SetLoaded();
MMFNPCFactionListsData = (const MMFNPCFactionLists_Struct*) NPCFactionListsMMF.GetHandle();
if (!MMFNPCFactionListsData) {
cout << "Error: EMuShareMem: DLLLoadNPCFactionLists: !MMFNPCFactionListsData (CanWrite=true)" << endl;
return false;
}
return true;
}
else {
if (!NPCFactionListsMMF.IsLoaded()) {
Timer::SetCurrentTime();
uint32 starttime = Timer::GetCurrentTime();
while ((!NPCFactionListsMMF.IsLoaded()) && ((Timer::GetCurrentTime() - starttime) < 300000)) {
Sleep(100);
Timer::SetCurrentTime();
}
if (!NPCFactionListsMMF.IsLoaded()) {
cout << "Error: EMuShareMem: DLLLoadNPCFactionLists: !NPCFactionListsMMF.IsLoaded() (timeout)" << endl;
return false;
}
}
MMFNPCFactionListsData = (const MMFNPCFactionLists_Struct*) NPCFactionListsMMF.GetHandle();
if (!MMFNPCFactionListsData) {
cout << "Error: EMuShareMem: DLLLoadNPCFactionLists: !MMFNPCFactionListsData (CanWrite=false)" << endl;
return false;
}
*iMaxNPCFactionListID = MMFNPCFactionListsData->MaxNPCFactionListID;
*iNPCFactionListsCount = MMFNPCFactionListsData->NPCFactionListCount;
return true;
}
}
else {
cout << "Error Loading NPCFactionLists: NPCFactionLists.cpp: pDLLLoadNPCFactionLists: Open() == false" << endl;
return false;
}
return false;
};
const NPCFactionList* pGetNPCFactionList(uint32 id) {
if (MMFNPCFactionListsData == 0 || (!NPCFactionListsMMF.IsLoaded()) || id > MMF_MAX_NPCFactionList_ID || MMFNPCFactionListsData->NPCFactionListIndex[id] == 0xFFFFFFFF)
return 0;
return &MMFNPCFactionListsData->NPCFactionLists[MMFNPCFactionListsData->NPCFactionListIndex[id]];
}

View File

@ -0,0 +1,22 @@
#include "../common/types.h"
#include "../zone/features.h"
#include "../zone/faction.h"
#include "../common/EMuShareMem.h"
// MMF_MAX_NPCFactionList_ID: Make sure this is bigger than the highest NPCFactionList ID#
#ifndef MMF_MAX_NPCFactionList_ID
#define MMF_MAX_NPCFactionList_ID 50000
#endif
struct MMFNPCFactionLists_Struct {
uint32 MaxNPCFactionListID;
uint32 NextFreeIndex;
uint32 NPCFactionListCount;
uint32 NPCFactionListIndex[MMF_MAX_NPCFactionList_ID+1];
NPCFactionList NPCFactionLists[0];
};
bool pDLLLoadNPCFactionLists(CALLBACK_DBLoadNPCFactionLists cbDBLoadNPCFactionLists, uint32 iNPCFactionListStructSize, int32* iNPCFactionListCount, uint32* iMaxNPCFactionListID, uint8 iMaxNPCFactions);
bool pAddNPCFactionList(uint32 id, const NPCFactionList* nfl);
bool pSetNPCFaction(uint32 id, uint32* factionid, int32* factionvalue, int8 *factionnpcvalue, uint8 *factiontemp);
const NPCFactionList* pGetNPCFactionList(uint32 id);

137
EMuShareMem/NPCTypes.cpp Normal file
View File

@ -0,0 +1,137 @@
#include "../common/debug.h"
#ifdef _WINDOWS
#include <windows.h>
#else
#include "../common/unix.h"
#endif
#include <memory.h>
#include <iostream>
using namespace std;
#include "NPCTypes.h"
#include "../common/timer.h"
#include "MMF.h"
MMF NPCTypesMMF;
const MMFNPCTypes_Struct* MMFNPCTypesData = 0;
MMFNPCTypes_Struct* MMFNPCTypesData_Writable = 0;
#ifdef _WINDOWS
extern "C" __declspec(dllexport) const NPCType* GetNPCType(uint32 id) {
return pGetNPCType(id);
};
extern "C" __declspec(dllexport) bool AddNPCType(uint32 id, const NPCType* npctype) {
return pAddNPCType(id, npctype);
};
/*extern "C" __declspec(dllexport) bool DLLLoadNPCTypes(CALLBACK_DBLoadNPCTypes cbDBLoadNPCTypes, uint32 iNPCTypeStructSize, int32* iNPCTypesCount, uint32* iMaxNPCTypeID) {
return pDLLLoadNPCTypes(cbDBLoadNPCTypes, iNPCTypeStructSize, iNPCTypesCount, iMaxNPCTypeID);
};*/
#else
extern "C" const NPCType* GetNPCType(uint32 id) {
return pGetNPCType(id);
};
extern "C" bool AddNPCType(uint32 id, const NPCType* npctype) {
return pAddNPCType(id, npctype);
};
extern "C" bool DLLLoadNPCTypes(CALLBACK_DBLoadNPCTypes cbDBLoadNPCTypes, uint32 iNPCTypeStructSize, int32* iNPCTypesCount, uint32* iMaxNPCTypeID) {
return pDLLLoadNPCTypes(cbDBLoadNPCTypes, iNPCTypeStructSize, iNPCTypesCount, iMaxNPCTypeID);
};
#endif
bool pAddNPCType(uint32 id, const NPCType* npctype) {
if (!MMFNPCTypesData_Writable)
return false;
if (id > MMF_MAX_NPCTYPE_ID || MMFNPCTypesData_Writable->NextFreeIndex >= MMFNPCTypesData_Writable->NPCTypeCount)
return false;
if (MMFNPCTypesData_Writable->NPCTypeIndex[id] != 0xFFFFFFFF)
return false;
MMFNPCTypesData_Writable->NPCTypeIndex[id] = MMFNPCTypesData_Writable->NextFreeIndex++;
memcpy(&MMFNPCTypesData_Writable->NPCTypes[MMFNPCTypesData_Writable->NPCTypeIndex[id]], npctype, sizeof(NPCType));
return true;
}
/*bool pDLLLoadNPCTypes(CALLBACK_DBLoadNPCTypes cbDBLoadNPCTypes, uint32 iNPCTypeStructSize, int32* iNPCTypesCount, uint32* iMaxNPCTypeID) {
if (iNPCTypeStructSize != sizeof(NPCType)) {
cout << "Error: EMuShareMem: DLLLoadNPCTypes: iNPCTypeStructSize != sizeof(NPCType)" << endl;
cout << "NPCType struct has changed, EMuShareMem.dll needs to be recompiled." << endl;
return false;
}
if (*iMaxNPCTypeID > MMF_MAX_NPCTYPE_ID) {
cout << "Error: EMuShareMem: pDLLLoadNPCTypes: iMaxNPCTypeID > MMF_MAX_NPCTYPE_ID" << endl;
cout << "You need to increase the define in NPCTypes.h." << endl;
return false;
}
uint32 tmpMemSize = sizeof(MMFNPCTypes_Struct) + 256 + (sizeof(NPCType) * (*iNPCTypesCount));
if (NPCTypesMMF.Open("EQEMuNPCTypes", tmpMemSize)) {
// MMFNPCTypesData = (const MMFNPCTypes_Struct*) NPCTypesMMF.GetHandle();
if (NPCTypesMMF.CanWrite()) {
MMFNPCTypesData_Writable = (MMFNPCTypes_Struct*) NPCTypesMMF.GetWriteableHandle();
if (!MMFNPCTypesData_Writable) {
cout << "Error: EMuShareMem: DLLLoadNPCTypes: !MMFNPCTypesData_Writable" << endl;
return false;
}
memset(MMFNPCTypesData_Writable, 0, tmpMemSize);
for(int i=0; i<MMF_MAX_NPCTYPE_ID; i++)
MMFNPCTypesData_Writable->NPCTypeIndex[i] = 0xFFFFFFFF;
MMFNPCTypesData_Writable->MaxNPCTypeID = *iMaxNPCTypeID;
MMFNPCTypesData_Writable->NPCTypeCount = *iNPCTypesCount;
// use a callback so the DB functions are done in the main exe
// this way the DLL doesnt have to open a connection to mysql
if (!cbDBLoadNPCTypes(MMFNPCTypesData_Writable->NPCTypeCount, MMFNPCTypesData_Writable->MaxNPCTypeID)) {
cout << "Error: EMuShareMem: DLLLoadNPCTypes: !cbDBLoadNPCTypes" << endl;
return false;
}
MMFNPCTypesData_Writable = 0;
NPCTypesMMF.SetLoaded();
MMFNPCTypesData = (const MMFNPCTypes_Struct*) NPCTypesMMF.GetHandle();
if (!MMFNPCTypesData) {
cout << "Error: EMuShareMem: DLLLoadNPCTypes: !MMFNPCTypesData (CanWrite=true)" << endl;
return false;
}
return true;
}
else {
if (!NPCTypesMMF.IsLoaded()) {
Timer::SetCurrentTime();
uint32 starttime = Timer::GetCurrentTime();
while ((!NPCTypesMMF.IsLoaded()) && ((Timer::GetCurrentTime() - starttime) < 300000)) {
Sleep(100);
Timer::SetCurrentTime();
}
if (!NPCTypesMMF.IsLoaded()) {
cout << "Error: EMuShareMem: DLLLoadNPCTypes: !NPCTypesMMF.IsLoaded() (timeout)" << endl;
return false;
}
}
MMFNPCTypesData = (const MMFNPCTypes_Struct*) NPCTypesMMF.GetHandle();
if (!MMFNPCTypesData) {
cout << "Error: EMuShareMem: DLLLoadNPCTypes: !MMFNPCTypesData (CanWrite=false)" << endl;
return false;
}
*iMaxNPCTypeID = MMFNPCTypesData->MaxNPCTypeID;
*iNPCTypesCount = MMFNPCTypesData->NPCTypeCount;
return true;
}
}
else {
cout << "Error Loading NPCTypes: NPCTypes.cpp: pDLLLoadNPCTypes: Open() == false" << endl;
return false;
}
return false;
};*/
const NPCType* pGetNPCType(uint32 id) {
if (MMFNPCTypesData == 0 || (!NPCTypesMMF.IsLoaded()) || id > MMF_MAX_NPCTYPE_ID || MMFNPCTypesData->NPCTypeIndex[id] == 0xFFFFFFFF)
return 0;
return &MMFNPCTypesData->NPCTypes[MMFNPCTypesData->NPCTypeIndex[id]];
}

18
EMuShareMem/NPCTypes.h Normal file
View File

@ -0,0 +1,18 @@
#include "../common/types.h"
#include "../zone/zonedump.h"
#include "../common/EMuShareMem.h"
// MMF_MAX_NPCTYPE_ID: Make sure this is bigger than the highest NPCType ID#
#define MMF_MAX_NPCTYPE_ID 400000
struct MMFNPCTypes_Struct {
uint32 MaxNPCTypeID;
uint32 NextFreeIndex;
uint32 NPCTypeCount;
uint32 NPCTypeIndex[MMF_MAX_NPCTYPE_ID+1];
NPCType NPCTypes[0];
};
//bool pDLLLoadNPCTypes(CALLBACK_DBLoadNPCTypes cbDBLoadNPCTypes, uint32 iNPCTypeStructSize, int32* iNPCTypesCount, uint32* iMaxNPCTypeID);
bool pAddNPCType(uint32 id, const NPCType* npctype);
const NPCType* pGetNPCType(uint32 id);

140
EMuShareMem/Opcodes.cpp Normal file
View File

@ -0,0 +1,140 @@
#include "../common/debug.h"
#ifdef _WINDOWS
#include <windows.h>
#else
#include "../common/unix.h"
#endif
#include <memory.h>
#include <iostream>
using namespace std;
#include "Opcodes.h"
#include "../common/timer.h"
#include "MMF.h"
MMF OpcodesMMF;
const MMFOpcodes_Struct* MMFOpcodesData = 0;
MMFOpcodes_Struct* MMFOpcodesData_Writable = 0;
const uint16 *MMFOpcodesData_emu_to_eq = NULL;
uint16 *MMFOpcodesData_emu_to_eq_write = NULL;
//we choose to store all opcodes as 16 bits, so if they are a different
//size in emu, they are gunna get casted to 16 bits... prolly will never
//be a problem, but I figured it was noteworthy
DLLFUNC uint16 GetEQOpcode(uint16 emu_op) {
if (MMFOpcodesData == 0 || (!OpcodesMMF.IsLoaded()) || emu_op >= MMFOpcodesData->EmuOpcodeCount )
return 0;
return MMFOpcodesData_emu_to_eq[emu_op];
}
DLLFUNC uint16 GetEmuOpcode(uint16 eq_op) {
if (MMFOpcodesData == 0 || (!OpcodesMMF.IsLoaded()) || eq_op >= MMFOpcodesData->EQOpcodeCount )
return 0;
return MMFOpcodesData->eq_to_emu[eq_op];
}
DLLFUNC bool SetOpcodePair(uint16 emu_op, uint16 eq_op) {
if (!MMFOpcodesData_Writable || !MMFOpcodesData_emu_to_eq_write)
return false;
if (emu_op >= MMFOpcodesData_Writable->EmuOpcodeCount || eq_op >= MMFOpcodesData_Writable->EQOpcodeCount)
return false;
MMFOpcodesData_emu_to_eq_write[emu_op] = eq_op;
MMFOpcodesData_Writable->eq_to_emu[eq_op] = emu_op;
return true;
}
DLLFUNC void ClearEQOpcodes() {
if (!MMFOpcodesData_Writable)
return;
memset(MMFOpcodesData_Writable->eq_to_emu, 0, sizeof(uint16)*MMFOpcodesData->EQOpcodeCount);
}
DLLFUNC bool DLLLoadOpcodes(CALLBACK_DBLoadOpcodes cb, uint32 opsize, uint32 eq_count, uint32 emu_count, const char *filename) {
if(opsize != sizeof(uint16)) {
cout << "Error: EMuShareMem: DLLLoadOpcodes: opsize != sizeof(uint16)" << endl;
cout << "Opcode size has changed, EMuShareMem.dll needs to be recompiled." << endl;
return false;
}
uint32 tmpMemSize = sizeof(MMFOpcodes_Struct) + opsize * (eq_count+emu_count);
if (OpcodesMMF.Open("EQEMuOpcodes", tmpMemSize)) {
if (OpcodesMMF.CanWrite()) {
MMFOpcodesData_Writable = (MMFOpcodes_Struct*) OpcodesMMF.GetWriteableHandle();
if (!MMFOpcodesData_Writable) {
cout << "Error: EMuShareMem: DLLLoadOpcodes: !MMFOpcodesData_Writable" << endl;
return false;
}
//emu_to_eq is right after eq_to_emu
MMFOpcodesData_emu_to_eq = MMFOpcodesData_Writable->eq_to_emu + eq_count;
MMFOpcodesData_emu_to_eq_write = MMFOpcodesData_Writable->eq_to_emu + eq_count;
//we need to memset the eq opcodes
memset(MMFOpcodesData_Writable->eq_to_emu, 0, sizeof(uint16)*eq_count);
MMFOpcodesData_Writable->EQOpcodeCount = eq_count;
MMFOpcodesData_Writable->EmuOpcodeCount = emu_count;
// use a callback so the DB functions are done in the main exe
// this way the DLL doesnt have to open a connection to mysql
if (!cb(filename)) {
cout << "Error: EMuShareMem: DLLLoadOpcodes: !cbDBLoadOpcodes" << endl;
return false;
}
//we dont disable the write handle here, so we can reload them
//MMFOpcodesData_Writable = 0;
OpcodesMMF.SetLoaded();
MMFOpcodesData = (const MMFOpcodes_Struct*) OpcodesMMF.GetHandle();
if (!MMFOpcodesData) {
cout << "Error: EMuShareMem: DLLLoadOpcodes: !MMFOpcodesData (CanWrite=true)" << endl;
return false;
}
return true;
} else {
if (!OpcodesMMF.IsLoaded()) {
Timer::SetCurrentTime();
uint32 starttime = Timer::GetCurrentTime();
while ((!OpcodesMMF.IsLoaded()) && ((Timer::GetCurrentTime() - starttime) < 300000)) {
Sleep(10);
Timer::SetCurrentTime();
}
if (!OpcodesMMF.IsLoaded()) {
cout << "Error: EMuShareMem: DLLLoadOpcodes: !OpcodesMMF.IsLoaded() (timeout)" << endl;
return false;
}
}
MMFOpcodesData = (const MMFOpcodes_Struct*) OpcodesMMF.GetHandle();
if (!MMFOpcodesData) {
cout << "Error: EMuShareMem: DLLLoadOpcodes: !MMFOpcodesData (CanWrite=false)" << endl;
return false;
}
//emu_to_eq is right after eq_to_emu
MMFOpcodesData_emu_to_eq = MMFOpcodesData->eq_to_emu + MMFOpcodesData->EQOpcodeCount;
//cheat a little so we can retain writeable handles for reloading
MMFOpcodesData_Writable = const_cast<MMFOpcodes_Struct*>(MMFOpcodesData);
MMFOpcodesData_emu_to_eq_write = MMFOpcodesData_Writable->eq_to_emu + eq_count;
return true;
}
}
else {
cout << "Error Loading Opcodes: Opcodes.cpp: pDLLLoadOpcodes: ret == 0, size = " << tmpMemSize << endl;
return false;
}
return false;
}

10
EMuShareMem/Opcodes.h Normal file
View File

@ -0,0 +1,10 @@
#include "../common/types.h"
#include "../common/EMuShareMem.h"
struct MMFOpcodes_Struct {
uint32 EQOpcodeCount;
uint32 EmuOpcodeCount;
uint16 eq_to_emu[0];
//uint16 emu_to_eq[0]; //logical, not really here... EQOpcodeCount indexes in
};

142
EMuShareMem/SkillCaps.cpp Normal file
View File

@ -0,0 +1,142 @@
#include "../common/debug.h"
#ifdef _WINDOWS
#include <windows.h>
#else
#include "../common/unix.h"
#endif
#include <memory.h>
#include <iostream>
using namespace std;
#include "SkillCaps.h"
#include "../common/timer.h"
#include "MMF.h"
MMF SkillCapsMMF;
const MMFSkillCaps_Struct* MMFSkillCapsData = 0;
MMFSkillCaps_Struct* MMFSkillCapsData_Writable = 0;
DLLFUNC uint16 GetSkillCap(uint8 Class_, uint8 Skill, uint8 Level) {
if (MMFSkillCapsData == 0 || (!SkillCapsMMF.IsLoaded()))
return 0;
if (Class_ >= MMFSkillCapsData->ClassCount || Skill >= MMFSkillCapsData->SkillCount || Level >= MMFSkillCapsData->LevelCount)
return(0);
uint32 index =
(((Class_ * MMFSkillCapsData->SkillCount) + Skill) * MMFSkillCapsData->LevelCount)
+ Level;
return MMFSkillCapsData->caps[index];
}
DLLFUNC bool SetSkillCap(uint8 Class_, uint8 Skill, uint8 Level, uint16 cap) {
if (!MMFSkillCapsData_Writable)
return false;
if (Class_ >= MMFSkillCapsData_Writable->ClassCount || Skill >= MMFSkillCapsData_Writable->SkillCount || Level >= MMFSkillCapsData_Writable->LevelCount)
return false;
uint32 index =
(((Class_ * MMFSkillCapsData_Writable->SkillCount) + Skill) * MMFSkillCapsData_Writable->LevelCount)
+ Level;
MMFSkillCapsData_Writable->caps[index] = cap;
return true;
}
DLLFUNC uint8 GetTrainLevel(uint8 Class_, uint8 Skill, uint8 Level){
if (MMFSkillCapsData == 0 || (!SkillCapsMMF.IsLoaded()))
return 0;
if (Class_ >= MMFSkillCapsData->ClassCount || Skill >= MMFSkillCapsData->SkillCount || Level >= MMFSkillCapsData->LevelCount)
return(0);
uint32 index = (((Class_ * MMFSkillCapsData->SkillCount) + Skill) * MMFSkillCapsData->LevelCount);
for(int x = 0; x < Level; x++){
if(MMFSkillCapsData->caps[index + x]){
return (x);
}
}
return(0);
}
DLLFUNC void ClearSkillCaps() {
if (!MMFSkillCapsData_Writable)
return;
memset(MMFSkillCapsData_Writable->caps, 0,
sizeof(uint16)*(MMFSkillCapsData->ClassCount*MMFSkillCapsData->SkillCount*MMFSkillCapsData->LevelCount));
}
DLLFUNC bool LoadSkillCaps(CALLBACK_DBLoadSkillCaps cb, uint32 opsize, uint8 ClassCount, uint8 SkillCount, uint8 LevelCount) {
if(opsize != sizeof(uint16)) {
cout << "Error: EMuShareMem: DLLLoadSkillCaps: opsize != sizeof(uint16)" << endl;
cout << "SkillCap size has changed, EMuShareMem.dll needs to be recompiled." << endl;
return false;
}
uint32 tmpMemSize = sizeof(MMFSkillCaps_Struct) + opsize * (ClassCount*SkillCount*LevelCount);
if (SkillCapsMMF.Open("EQEMuKSkillCaps", tmpMemSize)) {
if (SkillCapsMMF.CanWrite()) {
MMFSkillCapsData_Writable = (MMFSkillCaps_Struct*) SkillCapsMMF.GetWriteableHandle();
if (!MMFSkillCapsData_Writable) {
cout << "Error: EMuShareMem: DLLLoadSkillCaps: !MMFSkillCapsData_Writable" << endl;
return false;
}
//we need to memset the eq SkillCaps
memset(MMFSkillCapsData_Writable->caps, 0, sizeof(uint16)*(ClassCount*SkillCount*LevelCount));
MMFSkillCapsData_Writable->ClassCount = ClassCount;
MMFSkillCapsData_Writable->SkillCount = SkillCount;
MMFSkillCapsData_Writable->LevelCount = LevelCount;
// use a callback so the DB functions are done in the main exe
// this way the DLL doesnt have to open a connection to mysql
if (!cb()) {
cout << "Error: EMuShareMem: DLLLoadSkillCaps: !cbDBLoadSkillCaps" << endl;
return false;
}
MMFSkillCapsData_Writable = 0;
SkillCapsMMF.SetLoaded();
MMFSkillCapsData = (const MMFSkillCaps_Struct*) SkillCapsMMF.GetHandle();
if (!MMFSkillCapsData) {
cout << "Error: EMuShareMem: DLLLoadSkillCaps: !MMFSkillCapsData (CanWrite=true)" << endl;
return false;
}
return true;
} else {
if (!SkillCapsMMF.IsLoaded()) {
Timer::SetCurrentTime();
uint32 starttime = Timer::GetCurrentTime();
while ((!SkillCapsMMF.IsLoaded()) && ((Timer::GetCurrentTime() - starttime) < 300000)) {
Sleep(10);
Timer::SetCurrentTime();
}
if (!SkillCapsMMF.IsLoaded()) {
cout << "Error: EMuShareMem: DLLLoadSkillCaps: !SkillCapsMMF.IsLoaded() (timeout)" << endl;
return false;
}
}
MMFSkillCapsData = (const MMFSkillCaps_Struct*) SkillCapsMMF.GetHandle();
if (!MMFSkillCapsData) {
cout << "Error: EMuShareMem: DLLLoadSkillCaps: !MMFSkillCapsData (CanWrite=false)" << endl;
return false;
}
return true;
}
}
else {
cout << "Error Loading SkillCaps: SkillCaps.cpp: pDLLLoadSkillCaps: ret == 0, size = " << tmpMemSize << endl;
return false;
}
return false;
}

10
EMuShareMem/SkillCaps.h Normal file
View File

@ -0,0 +1,10 @@
#include "../common/types.h"
#include "../common/EMuShareMem.h"
struct MMFSkillCaps_Struct {
uint8 ClassCount;
uint8 SkillCount;
uint8 LevelCount;
uint16 caps[0];
};

98
EMuShareMem/Spells.cpp Normal file
View File

@ -0,0 +1,98 @@
#include "../common/debug.h"
#ifdef _WINDOWS
#include <windows.h>
#else
#include "../common/unix.h"
#endif
#include <memory.h>
#include <iostream>
using namespace std;
#include "Spells.h"
#include "../common/timer.h"
//#include "../zone/masterentity.h"
#include "MMF.h"
MMF SpellsMMF;
const MMFSpells_Struct* MMFSpellsData = 0;
MMFSpells_Struct* MMFSpellsData_Writable = 0;
#ifdef _WINDOWS
extern "C" __declspec(dllexport) bool DLLLoadSPDat(const CALLBACK_FileLoadSPDat cbFileLoadSPDat, const void** oSpellsPointer, int32* oSPDAT_RECORDS, uint32 iSPDat_Struct_Size) {
return pDLLLoadSPDat(cbFileLoadSPDat, oSpellsPointer, oSPDAT_RECORDS, iSPDat_Struct_Size);
};
#else
extern "C" bool DLLLoadSPDat(const CALLBACK_FileLoadSPDat cbFileLoadSPDat, const void** oSpellsPointer, int32* oSPDAT_RECORDS, uint32 iSPDat_Struct_Size) {
return pDLLLoadSPDat(cbFileLoadSPDat, oSpellsPointer, oSPDAT_RECORDS, iSPDat_Struct_Size);
};
#endif
bool pDLLLoadSPDat(const CALLBACK_FileLoadSPDat cbFileLoadSPDat, const void** oSpellsPointer, int32* oSPDAT_RECORDS, uint32 iSPDat_Struct_Size) {
if (iSPDat_Struct_Size != sizeof(SPDat_Spell_Struct)) {
cout << "Error: EMuShareMem: DLLLoadSPDat: iSPDat_Struct_Size != sizeof(SPDat_Spell_Struct)" << endl;
cout << "SPDat_Spell_Struct has changed, EMuShareMem.dll needs to be recompiled." << endl;
return false;
}
uint32 tmpMemSize = sizeof(MMFSpells_Struct) + 256 + (sizeof(SPDat_Spell_Struct) * (*oSPDAT_RECORDS));
if (SpellsMMF.Open("EQEMuSpells", tmpMemSize)) {
if (SpellsMMF.CanWrite()) {
MMFSpellsData_Writable = (MMFSpells_Struct*) SpellsMMF.GetWriteableHandle();
if (!MMFSpellsData_Writable) {
cout << "Error: EMuShareMem: DLLLoadSPDat: !MMFSpellsData_Writable" << endl;
return false;
}
memset(MMFSpellsData_Writable, 0, tmpMemSize);
MMFSpellsData_Writable->SPDAT_RECORDS = *oSPDAT_RECORDS;
// use a callback so the DB functions are done in the main exe
// this way the DLL doesnt have to open a connection to mysql
if (MMFSpellsData_Writable->SPDAT_RECORDS > 0) {
cbFileLoadSPDat(&MMFSpellsData_Writable->spells[0], MMFSpellsData_Writable->SPDAT_RECORDS-1);
*oSpellsPointer = &MMFSpellsData_Writable->spells[0];
}
else
*oSpellsPointer = 0;
MMFSpellsData_Writable = 0;
SpellsMMF.SetLoaded();
MMFSpellsData = (const MMFSpells_Struct*) SpellsMMF.GetHandle();
if (!MMFSpellsData) {
cout << "Error: EMuShareMem: DLLLoadSPDat: !MMFSpellsData (CanWrite=true)" << endl;
return false;
}
return true;
}
else {
if (!SpellsMMF.IsLoaded()) {
Timer::SetCurrentTime();
uint32 starttime = Timer::GetCurrentTime();
while ((!SpellsMMF.IsLoaded()) && ((Timer::GetCurrentTime() - starttime) < 300000)) {
Sleep(100);
Timer::SetCurrentTime();
}
if (!SpellsMMF.IsLoaded()) {
cout << "Error: EMuShareMem: DLLLoadSPDat: !SpellsMMF.IsLoaded() (timeout)" << endl;
return false;
}
}
MMFSpellsData = (const MMFSpells_Struct*) SpellsMMF.GetHandle();
if (!MMFSpellsData) {
cout << "Error: EMuShareMem: DLLLoadSPDat: !SpellsMMF (CanWrite=false)" << endl;
return false;
}
*oSPDAT_RECORDS = MMFSpellsData->SPDAT_RECORDS;
if (MMFSpellsData->SPDAT_RECORDS > 0)
*oSpellsPointer = &MMFSpellsData->spells[0];
else
*oSpellsPointer = 0;
return true;
}
}
else {
cout << "Error Loading SPDat: Spells.cpp: pDLLLoadSPDat: Open() == false" << endl;
return false;
}
return false;
}

16
EMuShareMem/Spells.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef MEMSHARE_SPELLS_H
#define MEMSHARE_SPELLS_H
#include "../common/types.h"
#include "../zone/spdat.h"
#include "../common/EMuShareMem.h"
struct MMFSpells_Struct {
uint32 SPDAT_RECORDS; // maxspellid + 1, size of array
SPDat_Spell_Struct spells[0];
};
bool pDLLLoadSPDat(const CALLBACK_FileLoadSPDat cbFileLoadSPDat, const void** oSpellsPointer, int32* oSPDAT_RECORDS, uint32 iSPDat_Struct_Size);
#endif

339
GPL.txt Normal file
View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

7873
changelog.txt Normal file

File diff suppressed because it is too large Load Diff

85
cmake/FindMySQL.cmake Normal file
View File

@ -0,0 +1,85 @@
# - Find mysqlclient
#
# -*- cmake -*-
#
# Find the native MySQL includes and library
#
# MySQL_INCLUDE_DIR - where to find mysql.h, etc.
# MySQL_LIBRARIES - List of libraries when using MySQL.
# MySQL_FOUND - True if MySQL found.
# The following can be used as a hint as to where to search:
# MYSQL_ROOT
IF (MySQL_INCLUDE_DIR AND MySQL_LIBRARIES)
# Already in cache, be silent
SET(MySQL_FIND_QUIETLY TRUE)
ENDIF (MySQL_INCLUDE_DIR AND MySQL_LIBRARIES)
# Include dir
IF(MYSQL_ROOT)
FIND_PATH(MySQL_INCLUDE_DIR
NAMES mysql.h
PATHS ${MYSQL_ROOT}/include
PATH_SUFFIXES mysql
)
ELSE(MYSQL_ROOT)
FIND_PATH(MySQL_INCLUDE_DIR
NAMES mysql.h
PATH_SUFFIXES mysql
)
ENDIF(MYSQL_ROOT)
# Library
SET(MySQL_NAMES mysqlclient_r mysqlclient)
IF(MYSQL_ROOT)
FIND_LIBRARY(MySQL_LIBRARY_DEBUG
NAMES ${MySQL_NAMES}
PATHS ${MYSQL_ROOT}/lib/debug /usr/lib /usr/local/lib /usr/lib64 /usr/local/lib64
PATH_SUFFIXES mysql
)
FIND_LIBRARY(MySQL_LIBRARY_RELEASE
NAMES ${MySQL_NAMES}
PATHS ${MYSQL_ROOT}/lib /usr/lib /usr/local/lib /usr/lib64 /usr/local/lib64
PATH_SUFFIXES mysql
)
ELSE(MYSQL_ROOT)
FIND_LIBRARY(MySQL_LIBRARY_DEBUG
NAMES ${MySQL_NAMES}
PATHS /usr/lib /usr/local/lib /usr/lib64 /usr/local/lib64
PATH_SUFFIXES mysql
)
FIND_LIBRARY(MySQL_LIBRARY_RELEASE
NAMES ${MySQL_NAMES}
PATHS /usr/lib /usr/local/lib /usr/lib64 /usr/local/lib64
PATH_SUFFIXES mysql
)
ENDIF(MYSQL_ROOT)
IF (MySQL_INCLUDE_DIR AND MySQL_LIBRARY_DEBUG AND MySQL_LIBRARY_RELEASE)
SET(MySQL_FOUND TRUE)
SET( MySQL_LIBRARIES ${MySQL_LIBRARY_DEBUG} ${MySQL_LIBRARY_RELEASE} )
ELSE (MySQL_INCLUDE_DIR AND MySQL_LIBRARY_DEBUG AND MySQL_LIBRARY_RELEASE)
SET(MySQL_FOUND FALSE)
SET( MySQL_LIBRARIES )
ENDIF (MySQL_INCLUDE_DIR AND MySQL_LIBRARY_DEBUG AND MySQL_LIBRARY_RELEASE)
# handle the QUIETLY and REQUIRED arguments and set MySQL_FOUND to TRUE if
# all listed variables are TRUE
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(MySQL DEFAULT_MSG MySQL_LIBRARY_DEBUG MySQL_LIBRARY_RELEASE MySQL_INCLUDE_DIR)
IF(MySQL_FOUND)
SET( MySQL_LIBRARIES ${MySQL_LIBRARY_DEBUG} ${MySQL_LIBRARY_RELEASE} )
ELSE(MySQL_FOUND)
SET( MySQL_LIBRARIES )
ENDIF(MySQL_FOUND)
MARK_AS_ADVANCED(
MySQL_LIBRARY_DEBUG
MySQL_LIBRARY_RELEASE
MySQL_INCLUDE_DIR
)

146
common/BasePacket.cpp Normal file
View File

@ -0,0 +1,146 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "debug.h"
#include "BasePacket.h"
#include "misc.h"
#include "packet_dump.h"
BasePacket::BasePacket(const unsigned char *buf, uint32 len)
{
this->pBuffer=NULL;
this->size=0;
this->_wpos = 0;
this->_rpos = 0;
if (len>0) {
this->size=len;
pBuffer= new unsigned char[len];
if (buf) {
memcpy(this->pBuffer,buf,len);
} else {
memset(this->pBuffer,0,len);
}
}
}
BasePacket::~BasePacket()
{
if (pBuffer)
delete[] pBuffer;
pBuffer=NULL;
}
void BasePacket::build_raw_header_dump(char *buffer, uint16 seq) const
{
if (timestamp.tv_sec) {
char temp[20];
strftime(temp,20,"%F %T",localtime((const time_t *)&timestamp.tv_sec));
buffer += sprintf(buffer, "%s.%06lu ",temp,timestamp.tv_usec);
}
if (src_ip) {
string sIP,dIP;;
sIP=long2ip(src_ip);
dIP=long2ip(dst_ip);
buffer += sprintf(buffer, "[%s:%d->%s:%d]\n",sIP.c_str(),src_port,dIP.c_str(),dst_port);
}
if (seq != 0xffff)
buffer += sprintf(buffer, "[Seq=%u] ",seq);
}
void BasePacket::DumpRawHeader(uint16 seq, FILE *to) const
{
char buff[128];
build_raw_header_dump(buff, seq);
fprintf(to, "%s", buff);
}
void BasePacket::build_header_dump(char *buffer) const
{
sprintf(buffer, "[packet]\n");
}
void BasePacket::DumpRawHeaderNoTime(uint16 seq, FILE *to) const
{
if (src_ip) {
string sIP,dIP;;
sIP=long2ip(src_ip);
dIP=long2ip(dst_ip);
fprintf(to, "[%s:%d->%s:%d] ",sIP.c_str(),src_port,dIP.c_str(),dst_port);
}
if (seq != 0xffff)
fprintf(to, "[Seq=%u] ",seq);
}
void BasePacket::DumpRaw(FILE *to) const
{
DumpRawHeader();
if (pBuffer && size)
dump_message_column(pBuffer, size, " ", to);
fprintf(to, "\n");
}
void BasePacket::ReadString(char *str, uint32 Offset, uint32 MaxLength) const
{
uint32 i = 0, j = Offset;
do
{
str[i++] = pBuffer[j++];
}
while((j < size) && (i < MaxLength) && (str[i - 1] != 0));
str[i - 1] = '\0';
}
void DumpPacketHex(const BasePacket* app)
{
DumpPacketHex(app->pBuffer, app->size);
}
void DumpPacketAscii(const BasePacket* app)
{
DumpPacketAscii(app->pBuffer, app->size);
}
void DumpPacketBin(const BasePacket* app) {
DumpPacketBin(app->pBuffer, app->size);
}

93
common/BasePacket.h Normal file
View File

@ -0,0 +1,93 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef BASEPACKET_H_
#define BASEPACKET_H_
#include "types.h"
#include <stdio.h>
#include <string.h>
#include <string>
#ifdef WIN32
#include <time.h>
#include <windows.h>
#include <winsock2.h>
#else
#include <sys/time.h>
#include <netinet/in.h>
#endif
class BasePacket {
public:
unsigned char *pBuffer;
uint32 size, _wpos, _rpos;
uint32 src_ip,dst_ip;
uint16 src_port,dst_port;
uint32 priority;
timeval timestamp;
virtual void build_raw_header_dump(char *buffer, uint16 seq=0xffff) const;
virtual void build_header_dump(char *buffer) const;
virtual void DumpRawHeader(uint16 seq=0xffff, FILE *to = stdout) const;
virtual void DumpRawHeaderNoTime(uint16 seq=0xffff, FILE *to = stdout) const;
void DumpRaw(FILE *to = stdout) const;
void setSrcInfo(uint32 sip, uint16 sport) { src_ip=sip; src_port=sport; }
void setDstInfo(uint32 dip, uint16 dport) { dst_ip=dip; dst_port=dport; }
void setTimeInfo(uint32 ts_sec, uint32 ts_usec) { timestamp.tv_sec=ts_sec; timestamp.tv_usec=ts_usec; }
void copyInfo(const BasePacket *p) { src_ip=p->src_ip; src_port=p->src_port; dst_ip=p->dst_ip; dst_port=p->dst_port; timestamp.tv_sec=p->timestamp.tv_sec; timestamp.tv_usec=p->timestamp.tv_usec; }
inline bool operator<(const BasePacket &rhs) {
return (timestamp.tv_sec < rhs.timestamp.tv_sec || (timestamp.tv_sec==rhs.timestamp.tv_sec && timestamp.tv_usec < rhs.timestamp.tv_usec));
}
void WriteUInt8(uint8 value) { *(uint8 *)(pBuffer + _wpos) = value; _wpos += sizeof(uint8); }
void WriteUInt32(uint32 value) { *(uint32 *)(pBuffer + _wpos) = value; _wpos += sizeof(uint32); }
void WriteUInt64(uint64 value) { *(uint64 *)(pBuffer + _wpos) = value; _wpos += sizeof(uint64); }
void WriteUInt16(uint32 value) { *(uint16 *)(pBuffer + _wpos) = value; _wpos += sizeof(uint16); }
void WriteSInt32(int32 value) { *(int32 *)(pBuffer + _wpos) = value; _wpos += sizeof(int32); }
void WriteFloat(float value) { *(float *)(pBuffer + _wpos) = value; _wpos += sizeof(float); }
void WriteDouble(double value) { *(double *)(pBuffer + _wpos) = value; _wpos += sizeof(double); }
void WriteString(const char * str) { uint32 len = static_cast<uint32>(strlen(str)) + 1; memcpy(pBuffer + _wpos, str, len); _wpos += len; }
uint8 ReadUInt8() { uint8 value = *(uint8 *)(pBuffer + _rpos); _rpos += sizeof(uint8); return value; }
uint8 ReadUInt8(uint32 Offset) const { uint8 value = *(uint8 *)(pBuffer + Offset); return value; }
uint32 ReadUInt32() { uint32 value = *(uint32 *)(pBuffer + _rpos); _rpos += sizeof(uint32); return value; }
uint32 ReadUInt32(uint32 Offset) const { uint32 value = *(uint32 *)(pBuffer + Offset); return value; }
void ReadString(char *str) { uint32 len = static_cast<uint32>(strlen((char *)(pBuffer + _rpos))) + 1; memcpy(str, pBuffer + _rpos, len); _rpos += len; }
void ReadString(char *str, uint32 Offset, uint32 MaxLength) const;
uint32 GetWritePosition() { return _wpos; }
uint32 GetReadPosition() { return _rpos; }
void SetWritePosition(uint32 Newwpos) { _wpos = Newwpos; }
void SetReadPosition(uint32 Newrpos) { _rpos = Newrpos; }
protected:
virtual ~BasePacket();
BasePacket() { pBuffer=NULL; size=0; _wpos = 0; _rpos = 0; }
BasePacket(const unsigned char *buf, const uint32 len);
};
extern void DumpPacketHex(const BasePacket* app);
extern void DumpPacketAscii(const BasePacket* app);
extern void DumpPacketBin(const BasePacket* app);
#endif /*BASEPACKET_H_*/

313
common/CMakeLists.txt Normal file
View File

@ -0,0 +1,313 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
SET(common_sources
BasePacket.cpp
classes.cpp
Condition.cpp
crash.cpp
CRC16.cpp
crc32.cpp
database.cpp
dbasync.cpp
dbcore.cpp
DBMemLeak.cpp
debug.cpp
emu_opcodes.cpp
EMuShareMem.cpp
EmuTCPConnection.cpp
EmuTCPServer.cpp
EQDB.cpp
EQDBRes.cpp
EQEmuConfig.cpp
EQEMuError.cpp
EQPacket.cpp
EQStream.cpp
EQStreamFactory.cpp
EQStreamIdent.cpp
EQStreamProxy.cpp
eqtime.cpp
extprofile.cpp
guild_base.cpp
guilds.cpp
Item.cpp
logsys.cpp
logsys_eqemu.cpp
md5.cpp
misc.cpp
MiscFunctions.cpp
moremath.cpp
Mutex.cpp
opcode_map.cpp
opcodemgr.cpp
packet_dump.cpp
packet_dump_file.cpp
packet_functions.cpp
perl_EQDB.cpp
perl_EQDBRes.cpp
ProcLauncher.cpp
ptimer.cpp
races.cpp
rdtsc.cpp
rulesys.cpp
serverinfo.cpp
shareddb.cpp
SharedLibrary.cpp
StructStrategy.cpp
TCPConnection.cpp
TCPServer.cpp
timeoutmgr.cpp
timer.cpp
unix.cpp
worldconn.cpp
XMLParser.cpp
platform.cpp
patches/Client62.cpp
patches/patches.cpp
patches/SoD.cpp
patches/SoF.cpp
patches/RoF.cpp
patches/Titanium.cpp
patches/Underfoot.cpp
SocketLib/Base64.cpp
SocketLib/File.cpp
SocketLib/HttpdCookies.cpp
SocketLib/HttpdForm.cpp
SocketLib/HttpdSocket.cpp
SocketLib/HTTPSocket.cpp
SocketLib/MemFile.cpp
SocketLib/Mime.cpp
SocketLib/Parse.cpp
SocketLib/socket_include.cpp
SocketLib/Utility.cpp
StackWalker/StackWalker.cpp
tinyxml/tinystr.cpp
tinyxml/tinyxml.cpp
tinyxml/tinyxmlerror.cpp
tinyxml/tinyxmlparser.cpp
)
SET(common_headers
BasePacket.h
bodytypes.h
breakdowns.h
classes.h
common_profile.h
Condition.h
crash.h
CRC16.h
crc32.h
database.h
dbasync.h
dbcore.h
DBMemLeak.h
debug.h
deity.h
emu_opcodes.h
emu_oplist.h
EMuShareMem.h
EmuTCPConnection.h
EmuTCPServer.h
eq_constants.h
eq_opcodes.h
eq_packet_structs.h
EQDB.h
EQDBRes.h
EQEmuConfig.h
EQEmuConfig_elements.h
EQEMuError.h
EQPacket.h
EQStream.h
EQStreamFactory.h
EQStreamIdent.h
EQStreamIntf.h
EQStreamLocator.h
EQStreamProxy.h
EQStreamType.h
eqtime.h
errmsg.h
extprofile.h
guild_base.h
guilds.h
Item.h
item_fieldlist.h
item_struct.h
languages.h
linked_list.h
logsys.h
logtypes.h
mail_oplist.h
md5.h
misc.h
MiscFunctions.h
moremath.h
Mutex.h
op_codes.h
opcode_dispatch.h
opcodemgr.h
packet_dump.h
packet_dump_file.h
packet_functions.h
ProcLauncher.h
profiler.h
ptimer.h
queue.h
races.h
rdtsc.h
rulesys.h
ruletypes.h
seperator.h
serverinfo.h
servertalk.h
shareddb.h
SharedLibrary.h
skills.h
StructStrategy.h
TCPBasicServer.h
TCPConnection.h
TCPServer.h
timeoutmgr.h
timer.h
types.h
unix.h
useperl.h
version.h
worldconn.h
XMLParser.h
ZoneNumbers.h
platform.h
patches/Client62.h
patches/Client62_itemfields.h
patches/Client62_ops.h
patches/Client62_structs.h
patches/patches.h
patches/SoD.h
patches/SoD_itemfields.h
patches/SoD_ops.h
patches/SoD_structs.h
patches/SoF.h
patches/SoF_itemfields.h
patches/SoF_opcode_list.h
patches/SoF_ops.h
patches/SoF_structs.h
patches/SSDeclare.h
patches/SSDefine.h
patches/SSRegister.h
patches/RoF.h
patches/RoF_itemfields.h
patches/RoF_ops.h
patches/RoF_structs.h
patches/Titanium.h
patches/Titanium_itemfields.h
patches/Titanium_ops.h
patches/Titanium_structs.h
patches/Underfoot.h
patches/Underfoot_itemfields.h
patches/Underfoot_ops.h
patches/Underfoot_structs.h
SocketLib/Base64.h
SocketLib/File.h
SocketLib/HttpdCookies.h
SocketLib/HttpdForm.h
SocketLib/HttpdSocket.h
SocketLib/HTTPSocket.h
SocketLib/IFile.h
SocketLib/MemFile.h
SocketLib/Mime.h
SocketLib/Parse.h
SocketLib/socket_include.h
SocketLib/Utility.h
StackWalker/StackWalker.h
tinyxml/tinystr.h
tinyxml/tinyxml.h
)
SOURCE_GROUP(Patches FILES
patches/Client62.h
patches/Client62_itemfields.h
patches/Client62_ops.h
patches/Client62_structs.h
patches/patches.h
patches/SoD.h
patches/SoD_itemfields.h
patches/SoD_ops.h
patches/SoD_structs.h
patches/SoF.h
patches/SoF_itemfields.h
patches/SoF_opcode_list.h
patches/SoF_ops.h
patches/SoF_structs.h
patches/SSDeclare.h
patches/SSDefine.h
patches/SSRegister.h
patches/RoF.h
patches/RoF_itemfields.h
patches/RoF_ops.h
patches/RoF_structs.h
patches/Titanium.h
patches/Titanium_itemfields.h
patches/Titanium_ops.h
patches/Titanium_structs.h
patches/Underfoot.h
patches/Underfoot_itemfields.h
patches/Underfoot_ops.h
patches/Underfoot_structs.h
patches/Client62.cpp
patches/patches.cpp
patches/SoD.cpp
patches/SoF.cpp
patches/RoF.cpp
patches/Titanium.cpp
patches/Underfoot.cpp
)
SOURCE_GROUP(SocketLib FILES
SocketLib/Base64.h
SocketLib/File.h
SocketLib/HttpdCookies.h
SocketLib/HttpdForm.h
SocketLib/HttpdSocket.h
SocketLib/HTTPSocket.h
SocketLib/IFile.h
SocketLib/MemFile.h
SocketLib/Mime.h
SocketLib/Parse.h
SocketLib/socket_include.h
SocketLib/Utility.h
SocketLib/Base64.cpp
SocketLib/File.cpp
SocketLib/HttpdCookies.cpp
SocketLib/HttpdForm.cpp
SocketLib/HttpdSocket.cpp
SocketLib/HTTPSocket.cpp
SocketLib/MemFile.cpp
SocketLib/Mime.cpp
SocketLib/Parse.cpp
SocketLib/socket_include.cpp
SocketLib/Utility.cpp
)
SOURCE_GROUP(StackWalker FILES
StackWalker/StackWalker.h
StackWalker/StackWalker.cpp
)
SOURCE_GROUP(TinyXML FILES
tinyxml/tinystr.h
tinyxml/tinyxml.h
tinyxml/tinystr.cpp
tinyxml/tinyxml.cpp
tinyxml/tinyxmlerror.cpp
tinyxml/tinyxmlparser.cpp
)
INCLUDE_DIRECTORIES(Patches SocketLib StackWalker TinyXML)
ADD_LIBRARY(Common ${common_sources} ${common_headers})
IF(UNIX)
ADD_DEFINITIONS(-fPIC)
SET_SOURCE_FILES_PROPERTIES("patches/SoD.cpp" "patches/SoF.cpp" "patches/RoF.cpp" "patches/Underfoot.cpp" PROPERTIES COMPILE_FLAGS -O0)
ENDIF(UNIX)
SET(LIBRARY_OUTPUT_PATH ../Bin)

346
common/CRC16.cpp Normal file
View File

@ -0,0 +1,346 @@
#include <stdio.h>
unsigned long IntArray[]={
0x00000000,
0x77073096,
0xEE0E612C,
0x990951BA,
0x076DC419,
0x706AF48F,
0xE963A535,
0x9E6495A3,
0x0EDB8832,
0x79DCB8A4,
0xE0D5E91E,
0x97D2D988,
0x09B64C2B,
0x7EB17CBD,
0xE7B82D07,
0x90BF1D91,
0x1DB71064,
0x6AB020F2,
0xF3B97148,
0x84BE41DE,
0x1ADAD47D,
0x6DDDE4EB,
0xF4D4B551,
0x83D385C7,
0x136C9856,
0x646BA8C0,
0xFD62F97A,
0x8A65C9EC,
0x14015C4F,
0x63066CD9,
0xFA0F3D63,
0x8D080DF5,
0x3B6E20C8,
0x4C69105E,
0xD56041E4,
0xA2677172,
0x3C03E4D1,
0x4B04D447,
0xD20D85FD,
0xA50AB56B,
0x35B5A8FA,
0x42B2986C,
0xDBBBC9D6,
0xACBCF940,
0x32D86CE3,
0x45DF5C75,
0xDCD60DCF,
0xABD13D59,
0x26D930AC,
0x51DE003A,
0xC8D75180,
0xBFD06116,
0x21B4F4B5,
0x56B3C423,
0xCFBA9599,
0xB8BDA50F,
0x2802B89E,
0x5F058808,
0xC60CD9B2,
0xB10BE924,
0x2F6F7C87,
0x58684C11,
0xC1611DAB,
0xB6662D3D,
0x76DC4190,
0x01DB7106,
0x98D220BC,
0xEFD5102A,
0x71B18589,
0x06B6B51F,
0x9FBFE4A5,
0xE8B8D433,
0x7807C9A2,
0x0F00F934,
0x9609A88E,
0xE10E9818,
0x7F6A0DBB,
0x086D3D2D,
0x91646C97,
0xE6635C01,
0x6B6B51F4,
0x1C6C6162,
0x856530D8,
0xF262004E,
0x6C0695ED,
0x1B01A57B,
0x8208F4C1,
0xF50FC457,
0x65B0D9C6,
0x12B7E950,
0x8BBEB8EA,
0xFCB9887C,
0x62DD1DDF,
0x15DA2D49,
0x8CD37CF3,
0xFBD44C65,
0x4DB26158,
0x3AB551CE,
0xA3BC0074,
0xD4BB30E2,
0x4ADFA541,
0x3DD895D7,
0xA4D1C46D,
0xD3D6F4FB,
0x4369E96A,
0x346ED9FC,
0xAD678846,
0xDA60B8D0,
0x44042D73,
0x33031DE5,
0xAA0A4C5F,
0xDD0D7CC9,
0x5005713C,
0x270241AA,
0xBE0B1010,
0xC90C2086,
0x5768B525,
0x206F85B3,
0xB966D409,
0xCE61E49F,
0x5EDEF90E,
0x29D9C998,
0xB0D09822,
0xC7D7A8B4,
0x59B33D17,
0x2EB40D81,
0xB7BD5C3B,
0xC0BA6CAD,
0xEDB88320,
0x9ABFB3B6,
0x03B6E20C,
0x74B1D29A,
0xEAD54739,
0x9DD277AF,
0x04DB2615,
0x73DC1683,
0xE3630B12,
0x94643B84,
0x0D6D6A3E,
0x7A6A5AA8,
0xE40ECF0B,
0x9309FF9D,
0x0A00AE27,
0x7D079EB1,
0xF00F9344,
0x8708A3D2,
0x1E01F268,
0x6906C2FE,
0xF762575D,
0x806567CB,
0x196C3671,
0x6E6B06E7,
0xFED41B76,
0x89D32BE0,
0x10DA7A5A,
0x67DD4ACC,
0xF9B9DF6F,
0x8EBEEFF9,
0x17B7BE43,
0x60B08ED5,
0xD6D6A3E8,
0xA1D1937E,
0x38D8C2C4,
0x4FDFF252,
0xD1BB67F1,
0xA6BC5767,
0x3FB506DD,
0x48B2364B,
0xD80D2BDA,
0xAF0A1B4C,
0x36034AF6,
0x41047A60,
0xDF60EFC3,
0xA867DF55,
0x316E8EEF,
0x4669BE79,
0xCB61B38C,
0xBC66831A,
0x256FD2A0,
0x5268E236,
0xCC0C7795,
0xBB0B4703,
0x220216B9,
0x5505262F,
0xC5BA3BBE,
0xB2BD0B28,
0x2BB45A92,
0x5CB36A04,
0xC2D7FFA7,
0xB5D0CF31,
0x2CD99E8B,
0x5BDEAE1D,
0x9B64C2B0,
0xEC63F226,
0x756AA39C,
0x026D930A,
0x9C0906A9,
0xEB0E363F,
0x72076785,
0x05005713,
0x95BF4A82,
0xE2B87A14,
0x7BB12BAE,
0x0CB61B38,
0x92D28E9B,
0xE5D5BE0D,
0x7CDCEFB7,
0x0BDBDF21,
0x86D3D2D4,
0xF1D4E242,
0x68DDB3F8,
0x1FDA836E,
0x81BE16CD,
0xF6B9265B,
0x6FB077E1,
0x18B74777,
0x88085AE6,
0xFF0F6A70,
0x66063BCA,
0x11010B5C,
0x8F659EFF,
0xF862AE69,
0x616BFFD3,
0x166CCF45,
0xA00AE278,
0xD70DD2EE,
0x4E048354,
0x3903B3C2,
0xA7672661,
0xD06016F7,
0x4969474D,
0x3E6E77DB,
0xAED16A4A,
0xD9D65ADC,
0x40DF0B66,
0x37D83BF0,
0xA9BCAE53,
0xDEBB9EC5,
0x47B2CF7F,
0x30B5FFE9,
0xBDBDF21C,
0xCABAC28A,
0x53B39330,
0x24B4A3A6,
0xBAD03605,
0xCDD70693,
0x54DE5729,
0x23D967BF,
0xB3667A2E,
0xC4614AB8,
0x5D681B02,
0x2A6F2B94,
0xB40BBE37,
0xC30C8EA1,
0x5A05DF1B,
0x2D02EF8D,
};
unsigned long CRC16(const unsigned char *buf, int size, int key)
{
//printf("CRC16() key=%d\n",key);
/*
sub_0_10020760 proc near ; CODE XREF: sub_0_10008620+AEp
; sub_0_10022A90+14Fp ...
arg_0 = dword ptr 4
arg_4 = dword ptr 8
arg_8 = dword ptr 0Ch
*/
//int *pecx = buf;
unsigned long ecx = key; //mov ecx, [esp+arg_8]
unsigned long eax = ecx; //mov eax, ecx
unsigned long edi;
/* int ecx = key; //mov ecx, [esp+arg_8]
int eax = ecx; //mov eax, ecx
int edi;
*/
eax = ~ eax; //not eax
eax&=0xFF; //and eax, 0FFh
eax=IntArray[eax]; //mov eax, dword_0_10115D38[eax*4] IntArray
eax ^= 0x00FFFFFF; //xor eax, 0FFFFFFh
int edx = ecx; //mov edx, ecx
edx = edx >> 8; //sar edx, 8
edx = edx ^ eax; //xor edx, eax
eax = eax >> 8; //sar eax, 8
edx &= 0xFF; //and edx, 0FFh
eax &= 0x00FFFFFF; //and eax, 0FFFFFFh
//push esi
eax ^= IntArray[edx]; //xor eax, dword_0_10115D38[edx*4]
edx = ecx; //mov edx, ecx
edx = edx >> 0x10; //sar edx, 10h
edx ^= eax; //xor edx, eax
eax = eax >> 8; //sar eax, 8
edx &= 0xFF; //and edx, 0FFh
int esi = IntArray[edx]; //mov esi, dword_0_10115D38[edx*4]
edx = size; //mov edx, [esp+4+arg_4]
eax &= 0x00FFFFFF; //and eax, 0FFFFFFh
eax ^= esi; //xor eax, esi
ecx = ecx >> 0x18; //sar ecx, 18h
ecx ^= eax; //xor ecx, eax
ecx &= 0xFF; //and ecx, 0FFh
esi = IntArray[ecx]; //mov esi, dword_0_10115D38[ecx*4]
/*ecx = (int) buf; not used */ //mov ecx, [esp+4+arg_0]
eax = eax >> 8; //sar eax, 8
eax &= 0x00FFFFFF; //and eax, 0FFFFFFh
eax ^= esi; //xor eax, esi
/* int* esi = ecx+edx //??*///lea esi, [ecx+edx]
for(int x = 0; x < size; x++)
{ //eax is the crc, ecx is the current part of the buffer
int edx = 0; //xor edx, edx
edx = buf[x] & 0x00FF; //mov dl, [ecx]
/*if(pos > size) //cmp ecx, esi
return ~eax; //jnb short loc_0_10020803
*/
//push edi
//loc_0_100207E0: ; CODE XREF: sub_0_10020760+A0j
//LOOP
edx ^= eax; //xor edx, eax
eax = eax >> 8; //sar eax, 8
edx &= 0xFF; //and edx, 0FFh
edi = IntArray[edx]; //mov edi, dword_0_10115D38[edx*4]
eax &= 0x00FFFFFF; //and eax, 0FFFFFFh
eax ^= edi; //xor eax, edi
//inc ecx
//cmp ecx, esi
// jb short loc_0_100207E0
//pop edi
}
return ~eax;
}
/*loc_0_10020803: ; CODE XREF: sub_0_10020760+7Dj
not eax
pop esi
retn
sub_0_10020760 endp
*/

6
common/CRC16.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef _CRC16_H
#define _CRC16_H
unsigned long CRC16(const unsigned char *buf, int size, int key);
#endif

153
common/Condition.cpp Normal file
View File

@ -0,0 +1,153 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "debug.h"
#include "Condition.h"
#ifdef _WINDOWS
#else
#include <pthread.h>
#include <sys/time.h>
#include <errno.h>
#endif
#ifdef _WINDOWS
Condition::Condition()
{
m_events[SignalEvent] = CreateEvent (NULL, // security
FALSE, // is auto-reset event?
FALSE, // is signaled initially?
NULL); // name
m_events[BroadcastEvent] = CreateEvent (NULL, // security
TRUE, // is auto-reset event?
FALSE, // is signaled initially?
NULL); // name
m_waiters = 0;
InitializeCriticalSection(&CSMutex);
}
Condition::~Condition()
{
DeleteCriticalSection(&CSMutex);
CloseHandle(m_events[SignalEvent]);
CloseHandle(m_events[BroadcastEvent]);
}
void Condition::Signal()
{
EnterCriticalSection(&CSMutex);
if(m_waiters > 0)
SetEvent(m_events[SignalEvent]);
LeaveCriticalSection(&CSMutex);
}
void Condition::SignalAll()
{
EnterCriticalSection(&CSMutex);
if(m_waiters > 0)
SetEvent(m_events[BroadcastEvent]);
LeaveCriticalSection(&CSMutex);
}
void Condition::Wait()
{
EnterCriticalSection(&CSMutex);
m_waiters++;
LeaveCriticalSection(&CSMutex);
int result = WaitForMultipleObjects (_eventCount, m_events, FALSE, INFINITE);
EnterCriticalSection(&CSMutex);
m_waiters--;
//see if we are the last person waiting on the condition, and there was a broadcast
//if so, we need to reset the broadcast event.
if(m_waiters == 0 && result == (WAIT_OBJECT_0+BroadcastEvent))
ResetEvent(m_events[BroadcastEvent]);
LeaveCriticalSection(&CSMutex);
}
#else //!WIN32
Condition::Condition()
{
pthread_cond_init(&cond,NULL);
pthread_mutex_init(&mutex,NULL);
}
void Condition::Signal()
{
pthread_mutex_lock(&mutex);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
void Condition::SignalAll()
{
pthread_mutex_lock(&mutex);
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mutex);
}
void Condition::Wait()
{
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond,&mutex);
pthread_mutex_unlock(&mutex);
}
/*
I commented this specifically because I think it might be very
difficult to write a windows counterpart to it, so I would like
to discourage its use until we can confirm that it can be reasonably
implemented on windows.
bool Condition::TimedWait(unsigned long usec)
{
struct timeval now;
struct timespec timeout;
int retcode=0;
pthread_mutex_lock(&mutex);
gettimeofday(&now,NULL);
now.tv_usec+=usec;
timeout.tv_sec = now.tv_sec + (now.tv_usec/1000000);
timeout.tv_nsec = (now.tv_usec%1000000) *1000;
//cout << "now=" << now.tv_sec << "."<<now.tv_usec << endl;
//cout << "timeout=" << timeout.tv_sec << "."<<timeout.tv_nsec << endl;
retcode=pthread_cond_timedwait(&cond,&mutex,&timeout);
pthread_mutex_unlock(&mutex);
return retcode!=ETIMEDOUT;
}
*/
Condition::~Condition()
{
pthread_mutex_lock(&mutex);
pthread_cond_destroy(&cond);
pthread_mutex_unlock(&mutex);
pthread_mutex_destroy(&mutex);
}
#endif

56
common/Condition.h Normal file
View File

@ -0,0 +1,56 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __CONDITION_H
#define __CONDITION_H
#include "debug.h"
#ifndef WIN32
#include <pthread.h>
#endif
//Sombody, someday needs to figure out how to implement a condition
//system on windows...
class Condition {
private:
#ifdef WIN32
enum {
SignalEvent = 0,
BroadcastEvent,
_eventCount
};
HANDLE m_events[_eventCount];
uint32 m_waiters;
CRITICAL_SECTION CSMutex;
#else
pthread_cond_t cond;
pthread_mutex_t mutex;
#endif
public:
Condition();
void Signal();
void SignalAll();
void Wait();
// bool TimedWait(unsigned long usec);
~Condition();
};
#endif

62
common/DBMemLeak.cpp Normal file
View File

@ -0,0 +1,62 @@
#ifdef _EQDEBUG
#include "../common/debug.h"
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include "../common/Mutex.h"
#include "DBMemLeak.h"
#include <crtdbg.h>
#ifdef _WINDOWS
#define snprintf _snprintf
#define strncasecmp _strnicmp
#define strcasecmp _stricmp
#endif
DBMemLeak dbmemleak;
LinkedList<DBMemLeakStruct*>* list = 0;
Mutex MDBMemLeak;
DBMemLeak::DBMemLeak() {
list = new LinkedList<DBMemLeakStruct*>;
}
DBMemLeak::~DBMemLeak() {
LinkedListIterator<DBMemLeakStruct*> iterator(*list);
iterator.Reset();
while (iterator.MoreElements()) {
char tmp[200];
snprintf(tmp, sizeof(tmp) - 3, "DB Mem Leak: Block=%6d, Query=%s", iterator.GetData()->memblock, iterator.GetData()->query);
snprintf(tmp, sizeof(tmp), "%s\n", tmp);
OutputDebugString(tmp);
iterator.Advance();
}
safe_delete(list);
}
void DBMemLeak::Alloc(const void* result, const char* query) {
LockMutex lock(&MDBMemLeak);
long requestNumber;
uint8* tmp2 = new uint8;
_CrtIsMemoryBlock( tmp2, 1, &requestNumber, 0, 0 );
safe_delete(tmp2);
DBMemLeakStruct* tmp = (DBMemLeakStruct*) new uchar[sizeof(DBMemLeakStruct) + strlen(query) + 1];
tmp->result = result;
tmp->memblock = requestNumber;
strcpy(tmp->query, query);
list->Append(tmp);
}
void DBMemLeak::Free(const void* result) {
LockMutex lock(&MDBMemLeak);
LinkedListIterator<DBMemLeakStruct*> iterator(*list);
iterator.Reset();
while (iterator.MoreElements()) {
if (result == iterator.GetData()->result)
iterator.RemoveCurrent();
else
iterator.Advance();
}
}
#endif

25
common/DBMemLeak.h Normal file
View File

@ -0,0 +1,25 @@
#ifdef _EQDEBUG
#ifndef DBMemLeak_H
#define DBMemLeak_H
#include "../common/types.h"
#include "../common/linked_list.h"
#define mysql_free_result(r) { DBMemLeak::Free(r); mysql_free_result(r); }
struct DBMemLeakStruct {
const void* result;
uint32 memblock;
char query[0];
};
class DBMemLeak {
public:
DBMemLeak();
~DBMemLeak();
static void Alloc(const void* result, const char* query);
static void Free(const void* result);
};
#endif
#endif

300
common/EMuShareMem.cpp Normal file
View File

@ -0,0 +1,300 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "../common/debug.h"
#include <iostream>
using namespace std;
#include "../common/types.h"
#include "EMuShareMem.h"
#ifdef _WINDOWS
#define snprintf _snprintf
#if (_MSC_VER < 1500)
#define vsnprintf _vsnprintf
#endif
#define strncasecmp _strnicmp
#define strcasecmp _stricmp
#define EmuLibName "EMuShareMem"
#else
#define EmuLibName "libEMuShareMem.so"
#endif
LoadEMuShareMemDLL EMuShareMemDLL;
#ifndef WIN32
uint32 LoadEMuShareMemDLL::refCount = 0;
#endif
LoadEMuShareMemDLL::LoadEMuShareMemDLL() {
ClearFunc();
#ifndef WIN32
refCountU();
#endif
}
LoadEMuShareMemDLL::~LoadEMuShareMemDLL() {
#ifndef WIN32
if (refCountD() <= 0) {
#endif
Unload();
#ifndef WIN32
}
#endif
}
bool LoadEMuShareMemDLL::Load() {
if(loaded)
return(true);
if(!SharedLibrary::Load(EmuLibName))
return(false);
if (Loaded()) {
Items.GetItem = (DLLFUNC_GetItem) GetSym("GetItem");
Items.IterateItems = (DLLFUNC_IterateItems) GetSym("IterateItems");
Items.cbAddItem = (DLLFUNC_AddItem) GetSym("AddItem");
Items.DLLLoadItems = (DLLFUNC_DLLLoadItems) GetSym("DLLLoadItems");
Doors.GetDoor = (DLLFUNC_GetDoor) GetSym("GetDoor");
Doors.cbAddDoor = (DLLFUNC_AddDoor) GetSym("AddDoor");
Doors.DLLLoadDoors = (DLLFUNC_DLLLoadDoors) GetSym("DLLLoadDoors");
Spells.DLLLoadSPDat = (DLLFUNC_DLLLoadSPDat) GetSym("DLLLoadSPDat");
NPCFactionList.DLLLoadNPCFactionLists = (DLLFUNC_DLLLoadNPCFactionLists) GetSym("DLLLoadNPCFactionLists");
NPCFactionList.GetNPCFactionList = (DLLFUNC_GetNPCFactionList) GetSym("GetNPCFactionList");
NPCFactionList.cbAddNPCFactionList = (DLLFUNC_AddNPCFactionList) GetSym("AddNPCFactionList");
NPCFactionList.cbSetFaction = (DLLFUNC_SetFaction) GetSym("SetNPCFaction");
Loot.DLLLoadLoot = (DLLFUNC_DLLLoadLoot) GetSym("DLLLoadLoot");
Loot.cbAddLootTable = (DLLFUNC_AddLootTable) GetSym("AddLootTable");
Loot.cbAddLootDrop = (DLLFUNC_AddLootDrop) GetSym("AddLootDrop");
Loot.GetLootTable = (DLLFUNC_GetLootTable) GetSym("GetLootTable");
Loot.GetLootDrop = (DLLFUNC_GetLootDrop) GetSym("GetLootDrop");
Opcodes.GetEQOpcode = (DLLFUNC_GetEQOpcode) GetSym("GetEQOpcode");
Opcodes.GetEmuOpcode = (DLLFUNC_GetEmuOpcode) GetSym("GetEmuOpcode");
Opcodes.SetOpcodePair = (DLLFUNC_SetOpcodePair) GetSym("SetOpcodePair");
Opcodes.DLLLoadOpcodes = (DLLFUNC_DLLLoadOpcodes) GetSym("DLLLoadOpcodes");
Opcodes.ClearEQOpcodes = (DLLFUNC_ClearEQOpcodes) GetSym("ClearEQOpcodes");
SkillCaps.LoadSkillCaps = (DLLFUNC_DLLLoadSkillCaps) GetSym("LoadSkillCaps");
SkillCaps.GetSkillCap = (DLLFUNC_GetSkillCap) GetSym("GetSkillCap");
SkillCaps.SetSkillCap = (DLLFUNC_SetSkillCap) GetSym("SetSkillCap");
SkillCaps.ClearSkillCaps = (DLLFUNC_ClearSkillCaps) GetSym("ClearSkillCaps");
SkillCaps.GetTrainLevel = (DLLFUNC_GetTrainLevel) GetSym("GetTrainLevel");
if(Items.GetItem == NULL) {
Unload();
LogFile->write(EQEMuLog::Error, "LoadEMuShareMemDLL::Load() failed to attach Items.GetItem");
return(false);
}
if(Items.IterateItems == NULL) {
Unload();
LogFile->write(EQEMuLog::Error, "LoadEMuShareMemDLL::Load() failed to attach Items.IterateItems");
return(false);
}
if(Items.cbAddItem == NULL) {
Unload();
LogFile->write(EQEMuLog::Error, "LoadEMuShareMemDLL::Load() failed to attach Items.cbAddItem");
return(false);
}
if(Items.DLLLoadItems == NULL) {
Unload();
LogFile->write(EQEMuLog::Error, "LoadEMuShareMemDLL::Load() failed to attach Items.DLLLoadItems");
return(false);
}
if(Doors.GetDoor == NULL) {
Unload();
LogFile->write(EQEMuLog::Error, "LoadEMuShareMemDLL::Load() failed to attach Doors.GetDoor");
return(false);
}
if(Doors.cbAddDoor == NULL) {
Unload();
LogFile->write(EQEMuLog::Error, "LoadEMuShareMemDLL::Load() failed to attach Doors.cbAddDoor");
return(false);
}
if(Doors.DLLLoadDoors == NULL) {
Unload();
LogFile->write(EQEMuLog::Error, "LoadEMuShareMemDLL::Load() failed to attach Doors.DLLLoadDoors");
return(false);
}
if(Spells.DLLLoadSPDat == NULL) {
Unload();
LogFile->write(EQEMuLog::Error, "LoadEMuShareMemDLL::Load() failed to attach Spells.DLLLoadSPDat");
return(false);
}
if(NPCFactionList.DLLLoadNPCFactionLists == NULL) {
Unload();
LogFile->write(EQEMuLog::Error, "LoadEMuShareMemDLL::Load() failed to attach NPCFactionList.DLLLoadNPCFactionLists");
return(false);
}
if(NPCFactionList.GetNPCFactionList == NULL) {
Unload();
LogFile->write(EQEMuLog::Error, "LoadEMuShareMemDLL::Load() failed to attach NPCFactionList.GetNPCFactionList");
return(false);
}
if(NPCFactionList.cbAddNPCFactionList == NULL) {
Unload();
LogFile->write(EQEMuLog::Error, "LoadEMuShareMemDLL::Load() failed to attach NPCFactionList.cbAddNPCFactionList");
return(false);
}
if(NPCFactionList.cbSetFaction == NULL) {
Unload();
LogFile->write(EQEMuLog::Error, "LoadEMuShareMemDLL::Load() failed to attach NPCFactionList.cbSetFaction");
return(false);
}
if(Loot.DLLLoadLoot == NULL) {
Unload();
LogFile->write(EQEMuLog::Error, "LoadEMuShareMemDLL::Load() failed to attach Loot.DLLLoadLoot");
return(false);
}
if(Loot.cbAddLootTable == NULL) {
Unload();
LogFile->write(EQEMuLog::Error, "LoadEMuShareMemDLL::Load() failed to attach Loot.cbAddLootTable");
return(false);
}
if(Loot.cbAddLootDrop == NULL) {
Unload();
LogFile->write(EQEMuLog::Error, "LoadEMuShareMemDLL::Load() failed to attach Loot.cbAddLootDrop");
return(false);
}
if(Loot.GetLootTable == NULL) {
Unload();
LogFile->write(EQEMuLog::Error, "LoadEMuShareMemDLL::Load() failed to attach Loot.GetLootTable");
return(false);
}
if(Loot.GetLootDrop == NULL) {
Unload();
LogFile->write(EQEMuLog::Error, "LoadEMuShareMemDLL::Load() failed to attach Loot.GetLootDrop");
return(false);
}
if(Opcodes.GetEQOpcode == NULL) {
Unload();
LogFile->write(EQEMuLog::Error, "LoadEMuShareMemDLL::Load() failed to attach Opcodes.GetEQOpcode");
return(false);
}
if(Opcodes.GetEmuOpcode == NULL) {
Unload();
LogFile->write(EQEMuLog::Error, "LoadEMuShareMemDLL::Load() failed to attach Opcodes.GetEmuOpcode");
return(false);
}
if(Opcodes.SetOpcodePair == NULL) {
Unload();
LogFile->write(EQEMuLog::Error, "LoadEMuShareMemDLL::Load() failed to attach Opcodes.SetOpcodePair");
return(false);
}
if(Opcodes.DLLLoadOpcodes == NULL) {
Unload();
LogFile->write(EQEMuLog::Error, "LoadEMuShareMemDLL::Load() failed to attach Opcodes.DLLLoadOpcodes");
return(false);
}
if(Opcodes.ClearEQOpcodes == NULL) {
Unload();
LogFile->write(EQEMuLog::Error, "LoadEMuShareMemDLL::Load() failed to attach Opcodes.ClearEQOpcodes");
return(false);
}
if(SkillCaps.LoadSkillCaps == NULL) {
Unload();
LogFile->write(EQEMuLog::Error, "LoadEMuShareMemDLL::Load() failed to attach SkillCaps.LoadSkillCaps");
return(false);
}
if(SkillCaps.GetSkillCap == NULL) {
Unload();
LogFile->write(EQEMuLog::Error, "LoadEMuShareMemDLL::Load() failed to attach SkillCaps.GetSkillCap");
return(false);
}
if(SkillCaps.SetSkillCap == NULL) {
Unload();
LogFile->write(EQEMuLog::Error, "LoadEMuShareMemDLL::Load() failed to attach SkillCaps.SetSkillCap");
return(false);
}
if(SkillCaps.ClearSkillCaps == NULL) {
Unload();
LogFile->write(EQEMuLog::Error, "LoadEMuShareMemDLL::Load() failed to attach SkillCaps.ClearSkillCaps");
return(false);
}
if(SkillCaps.GetTrainLevel == NULL) {
Unload();
LogFile->write(EQEMuLog::Error, "LoadEMuShareMemDLL::Load() failed to attach SkillCaps.GetTrainLevel");
return(false);
}
LogFile->write(EQEMuLog::Status, "%s loaded", EmuLibName);
loaded = true;
return true;
}
else {
LogFile->write(EQEMuLog::Error, "%s was not loaded, but did not report an error.", EmuLibName);
}
return false;
}
void LoadEMuShareMemDLL::Unload() {
ClearFunc();
SharedLibrary::Unload();
}
void LoadEMuShareMemDLL::ClearFunc() {
Items.GetItem = 0;
Items.IterateItems = 0;
Items.cbAddItem = 0;
Items.DLLLoadItems = 0;
Doors.GetDoor = 0;
Doors.cbAddDoor = 0;
Doors.DLLLoadDoors = 0;
NPCFactionList.DLLLoadNPCFactionLists = 0;
NPCFactionList.GetNPCFactionList = 0;
NPCFactionList.cbAddNPCFactionList = 0;
NPCFactionList.cbSetFaction = 0;
Loot.DLLLoadLoot = 0;
Loot.cbAddLootTable = 0;
Loot.cbAddLootDrop = 0;
Loot.GetLootTable = 0;
Loot.GetLootDrop = 0;
Opcodes.GetEQOpcode = NULL;
Opcodes.GetEmuOpcode = NULL;
Opcodes.SetOpcodePair = NULL;
Opcodes.DLLLoadOpcodes = NULL;
Opcodes.ClearEQOpcodes = NULL;
SkillCaps.LoadSkillCaps = NULL;
SkillCaps.GetSkillCap = NULL;
SkillCaps.SetSkillCap = NULL;
SkillCaps.ClearSkillCaps = NULL;
SkillCaps.GetTrainLevel = NULL;
loaded = false;
}

187
common/EMuShareMem.h Normal file
View File

@ -0,0 +1,187 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef EMuShareMem_H
#define EMuShareMem_H
#ifdef _WINDOWS
#include <windows.h>
#else
#include "../common/unix.h"
#endif
#include "../common/eq_packet_structs.h"
#include "../zone/zonedump.h"
#include "../zone/loottable.h"
#include "SharedLibrary.h"
////////////
// Items //
///////////
typedef bool(*CALLBACK_DBLoadItems)(int32, uint32);
typedef bool(*DLLFUNC_DLLLoadItems)(const CALLBACK_DBLoadItems, uint32, int32*, uint32*);
typedef const Item_Struct*(*DLLFUNC_GetItem)(uint32);
typedef const Item_Struct*(*DLLFUNC_IterateItems)(uint32*);
typedef bool(*DLLFUNC_AddItem)(uint32, const Item_Struct*);
struct ItemsDLLFunc_Struct {
DLLFUNC_DLLLoadItems DLLLoadItems;
DLLFUNC_GetItem GetItem;
DLLFUNC_IterateItems IterateItems;
DLLFUNC_AddItem cbAddItem;
};
/*
typedef bool(*CALLBACK_DBLoadNPCTypes)(int32, uint32);
typedef bool(*DLLFUNC_DLLLoadNPCTypes)(const CALLBACK_DBLoadNPCTypes, uint32, int32*, uint32*);
typedef const NPCType*(*DLLFUNC_GetNPCType)(uint32);
typedef bool(*DLLFUNC_AddNPCType)(uint32, const NPCType*);
struct NPCTypesDLLFunc_Struct {
DLLFUNC_DLLLoadNPCTypes DLLLoadNPCTypes;
DLLFUNC_GetNPCType GetNPCType;
DLLFUNC_AddNPCType cbAddNPCType;
};
*/
////////////
// Doors ///
////////////
typedef bool(*CALLBACK_DBLoadDoors)(int32, uint32);
typedef bool(*DLLFUNC_DLLLoadDoors)(const CALLBACK_DBLoadDoors, uint32, int32*, uint32*);
typedef const Door*(*DLLFUNC_GetDoor)(uint32);
typedef bool(*DLLFUNC_AddDoor)(uint32, const Door*);
struct DoorsDLLFunc_Struct {
DLLFUNC_DLLLoadDoors DLLLoadDoors;
DLLFUNC_GetDoor GetDoor;
DLLFUNC_AddDoor cbAddDoor;
};
////////////
// Spells //
////////////
typedef bool(*CALLBACK_FileLoadSPDat)(void*, int32);
typedef bool(*DLLFUNC_DLLLoadSPDat)(const CALLBACK_FileLoadSPDat, const void**, int32*, uint32);
struct SpellsDLLFunc_Struct {
DLLFUNC_DLLLoadSPDat DLLLoadSPDat;
};
//////////////
// Factions //
//////////////
typedef bool(*CALLBACK_DBLoadNPCFactionLists)(int32, uint32);
typedef bool(*DLLFUNC_DLLLoadNPCFactionLists)(const CALLBACK_DBLoadNPCFactionLists, uint32, int32*, uint32*, uint8);
typedef const NPCFactionList*(*DLLFUNC_GetNPCFactionList)(uint32);
typedef bool(*DLLFUNC_AddNPCFactionList)(uint32, const NPCFactionList*);
typedef bool(*DLLFUNC_SetFaction)(uint32, uint32*, int32*, int8*, uint8*);
struct NPCFactionListDLLFunc_Struct {
DLLFUNC_DLLLoadNPCFactionLists DLLLoadNPCFactionLists;
DLLFUNC_GetNPCFactionList GetNPCFactionList;
DLLFUNC_AddNPCFactionList cbAddNPCFactionList;
DLLFUNC_SetFaction cbSetFaction;
};
////////////
// Loot //
///////////
typedef bool(*CALLBACK_DBLoadLoot)();
typedef bool(*DLLFUNC_DLLLoadLoot)(const CALLBACK_DBLoadLoot, uint32, uint32, uint32, uint32, uint32, uint32, uint32, uint32, uint32, uint32);
typedef bool(*DLLFUNC_AddLootTable)(uint32, const LootTable_Struct*);
typedef bool(*DLLFUNC_AddLootDrop)(uint32, const LootDrop_Struct*);
typedef const LootTable_Struct*(*DLLFUNC_GetLootTable)(uint32);
typedef const LootDrop_Struct*(*DLLFUNC_GetLootDrop)(uint32);
struct LootDLLFunc_Struct {
DLLFUNC_DLLLoadLoot DLLLoadLoot;
DLLFUNC_AddLootTable cbAddLootTable;
DLLFUNC_AddLootDrop cbAddLootDrop;
DLLFUNC_GetLootTable GetLootTable;
DLLFUNC_GetLootDrop GetLootDrop;
};
/////////////
// Opcodes //
/////////////
typedef bool(*CALLBACK_DBLoadOpcodes)(const char *filename);
typedef bool(*DLLFUNC_DLLLoadOpcodes)(const CALLBACK_DBLoadOpcodes, uint32 opsize, uint32 eq_count, uint32 emu_count, const char *filename);
typedef uint16 (*DLLFUNC_GetEQOpcode)(uint16 emu_op);
typedef uint16 (*DLLFUNC_GetEmuOpcode)(uint16 eq_op);
typedef void (*DLLFUNC_ClearEQOpcodes)();
typedef bool(*DLLFUNC_SetOpcodePair)(uint16 emu_op, uint16 eq_op);
struct OpcodeDLLFunc_Struct {
DLLFUNC_DLLLoadOpcodes DLLLoadOpcodes;
DLLFUNC_GetEQOpcode GetEQOpcode;
DLLFUNC_GetEmuOpcode GetEmuOpcode;
DLLFUNC_SetOpcodePair SetOpcodePair;
DLLFUNC_ClearEQOpcodes ClearEQOpcodes;
};
////////////////
// Skill Caps //
////////////////
typedef bool(*CALLBACK_DBLoadSkillCaps)();
typedef bool(*DLLFUNC_DLLLoadSkillCaps)(const CALLBACK_DBLoadSkillCaps, uint32 opsize, uint8 ClassCount, uint8 SkillCount, uint8 LevelCount);
typedef uint16 (*DLLFUNC_GetSkillCap)(uint8 Class_, uint8 Skill, uint8 Level);
typedef void (*DLLFUNC_ClearSkillCaps)();
typedef bool(*DLLFUNC_SetSkillCap)(uint8 Class_, uint8 Skill, uint8 Level, uint16 cap);
typedef uint8 (*DLLFUNC_GetTrainLevel)(uint8 Class_, uint8 Skill, uint8 Level);
struct SkillCapDLLFunc_Struct {
DLLFUNC_DLLLoadSkillCaps LoadSkillCaps;
DLLFUNC_GetSkillCap GetSkillCap;
DLLFUNC_SetSkillCap SetSkillCap;
DLLFUNC_ClearSkillCaps ClearSkillCaps;
DLLFUNC_GetTrainLevel GetTrainLevel;
};
class LoadEMuShareMemDLL : public SharedLibrary {
public:
LoadEMuShareMemDLL();
~LoadEMuShareMemDLL();
bool Load();
void Unload();
ItemsDLLFunc_Struct Items;
//NPCTypesDLLFunc_Struct NPCTypes;
DoorsDLLFunc_Struct Doors;
SpellsDLLFunc_Struct Spells;
NPCFactionListDLLFunc_Struct NPCFactionList;
LootDLLFunc_Struct Loot;
OpcodeDLLFunc_Struct Opcodes;
SkillCapDLLFunc_Struct SkillCaps;
private:
void ClearFunc();
bool loaded;
#ifdef _WINDOWS
#else
static uint32 refCount;
static uint32 refCountU() { return ++refCount; };
static uint32 refCountD() { return --refCount; };
#endif
};
#endif

78
common/EQDB.cpp Normal file
View File

@ -0,0 +1,78 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "debug.h"
#include "EQDB.h"
#include "database.h"
#include <mysql.h>
#include <cstring>
EQDB EQDB::s_EQDB;
EQDB::EQDB() {
}
unsigned int EQDB::field_count() {
return mysql_field_count(mysql_ref);
}
unsigned long EQDB::affected_rows() {
return mysql_affected_rows(mysql_ref);
}
unsigned long EQDB::insert_id() {
return mysql_insert_id(mysql_ref);
}
unsigned int EQDB::get_errno() {
return mysql_errno(mysql_ref);
}
Const_char * EQDB::error() {
return mysql_error(mysql_ref);
}
EQDBRes * EQDB::query(Const_char *q) {
if (mysql_real_query(mysql_ref,q,strlen(q))==0) {
if (mysql_field_count(mysql_ref)) {
MYSQL_RES *r=mysql_store_result(mysql_ref);
return new EQDBRes(r);
} else {
//no result, give them back a 'true but empty' result set
return(new EQDBRes(NULL));
}
}
return NULL;
}
//NOT THREAD SAFE!
Const_char *EQDB::escape_string(Const_char *from) {
int len = strlen(from);
char *res = new char[len*2+1];
mysql_real_escape_string(mysql_ref,res,from,len);
res[len*2] = '\0';
m_escapeBuffer = res;
delete[] res;
return(m_escapeBuffer.c_str());
}

54
common/EQDB.h Normal file
View File

@ -0,0 +1,54 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef EQDB_H_
#define EQDB_H_
#include <string>
#include <vector>
#include <map>
#include "types.h"
#include "EQDBRes.h"
#include <mysql.h>
//this is the main object exported to perl.
class EQDB {
EQDB();
public:
static EQDB *Singleton() { return(&s_EQDB); }
static void SetMySQL(MYSQL *m) { s_EQDB.mysql_ref=m; }
//BEGIN PERL EXPORT
//NOTE: you must have a space after the * of a return value
unsigned int field_count();
unsigned long affected_rows();
unsigned long insert_id();
unsigned int get_errno();
Const_char * error();
EQDBRes * query(Const_char *q);
Const_char * escape_string(Const_char *from); //NOT THREAD SAFE! (m_escapeBuffer)
//END PERL EXPORT
private:
string m_escapeBuffer;
static EQDB s_EQDB;
MYSQL *mysql_ref;
};
#endif /*EQDB_H_*/

51
common/EQDBRes.cpp Normal file
View File

@ -0,0 +1,51 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "debug.h"
#include "EQDBRes.h"
#include <mysql.h>
vector<string> EQDBRes::fetch_row_array() {
vector<string> array;
if(res == NULL)
return(array);
int count=mysql_num_fields(res);
MYSQL_ROW row=mysql_fetch_row(res);
for (int i=0;i<count;i++)
array.push_back(row[i]);
return array;
}
map<string,string> EQDBRes::fetch_row_hash() {
map<string,string> rowhash;
if(res == NULL)
return(rowhash);
MYSQL_FIELD *fields;
MYSQL_ROW row;
unsigned long num_fields,i;
if (res && (num_fields=mysql_num_fields(res)) && (row = mysql_fetch_row(res))!=NULL && (fields = mysql_fetch_fields(res))!=NULL) {
for(i=0;i<num_fields;i++) {
rowhash[fields[i].name]=(row[i] ? row[i] : "");
}
}
return rowhash;
}

48
common/EQDBRes.h Normal file
View File

@ -0,0 +1,48 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef EQDBRes_H_
#define EQDBRes_H_
#include <string>
#include <vector>
#include <map>
#include "types.h"
#include "database.h"
#include <mysql.h>
//this is the main object exported to perl.
class EQDBRes {
public:
EQDBRes(MYSQL_RES *r) { res=r; }
~EQDBRes() { finish(); }
//BEGIN PERL EXPORT
unsigned long num_rows() { return (res) ? mysql_num_rows(res) : 0; }
unsigned long num_fields() { return (res) ? mysql_num_fields(res) : 0; }
void DESTROY() { }
void finish() { if (res) mysql_free_result(res); res=NULL; };
vector<string> fetch_row_array();
map<string,string> fetch_row_hash();
unsigned long * fetch_lengths() { return (res) ? mysql_fetch_lengths(res) : 0; }
//END PERL EXPORT
private:
MYSQL_RES *res;
};
#endif /*EQDBRes_H_*/

135
common/EQEMuError.cpp Normal file
View File

@ -0,0 +1,135 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef _WINDOWS
#include <windows.h>
#endif
#include "EQEMuError.h"
#include "linked_list.h"
#include "Mutex.h"
#include "MiscFunctions.h"
#include <stdio.h>
#include <string.h>
#ifdef _WINDOWS
#include <conio.h>
#endif
void UpdateWindowTitle(char* iNewTitle = 0);
void CatchSignal(int sig_num);
const char* EQEMuErrorText[EQEMuError_MaxErrorID] = { "ErrorID# 0, No Error",
"MySQL Error #1405 or #2001 means your mysql server rejected the username and password you presented it.",
"MySQL Error #2003 means you were unable to connect to the mysql server.",
"MySQL Error #2005 means you there are too many connections on the mysql server. The server is overloaded.",
"MySQL Error #2007 means you the server is out of memory. The server is overloaded.",
};
LinkedList<char*>* EQEMuErrorList;
Mutex* MEQEMuErrorList;
AutoDelete< LinkedList<char*> > ADEQEMuErrorList(&EQEMuErrorList);
AutoDelete<Mutex> ADMEQEMuErrorList(&MEQEMuErrorList);
const char* GetErrorText(uint32 iError) {
if (iError >= EQEMuError_MaxErrorID)
return "ErrorID# out of range";
else
return EQEMuErrorText[iError];
}
void AddEQEMuError(eEQEMuError iError, bool iExitNow) {
if (!iError)
return;
if (!EQEMuErrorList) {
EQEMuErrorList = new LinkedList<char*>;
MEQEMuErrorList = new Mutex;
}
LockMutex lock(MEQEMuErrorList);
LinkedListIterator<char*> iterator(*EQEMuErrorList);
iterator.Reset();
while (iterator.MoreElements()) {
if (iterator.GetData()[0] == 1) {
//Umm... this gets a big WTF...
// if (*((uint32*) iterator.GetData()[1]) == iError)
//not sure whats going on, using a character as a pointer....
if (*((eEQEMuError*) &(iterator.GetData()[1])) == iError)
return;
}
iterator.Advance();
}
char* tmp = new char[6];
tmp[0] = 1;
tmp[5] = 0;
*((uint32*) &tmp[1]) = iError;
EQEMuErrorList->Append(tmp);
if (iExitNow)
CatchSignal(2);
}
void AddEQEMuError(char* iError, bool iExitNow) {
if (!iError)
return;
if (!EQEMuErrorList) {
EQEMuErrorList = new LinkedList<char*>;
MEQEMuErrorList = new Mutex;
}
LockMutex lock(MEQEMuErrorList);
char* tmp = strcpy(new char[strlen(iError) + 1], iError);
EQEMuErrorList->Append(tmp);
if (iExitNow)
CatchSignal(2);
}
uint32 CheckEQEMuError() {
if (!EQEMuErrorList)
return 0;
uint32 ret = 0;
char* tmp = 0;
bool HeaderPrinted = false;
LockMutex lock(MEQEMuErrorList);
while ((tmp = EQEMuErrorList->Pop() )) {
if (!HeaderPrinted) {
fprintf(stdout, "===============================\nRuntime errors:\n\n");
HeaderPrinted = true;
}
if (tmp[0] == 1) {
fprintf(stdout, "%s\n", GetErrorText(*((uint32*) &tmp[1])));
fprintf(stdout, "For more information on this error, visit http://www.eqemu.net/eqemuerror.php?id=%u\n\n", *((uint32*) &tmp[1]));
}
else {
fprintf(stdout, "%s\n\n", tmp);
}
safe_delete(tmp);
ret++;
}
return ret;
}
void CheckEQEMuErrorAndPause() {
#ifdef _WINDOWS
if (CheckEQEMuError()) {
fprintf(stdout, "Hit any key to exit\n");
UpdateWindowTitle("Error");
getch();
}
#endif
}

36
common/EQEMuError.h Normal file
View File

@ -0,0 +1,36 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef EQEMuError_H
#define EQEMuError_H
#include "../common/types.h"
enum eEQEMuError { EQEMuError_NoError,
EQEMuError_Mysql_1405,
EQEMuError_Mysql_2003,
EQEMuError_Mysql_2005,
EQEMuError_Mysql_2007,
EQEMuError_MaxErrorID };
void AddEQEMuError(eEQEMuError iError, bool iExitNow = false);
void AddEQEMuError(char* iError, bool iExitNow = false);
uint32 CheckEQEMuError();
void CheckEQEMuErrorAndPause();
#endif

472
common/EQEmuConfig.cpp Normal file
View File

@ -0,0 +1,472 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "../common/debug.h"
#include "EQEmuConfig.h"
#include "MiscFunctions.h"
#include <iostream>
#include <sstream>
string EQEmuConfig::ConfigFile = "eqemu_config.xml";
EQEmuConfig *EQEmuConfig::_config = NULL;
void EQEmuConfig::do_world(TiXmlElement *ele) {
const char *text;
TiXmlElement * sub_ele;;
text= ParseTextBlock(ele,"shortname");
if (text)
ShortName=text;
text = ParseTextBlock(ele,"longname");
if (text)
LongName=text;
text = ParseTextBlock(ele,"address",true);
if (text)
WorldAddress=text;
text = ParseTextBlock(ele,"localaddress",true);
if (text)
LocalAddress=text;
text = ParseTextBlock(ele,"maxclients",true);
if (text)
MaxClients=atoi(text);
// Get the <key> element
text = ParseTextBlock(ele,"key",true);
if (text)
SharedKey=text;
// Get the <loginserver> element
sub_ele = ele->FirstChildElement("loginserver");
if (sub_ele) {
text=ParseTextBlock(sub_ele,"host",true);
if (text)
LoginHost=text;
text=ParseTextBlock(sub_ele,"port",true);
if (text)
LoginPort=atoi(text);
text=ParseTextBlock(sub_ele,"account",true);
if (text)
LoginAccount=text;
text=ParseTextBlock(sub_ele,"password",true);
if (text)
LoginPassword=text;
} else {
char str[32];
do {
sprintf(str, "loginserver%i", ++LoginCount);
sub_ele = ele->FirstChildElement(str);
if (sub_ele) {
LoginConfig* loginconfig = new LoginConfig;
text=ParseTextBlock(sub_ele,"host",true);
if (text)
loginconfig->LoginHost=text;
text=ParseTextBlock(sub_ele,"port",true);
if (text)
loginconfig->LoginPort=atoi(text);
text=ParseTextBlock(sub_ele,"account",true);
if (text)
loginconfig->LoginAccount=text;
text=ParseTextBlock(sub_ele,"password",true);
if (text)
loginconfig->LoginPassword=text;
loginlist.Insert(loginconfig);
}
} while(sub_ele);
}
// Check for locked
sub_ele = ele->FirstChildElement("locked");
if (sub_ele != NULL)
Locked=true;
// Get the <tcp> element
sub_ele = ele->FirstChildElement("tcp");
if(sub_ele != NULL) {
text = sub_ele->Attribute("ip");
if (text)
WorldIP=text;
text = sub_ele->Attribute("port");
if (text)
WorldTCPPort=atoi(text);
text = sub_ele->Attribute("telnet");
if (text && !strcasecmp(text,"enabled"))
TelnetEnabled=true;
}
// Get the <http> element
sub_ele = ele->FirstChildElement("http");
if(sub_ele != NULL) {
// text = sub_ele->Attribute("ip");
// if (text)
// WorldIP=text;
text = sub_ele->Attribute("mimefile");
if (text)
WorldHTTPMimeFile=text;
text = sub_ele->Attribute("port");
if (text)
WorldHTTPPort=atoi(text);
text = sub_ele->Attribute("enabled");
if (text && !strcasecmp(text,"true"))
WorldHTTPEnabled=true;
}
}
void EQEmuConfig::do_chatserver(TiXmlElement *ele) {
const char *text;
text=ParseTextBlock(ele,"host",true);
if (text)
ChatHost=text;
text=ParseTextBlock(ele,"port",true);
if (text)
ChatPort=atoi(text);
}
void EQEmuConfig::do_mailserver(TiXmlElement *ele) {
const char *text;
text=ParseTextBlock(ele,"host",true);
if (text)
MailHost=text;
text=ParseTextBlock(ele,"port",true);
if (text)
MailPort=atoi(text);
}
void EQEmuConfig::do_database(TiXmlElement *ele) {
const char *text;
text=ParseTextBlock(ele,"host",true);
if (text)
DatabaseHost=text;
text=ParseTextBlock(ele,"port",true);
if (text)
DatabasePort=atoi(text);
text=ParseTextBlock(ele,"username",true);
if (text)
DatabaseUsername=text;
text=ParseTextBlock(ele,"password",true);
if (text)
DatabasePassword=text;
text=ParseTextBlock(ele,"db",true);
if (text)
DatabaseDB=text;
}
void EQEmuConfig::do_qsdatabase(TiXmlElement *ele) {
const char *text;
text=ParseTextBlock(ele,"host",true);
if (text)
QSDatabaseHost=text;
text=ParseTextBlock(ele,"port",true);
if (text)
QSDatabasePort=atoi(text);
text=ParseTextBlock(ele,"username",true);
if (text)
QSDatabaseUsername=text;
text=ParseTextBlock(ele,"password",true);
if (text)
QSDatabasePassword=text;
text=ParseTextBlock(ele,"db",true);
if (text)
QSDatabaseDB=text;
}
void EQEmuConfig::do_zones(TiXmlElement *ele) {
const char *text;
TiXmlElement *sub_ele;
// TiXmlNode *node,*sub_node;
text=ParseTextBlock(ele,"defaultstatus",true);
if (text)
DefaultStatus=atoi(text);
// Get the <ports> element
sub_ele = ele->FirstChildElement("ports");
if(sub_ele != NULL) {
text = sub_ele->Attribute("low");
if (text)
ZonePortLow=atoi(text);;
text = sub_ele->Attribute("high");
if (text)
ZonePortHigh=atoi(text);
}
}
void EQEmuConfig::do_files(TiXmlElement *ele) {
const char *text;
text=ParseTextBlock(ele,"spells",true);
if (text)
SpellsFile=text;
text=ParseTextBlock(ele,"opcodes",true);
if (text)
OpCodesFile=text;
text=ParseTextBlock(ele,"logsettings",true);
if (text)
LogSettingsFile=text;
text=ParseTextBlock(ele,"eqtime",true);
if (text)
EQTimeFile=text;
}
void EQEmuConfig::do_directories(TiXmlElement *ele) {
const char *text;
text=ParseTextBlock(ele,"maps",true);
if (text)
MapDir=text;
text=ParseTextBlock(ele,"quests",true);
if (text)
QuestDir=text;
text=ParseTextBlock(ele,"plugins",true);
if (text)
PluginDir=text;
}
void EQEmuConfig::do_launcher(TiXmlElement *ele) {
const char *text;
TiXmlElement *sub_ele;
text=ParseTextBlock(ele,"logprefix",true);
if (text)
LogPrefix = text;
text=ParseTextBlock(ele,"logsuffix",true);
if (text)
LogSuffix = text;
// Get the <exe> element
text = ParseTextBlock(ele,"exe",true);
if (text)
ZoneExe = text;
// Get the <timers> element
sub_ele = ele->FirstChildElement("timers");
if(sub_ele != NULL) {
text = sub_ele->Attribute("restart");
if (text)
RestartWait = atoi(text);
text = sub_ele->Attribute("reterminate");
if (text)
TerminateWait = atoi(text);
text = sub_ele->Attribute("initial");
if (text)
InitialBootWait = atoi(text);
text = sub_ele->Attribute("interval");
if (text)
ZoneBootInterval = atoi(text);
}
}
string EQEmuConfig::GetByName(const string &var_name) const {
if(var_name == "ShortName")
return(ShortName);
if(var_name == "LongName")
return(LongName);
if(var_name == "WorldAddress")
return(WorldAddress);
if(var_name == "LoginHost")
return(LoginHost);
if(var_name == "LoginAccount")
return(LoginAccount);
if(var_name == "LoginPassword")
return(LoginPassword);
if(var_name == "LoginPort")
return(itoa(LoginPort));
if(var_name == "Locked")
return(Locked?"true":"false");
if(var_name == "WorldTCPPort")
return(itoa(WorldTCPPort));
if(var_name == "WorldIP")
return(WorldIP);
if(var_name == "TelnetEnabled")
return(TelnetEnabled?"true":"false");
if(var_name == "WorldHTTPPort")
return(itoa(WorldHTTPPort));
if(var_name == "WorldHTTPMimeFile")
return(WorldHTTPMimeFile);
if(var_name == "WorldHTTPEnabled")
return(WorldHTTPEnabled?"true":"false");
if(var_name == "ChatHost")
return(ChatHost);
if(var_name == "ChatPort")
return(itoa(ChatPort));
if(var_name == "MailHost")
return(MailHost);
if(var_name == "MailPort")
return(itoa(MailPort));
if(var_name == "DatabaseHost")
return(DatabaseHost);
if(var_name == "DatabaseUsername")
return(DatabaseUsername);
if(var_name == "DatabasePassword")
return(DatabasePassword);
if(var_name == "DatabaseDB")
return(DatabaseDB);
if(var_name == "DatabasePort")
return(itoa(DatabasePort));
if(var_name == "QSDatabaseHost")
return(QSDatabaseHost);
if(var_name == "QSDatabaseUsername")
return(QSDatabaseUsername);
if(var_name == "QSDatabasePassword")
return(QSDatabasePassword);
if(var_name == "QSDatabaseDB")
return(QSDatabaseDB);
if(var_name == "QSDatabasePort")
return(itoa(QSDatabasePort));
if(var_name == "SpellsFile")
return(SpellsFile);
if(var_name == "OpCodesFile")
return(OpCodesFile);
if(var_name == "EQTimeFile")
return(EQTimeFile);
if(var_name == "LogSettingsFile")
return(LogSettingsFile);
if(var_name == "MapDir")
return(MapDir);
if(var_name == "QuestDir")
return(QuestDir);
if(var_name == "PluginDir")
return(PluginDir);
if(var_name == "LogPrefix")
return(LogPrefix);
if(var_name == "LogSuffix")
return(LogSuffix);
if(var_name == "ZoneExe")
return(ZoneExe);
if(var_name == "ZonePortLow")
return(itoa(ZonePortLow));
if(var_name == "ZonePortHigh")
return(itoa(ZonePortHigh));
if(var_name == "DefaultStatus")
return(itoa(DefaultStatus));
// if(var_name == "DynamicCount")
// return(itoa(DynamicCount));
return("");
}
void EQEmuConfig::Dump() const
{
cout << "ShortName = " << ShortName << endl;
cout << "LongName = " << LongName << endl;
cout << "WorldAddress = " << WorldAddress << endl;
cout << "LoginHost = " << LoginHost << endl;
cout << "LoginAccount = " << LoginAccount << endl;
cout << "LoginPassword = " << LoginPassword << endl;
cout << "LoginPort = " << LoginPort << endl;
cout << "Locked = " << Locked << endl;
cout << "WorldTCPPort = " << WorldTCPPort << endl;
cout << "WorldIP = " << WorldIP << endl;
cout << "TelnetEnabled = " << TelnetEnabled << endl;
cout << "WorldHTTPPort = " << WorldHTTPPort << endl;
cout << "WorldHTTPMimeFile = " << WorldHTTPMimeFile << endl;
cout << "WorldHTTPEnabled = " << WorldHTTPEnabled << endl;
cout << "ChatHost = " << ChatHost << endl;
cout << "ChatPort = " << ChatPort << endl;
cout << "MailHost = " << MailHost << endl;
cout << "MailPort = " << MailPort << endl;
cout << "DatabaseHost = " << DatabaseHost << endl;
cout << "DatabaseUsername = " << DatabaseUsername << endl;
cout << "DatabasePassword = " << DatabasePassword << endl;
cout << "DatabaseDB = " << DatabaseDB << endl;
cout << "DatabasePort = " << DatabasePort << endl;
cout << "QSDatabaseHost = " << QSDatabaseHost << endl;
cout << "QSDatabaseUsername = " << QSDatabaseUsername << endl;
cout << "QSDatabasePassword = " << QSDatabasePassword << endl;
cout << "QSDatabaseDB = " << QSDatabaseDB << endl;
cout << "QSDatabasePort = " << QSDatabasePort << endl;
cout << "SpellsFile = " << SpellsFile << endl;
cout << "OpCodesFile = " << OpCodesFile << endl;
cout << "EQTimeFile = " << EQTimeFile << endl;
cout << "LogSettingsFile = " << LogSettingsFile << endl;
cout << "MapDir = " << MapDir << endl;
cout << "QuestDir = " << QuestDir << endl;
cout << "PluginDir = " << PluginDir << endl;
cout << "ZonePortLow = " << ZonePortLow << endl;
cout << "ZonePortHigh = " << ZonePortHigh << endl;
cout << "DefaultStatus = " << (int)DefaultStatus << endl;
// cout << "DynamicCount = " << DynamicCount << endl;
}

227
common/EQEmuConfig.h Normal file
View File

@ -0,0 +1,227 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __EQEmuConfig_H
#define __EQEmuConfig_H
#include "XMLParser.h"
#include "linked_list.h"
struct LoginConfig {
string LoginHost;
string LoginAccount;
string LoginPassword;
uint16 LoginPort;
};
class EQEmuConfig : public XMLParser {
public:
virtual string GetByName(const string &var_name) const;
// From <world/>
string ShortName;
string LongName;
string WorldAddress;
string LocalAddress;
string LoginHost;
string LoginAccount;
string LoginPassword;
uint16 LoginPort;
uint32 LoginCount;
LinkedList<LoginConfig*> loginlist;
bool Locked;
uint16 WorldTCPPort;
string WorldIP;
bool TelnetEnabled;
int32 MaxClients;
bool WorldHTTPEnabled;
uint16 WorldHTTPPort;
string WorldHTTPMimeFile;
string SharedKey;
// From <chatserver/>
string ChatHost;
uint16 ChatPort;
// From <mailserver/>
string MailHost;
uint16 MailPort;
// From <database/>
string DatabaseHost;
string DatabaseUsername;
string DatabasePassword;
string DatabaseDB;
uint16 DatabasePort;
// From <qsdatabase> // QueryServ
string QSDatabaseHost;
string QSDatabaseUsername;
string QSDatabasePassword;
string QSDatabaseDB;
uint16 QSDatabasePort;
// From <files/>
string SpellsFile;
string OpCodesFile;
string EQTimeFile;
string LogSettingsFile;
// From <directories/>
string MapDir;
string QuestDir;
string PluginDir;
// From <launcher/>
string LogPrefix;
string LogSuffix;
string ZoneExe;
uint32 RestartWait;
uint32 TerminateWait;
uint32 InitialBootWait;
uint32 ZoneBootInterval;
// From <zones/>
uint16 ZonePortLow;
uint16 ZonePortHigh;
uint8 DefaultStatus;
// uint16 DynamicCount;
// map<string,uint16> StaticZones;
protected:
static EQEmuConfig *_config;
static string ConfigFile;
#define ELEMENT(name) \
void do_##name(TiXmlElement *ele);
#include "EQEmuConfig_elements.h"
EQEmuConfig() {
// import the needed handler prototypes
#define ELEMENT(name) \
Handlers[#name]=(ElementHandler)&EQEmuConfig::do_##name;
#include "EQEmuConfig_elements.h"
// Set sane defaults
// Login server
LoginHost="eqemulator.net";
LoginPort=5998;
// World
Locked=false;
WorldTCPPort=9000;
TelnetEnabled=false;
WorldHTTPEnabled=false;
WorldHTTPPort=9080;
WorldHTTPMimeFile="mime.types";
SharedKey = ""; //blank disables authentication
// Mail
ChatHost="eqchat.eqemulator.net";
ChatPort=7778;
// Mail
MailHost="eqmail.eqemulator.net";
MailPort=7779;
// Mysql
DatabaseHost="localhost";
DatabasePort=3306;
DatabaseUsername="eq";
DatabasePassword="eq";
DatabaseDB="eq";
// QueryServ Database
QSDatabaseHost="localhost";
QSDatabasePort=3306;
QSDatabaseUsername="eq";
QSDatabasePassword="eq";
QSDatabaseDB="eq";
// Files
SpellsFile="spells_us.txt";
OpCodesFile="opcodes.conf";
EQTimeFile="eqtime.cfg";
LogSettingsFile="log.ini";
// Dirs
MapDir="Maps";
QuestDir="quests";
PluginDir="plugins";
// Launcher
LogPrefix = "logs/zone-";
LogSuffix = ".log";
RestartWait = 10000; //milliseconds
TerminateWait = 10000; //milliseconds
InitialBootWait = 20000; //milliseconds
ZoneBootInterval = 2000; //milliseconds
#ifdef WIN32
ZoneExe = "zone.exe";
#else
ZoneExe = "./zone";
#endif
// Zones
ZonePortLow=7000;
ZonePortHigh=7999;
DefaultStatus=0;
// For where zones need to connect to.
WorldIP="127.0.0.1";
// Dynamics to start
//DynamicCount=5;
MaxClients=-1;
LoginCount=0;
}
virtual ~EQEmuConfig() {}
public:
// Produce a const singleton
static const EQEmuConfig *get() {
if (_config == NULL)
LoadConfig();
return(_config);
}
// Allow the use to set the conf file to be used.
static void SetConfigFile(string file) { EQEmuConfig::ConfigFile = file; }
// Load the config
static bool LoadConfig() {
if (_config != NULL)
delete _config;
_config=new EQEmuConfig;
return _config->ParseFile(EQEmuConfig::ConfigFile.c_str(),"server");
}
void Dump() const;
};
#endif

View File

@ -0,0 +1,11 @@
ELEMENT(world)
ELEMENT(chatserver)
ELEMENT(mailserver)
ELEMENT(zones)
ELEMENT(database)
ELEMENT(qsdatabase)
ELEMENT(files)
ELEMENT(directories)
ELEMENT(launcher)
#undef ELEMENT

414
common/EQNetwork.cpp Normal file
View File

@ -0,0 +1,414 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* EQStream classes, by Quagmire
*/
#include "../common/debug.h"
#include <iostream>
#include <iomanip>
#ifdef WIN32
#include <process.h>
#else
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "../common/unix.h"
#define SOCKET_ERROR -1
#endif
#include "EQNetwork.h"
#include "EQStream.h"
#include "../common/packet_dump.h"
#include "../common/packet_dump_file.h"
#include "../common/packet_functions.h"
#include "../common/MiscFunctions.h"
#include "../common/crc32.h"
#include "../common/eq_packet_structs.h"
using namespace std;
#define EQN_DEBUG 0
#define EQN_DEBUG_Error 0
#define EQN_DEBUG_Packet 0
#define EQN_DEBUG_Fragment 0
#define EQN_DEBUG_ACK 0
#define EQN_DEBUG_Unknown 0
#define EQN_DEBUG_NewStream 0
#define LOG_PACKETS 0
#define LOG_RAW_PACKETS_OUT 0
#define LOG_RAW_PACKETS_IN 0
//#define PRIORITYTEST
template <typename type> // LO_BYTE
type LO_BYTE (type a) {return (a&=0xff);}
template <typename type> // HI_BYTE
type HI_BYTE (type a) {return (a&=0xff00);}
template <typename type> // LO_WORD
type LO_WORD (type a) {return (a&=0xffff);}
template <typename type> // HI_WORD
type HI_WORD (type a) {return (a&=0xffff0000);}
template <typename type> // HI_LOSWAPshort
type HI_LOSWAPshort (type a) {return (LO_BYTE(a)<<8) | (HI_BYTE(a)>>8);}
template <typename type> // HI_LOSWAPlong
type HI_LOSWAPlong (type x) {return (LO_WORD(a)<<16) | (HIWORD(a)>>16);}
EQStreamServer::EQStreamServer(uint16 iPort) {
RunLoop = false;
pPort = iPort;
pOpen = false;
#ifdef WIN32
WORD version = MAKEWORD (1,1);
WSADATA wsadata;
WSAStartup (version, &wsadata);
#endif
sock = 0;
}
EQStreamServer::~EQStreamServer() {
Close();
RunLoop = false;
MLoopRunning.lock();
MLoopRunning.unlock();
#ifdef WIN32
WSACleanup();
#endif
connection_list.clear();
while (!NewQueue.empty())
NewQueue.pop(); // they're deleted with the list, clear this queue so it doesnt try to delete them again
}
bool EQStreamServer::Open(uint16 iPort) {
LockMutex lock(&MOpen);
if (iPort && pPort != iPort) {
if (pOpen)
return false;
pPort = iPort;
}
if (!RunLoop) {
RunLoop = true;
#ifdef WIN32
_beginthread(EQStreamServerLoop, 0, this);
#else
pthread_t thread;
pthread_create(&thread, NULL, &EQStreamServerLoop, this);
#endif
}
if (pOpen) {
return true;
}
else {
struct sockaddr_in address;
// int reuse_addr = 1;
int bufsize = 64 * 1024; // 64kbyte send/recieve buffers, up from default of 8k
#ifdef WIN32
unsigned long nonblocking = 1;
#endif
/* Setup internet address information.
This is used with the bind() call */
memset((char *) &address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_port = htons(pPort);
address.sin_addr.s_addr = htonl(INADDR_ANY);
/* Setting up UDP port for new clients */
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
return false;
}
//#ifdef WIN32
// setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse_addr, sizeof(reuse_addr));
setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*) &bufsize, sizeof(bufsize));
setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char*) &bufsize, sizeof(bufsize));
//#else
// setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr));
// setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(bufsize));
// setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize));
//#endif
if (bind(sock, (struct sockaddr *) &address, sizeof(address)) < 0) {
#ifdef WIN32
closesocket(sock);
#else
close(sock);
#endif
return false;
}
#ifdef WIN32
ioctlsocket (sock, FIONBIO, &nonblocking);
#else
fcntl(sock, F_SETFL, O_NONBLOCK);
#endif
pOpen = true;
return true;
}
}
void EQStreamServer::Close() {
SetOpen(false);
if (sock) {
#ifdef WIN32
closesocket(sock);
#else
close(sock);
#endif
}
sock = 0;
}
bool EQStreamServer::IsOpen() {
MOpen.lock();
bool ret = pOpen;
MOpen.unlock();
return ret;
}
void EQStreamServer::SetOpen(bool iOpen) {
MOpen.lock();
pOpen = iOpen;
MOpen.unlock();
}
void EQStreamServer::Process() {
_CP(EQStreamServer_Process);
if (!IsOpen()) {
if (sock) {
#ifdef WIN32
closesocket(sock);
#else
close(sock);
#endif
sock = 0;
}
return;
}
uchar buffer[1518];
int status;
struct sockaddr_in from;
unsigned int fromlen;
from.sin_family = AF_INET;
fromlen = sizeof(from);
while (1) {
#ifdef WIN32
status = recvfrom(sock, (char *) buffer, sizeof(buffer), 0,(struct sockaddr*) &from, (int *) &fromlen);
#else
status = recvfrom(sock, buffer, sizeof(buffer), 0,(struct sockaddr*) &from, &fromlen);
#endif
if (status >= 1) {
cout << "Got data from recvfrom" << endl;
RecvData(buffer, status, from.sin_addr.s_addr, from.sin_port);
}
else {
break;
}
}
map <string, EQStream*>::iterator connection;
for (connection = connection_list.begin( ); connection != connection_list.end( );)
{
if(!connection->second)
{
map <string, EQStream*>::iterator tmp=connection;
connection++;
connection_list.erase(tmp);
continue;
}
EQStream* eqs_data = connection->second;
if (eqs_data->IsFree() && (!eqs_data->CheckNetActive())) {
map <string, EQStream*>::iterator tmp=connection;
connection++;
safe_delete(eqs_data);
connection_list.erase(tmp);
}
else if(!eqs_data->RunLoop) {
eqs_data->Process(sock);
connection++;
}
}
}
void EQStreamServer::RecvData(uchar* data, uint32 size, uint32 irIP, uint16 irPort) {
/*
CHANGE HISTORY
Version Author Date Comment
1 Unknown Unknown Initial Revision
2 Joolz 05-Jan-2003 Optimised
3 Quagmire 05-Feb-2003 Changed so 2 connection objects wouldnt be created for the same ip/port pair, often happened
*/
// Check for invalid data
if (!data || size <= 4) return;
//if (CRC32::Generate(data, size-4) != ntohl(*((uint32*) &data[size-4]))) {
#if EQN_DEBUG_Error >= 1
//cout << "Incomming Packet failed checksum" << endl;
#endif
//return;
//}
char temp[25];
sprintf(temp,"%lu:%u",(unsigned long)irIP,irPort);
cout << "Data from " << temp << endl;
EQStream* tmp = NULL;
map <string, EQStream*>::iterator connection;
if ((connection=connection_list.find(temp))!=connection_list.end())
tmp=connection->second;
if(tmp != NULL && tmp->GetrPort() == irPort)
{
tmp->RecvData(data, size);
return;
}
else if(tmp != NULL && tmp->GetrPort() != irPort)
{
printf("Conflicting IPs & Ports: IP %i and Port %i is conflicting with IP %i and Port %i\n",irIP,irPort,tmp->GetrIP(),tmp->GetrPort());
return;
}
if (data[1]==0x01) {
cout << "New EQStream Connection." << endl;
EQStream* tmp = new EQStream(irIP, irPort);
tmp->RecvData(data, size);
connection_list[temp]=tmp;
if (connection_list.find(temp)==connection_list.end()) {
cerr <<"Could not find new connection we just added!" << endl;
}
MNewQueue.lock();
NewQueue.push(tmp);
MNewQueue.unlock();
return;
}
#if EQN_DEBUG >= 4
struct in_addr in;
in.s_addr = irIP;
cout << "WARNING: Stray packet? " << inet_ntoa(in) << ":" << irPort << endl;
#endif
}
EQStream* EQStreamServer::NewQueuePop() {
EQStream* ret = 0;
MNewQueue.lock();
if (!NewQueue.empty()) {
ret = NewQueue.front();
NewQueue.pop();
}
MNewQueue.unlock();
return ret;
}
#ifdef WIN32
void EQStreamServerLoop(void* tmp)
#else
void* EQStreamServerLoop(void* tmp)
#endif
{
#ifdef WIN32
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
#endif
EQStreamServer* eqns = (EQStreamServer*) tmp;
eqns->MLoopRunning.lock();
while (eqns->RunLoop) {
{
_CP(EQStreamServerLoop);
eqns->Process();
}
Sleep(1);
}
eqns->MLoopRunning.unlock();
#ifdef WIN32
_endthread();
#else
return 0;
#endif
}
#ifdef WIN32
void EQStreamInLoop(void* tmp)
#else
void* EQStreamInLoop(void* tmp)
#endif
{
EQStream* eqs = (EQStream*) tmp;
#ifdef _DEBUG
if (eqs->ConnectionType != Outgoing) {
ThrowError("EQStreamInLoop: eqs->ConnectionType != Outgoing");
}
#endif
eqs->MLoopRunning.lock();
Timer* tmp_timer = new Timer(100);
tmp_timer->Start();
while (eqs->RunLoop) {
{
_CP(EQStreamInLoop);
if(tmp_timer->Check())
eqs->DoRecvData();
}
Sleep(1);
}
safe_delete(tmp_timer);
eqs->MLoopRunning.unlock();
#ifdef WIN32
_endthread();
#else
return 0;
#endif
}
#ifdef WIN32
void EQStreamOutLoop(void* tmp)
#else
void* EQStreamOutLoop(void* tmp)
#endif
{
EQStream* eqs = (EQStream*) tmp;
#ifdef _DEBUG
if (eqs->ConnectionType != Outgoing) {
ThrowError("EQStreamOutLoop: eqs->ConnectionType != Outgoing");
}
#endif
eqs->MLoopRunning.lock();
Timer* tmp_timer = new Timer(100);
tmp_timer->Start();
while (eqs->RunLoop) {
{
_CP(EQStreamOutLoop);
if(tmp_timer->Check())
eqs->Process(eqs->outsock);
}
Sleep(1);
}
safe_delete(tmp_timer);
eqs->MLoopRunning.unlock();
#ifdef WIN32
_endthread();
#else
return 0;
#endif
}

121
common/EQNetwork.h Normal file
View File

@ -0,0 +1,121 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef EQNETWORK_H
#define EQNETWORK_H
#include "../common/debug.h"
//uncomment this to enable the packet profiler. Counts the number
//of each type of packet sent or received on a connection.
#ifdef ZONE
//#define PACKET_PROFILER 1
#endif
#include <string.h>
#include <map>
#include <list>
#include <queue>
using namespace std;
#include "../common/types.h"
#include "../common/timer.h"
#include "../common/linked_list.h"
#include "../common/queue.h"
#include "../common/Mutex.h"
#include "../common/packet_functions.h"
#include "EQStream.h"
#ifdef PACKET_PROFILER
#include "../common/rdtsc.h"
#endif
#define EQNC_TIMEOUT 60000
#define NAS_TIMER 100
#define KA_TIMER 400 /* keeps the lag bar constant */
#define MAX_HEADER_SIZE 39 // Quag: 39 is the max header + opcode + crc32 + unknowns size
class EQStreamServer;
class EQStream;
class EQStreamPacket;
class EQStreamFragmentGroupList;
class EQStreamFragmentGroup;
typedef EQStreamServer EQNServer;
typedef EQStream EQNConnection;
typedef EQStreamPacket EQNPacket;
typedef EQStreamFragmentGroupList EQNFragmentGroupList;
typedef EQStreamFragmentGroup EQNFragmentGroup;
#define FLAG_COMPRESSED 0x1000
#define FLAG_COMBINED 0x2000
#define FLAG_ENCRYPTED 0x4000
#define FLAG_IMPLICIT 0x8000
#define FLAG_ALL 0xF000
#define StripFlags(x) (x & ~FLAG_ALL)
// Optimistic compression, used for guessing pre-alloc size on debug output
#define BEST_COMPR_RATIO 300
enum eappCompressed { appNormal, appInflated, appDeflated };
#ifdef WIN32
void EQStreamServerLoop(void* tmp);
void EQStreamInLoop(void* tmp);
void EQStreamOutLoop(void* tmp);
#else
void* EQStreamServerLoop(void* tmp);
void* EQStreamInLoop(void* tmp);
void* EQStreamOutLoop(void* tmp);
#endif
class EQStreamServer {
public:
EQStreamServer(uint16 iPort = 0);
virtual ~EQStreamServer();
bool Open(uint16 iPort = 0); // opens the port
void Close(); // closes the port
void KillAll(); // kills all clients
inline uint16 GetPort() { return pPort; }
EQStream* NewQueuePop();
protected:
#ifdef WIN32
friend void EQStreamServerLoop(void* tmp);
#else
friend void* EQStreamServerLoop(void* tmp);
#endif
void Process();
bool IsOpen();
void SetOpen(bool iOpen);
bool RunLoop;
Mutex MLoopRunning;
private:
void RecvData(uchar* data, uint32 size, uint32 irIP, uint16 irPort);
#ifdef WIN32
SOCKET sock;
#else
int sock;
#endif
uint16 pPort;
bool pOpen;
Mutex MNewQueue;
Mutex MOpen;
map<string,EQStream*> connection_list;
queue<EQStream *> NewQueue;
};
#endif

511
common/EQPacket.cpp Normal file
View File

@ -0,0 +1,511 @@
/*
Copyright (C) 2005 Michael S. Finger
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "debug.h"
#include <stdio.h>
#include <iostream>
#include <iomanip>
#include "EQPacket.h"
#include "misc.h"
#include "op_codes.h"
#include "CRC16.h"
#include "platform.h"
#ifndef STATIC_OPCODE
#include "opcodemgr.h"
#endif
#include "packet_dump.h"
#include "packet_functions.h"
#include <cstdlib>
#include <cstring>
using namespace std;
EQPacket::EQPacket(EmuOpcode op, const unsigned char *buf, uint32 len)
: BasePacket(buf, len),
emu_opcode(op)
{
}
void EQPacket::build_raw_header_dump(char *buffer, uint16 seq) const {
BasePacket::build_raw_header_dump(buffer, seq);
buffer += strlen(buffer);
buffer += sprintf(buffer, "[EmuOpCode 0x%04x Size=%u]\n", emu_opcode, size);
}
void EQPacket::DumpRawHeader(uint16 seq, FILE *to) const
{
char buff[196];
build_raw_header_dump(buff, seq);
fprintf(to, "%s", buff);
}
void EQPacket::build_header_dump(char *buffer) const {
sprintf(buffer, "[EmuOpCode 0x%04x Size=%u]", emu_opcode, size);
}
void EQPacket::DumpRawHeaderNoTime(uint16 seq, FILE *to) const
{
if (src_ip) {
string sIP,dIP;;
sIP=long2ip(src_ip);
dIP=long2ip(dst_ip);
fprintf(to, "[%s:%d->%s:%d] ",sIP.c_str(),src_port,dIP.c_str(),dst_port);
}
if (seq != 0xffff)
fprintf(to, "[Seq=%u] ",seq);
fprintf(to, "[EmuOpCode 0x%04x Size=%lu]\n",emu_opcode,(unsigned long)size);
}
void EQProtocolPacket::build_raw_header_dump(char *buffer, uint16 seq) const
{
BasePacket::build_raw_header_dump(buffer, seq);
buffer += strlen(buffer);
buffer += sprintf(buffer, "[ProtoOpCode 0x%04x Size=%u]\n",opcode,size);
}
void EQProtocolPacket::DumpRawHeader(uint16 seq, FILE *to) const
{
char buff[196];
build_raw_header_dump(buff, seq);
fprintf(to, "%s", buff);
}
void EQProtocolPacket::build_header_dump(char *buffer) const
{
sprintf(buffer, "[ProtoOpCode 0x%04x Size=%u]",opcode,size);
}
void EQProtocolPacket::DumpRawHeaderNoTime(uint16 seq, FILE *to) const
{
if (src_ip) {
string sIP,dIP;;
sIP=long2ip(src_ip);
dIP=long2ip(dst_ip);
fprintf(to, "[%s:%d->%s:%d] ",sIP.c_str(),src_port,dIP.c_str(),dst_port);
}
if (seq != 0xffff)
fprintf(to, "[Seq=%u] ",seq);
fprintf(to, "[ProtoOpCode 0x%04x Size=%lu]\n",opcode,(unsigned long)size);
}
void EQApplicationPacket::build_raw_header_dump(char *buffer, uint16 seq) const
{
BasePacket::build_raw_header_dump(buffer, seq);
buffer += strlen(buffer);
#ifdef STATIC_OPCODE
buffer += sprintf(buffer, "[OpCode 0x%04x Size=%u]\n", emu_opcode,size);
#else
buffer += sprintf(buffer, "[OpCode %s Size=%u]\n",OpcodeManager::EmuToName(emu_opcode),size);
#endif
}
void EQApplicationPacket::DumpRawHeader(uint16 seq, FILE *to) const
{
char buff[196];
build_raw_header_dump(buff, seq);
fprintf(to, "%s", buff);
}
void EQApplicationPacket::build_header_dump(char *buffer) const
{
#ifdef STATIC_OPCODE
sprintf(buffer, "[OpCode 0x%04x Size=%u]\n", emu_opcode,size);
#else
sprintf(buffer, "[OpCode %s Size=%u]",OpcodeManager::EmuToName(emu_opcode),size);
#endif
}
void EQApplicationPacket::DumpRawHeaderNoTime(uint16 seq, FILE *to) const
{
if (src_ip) {
string sIP,dIP;;
sIP=long2ip(src_ip);
dIP=long2ip(dst_ip);
fprintf(to, "[%s:%d->%s:%d] ",sIP.c_str(),src_port,dIP.c_str(),dst_port);
}
if (seq != 0xffff)
fprintf(to, "[Seq=%u] ",seq);
#ifdef STATIC_OPCODE
fprintf(to, "[OpCode 0x%04x Size=%u]\n", emu_opcode,size);
#else
fprintf(to, "[OpCode %s Size=%lu]\n",OpcodeManager::EmuToName(emu_opcode),(unsigned long)size);
#endif
}
void EQRawApplicationPacket::build_raw_header_dump(char *buffer, uint16 seq) const
{
BasePacket::build_raw_header_dump(buffer, seq);
buffer += strlen(buffer);
#ifdef STATIC_OPCODE
buffer += sprintf(buffer, "[OpCode 0x%04x (0x%04x) Size=%u]\n", emu_opcode, opcode,size);
#else
buffer += sprintf(buffer, "[OpCode %s (0x%04x) Size=%u]\n", OpcodeManager::EmuToName(emu_opcode), opcode,size);
#endif
}
void EQRawApplicationPacket::DumpRawHeader(uint16 seq, FILE *to) const
{
char buff[196];
build_raw_header_dump(buff, seq);
fprintf(to, "%s", buff);
}
void EQRawApplicationPacket::build_header_dump(char *buffer) const
{
#ifdef STATIC_OPCODE
sprintf(buffer, "[OpCode 0x%04x (0x%04x) Size=%u]\n", emu_opcode, opcode,size);
#else
sprintf(buffer, "[OpCode %s (0x%04x) Size=%u]", OpcodeManager::EmuToName(emu_opcode), opcode,size);
#endif
}
void EQRawApplicationPacket::DumpRawHeaderNoTime(uint16 seq, FILE *to) const
{
if (src_ip) {
string sIP,dIP;;
sIP=long2ip(src_ip);
dIP=long2ip(dst_ip);
fprintf(to, "[%s:%d->%s:%d] ",sIP.c_str(),src_port,dIP.c_str(),dst_port);
}
if (seq != 0xffff)
fprintf(to, "[Seq=%u] ",seq);
#ifdef STATIC_OPCODE
fprintf(to, "[OpCode 0x%04x (0x%04x) Size=%u]\n", emu_opcode, opcode,size);
#else
fprintf(to, "[OpCode %s (0x%04x) Size=%lu]\n", OpcodeManager::EmuToName(emu_opcode), opcode,(unsigned long)size);
#endif
}
uint32 EQProtocolPacket::serialize(unsigned char *dest) const
{
if (opcode>0xff) {
*(uint16 *)dest=opcode;
} else {
*(dest)=0;
*(dest+1)=opcode;
}
memcpy(dest+2,pBuffer,size);
return size+2;
}
uint32 EQApplicationPacket::serialize(uint16 opcode, unsigned char *dest) const
{
uint8 OpCodeBytes = app_opcode_size;
if (app_opcode_size==1)
*(unsigned char *)dest = opcode;
else
{
// Application opcodes with a low order byte of 0x00 require an extra 0x00 byte inserting prior to the opcode.
if((opcode & 0x00ff) == 0)
{
*(uint8 *)dest = 0;
*(uint16 *)(dest + 1) = opcode;
++OpCodeBytes;
}
else
*(uint16 *)dest = opcode;
}
memcpy(dest+OpCodeBytes,pBuffer,size);
return size+OpCodeBytes;
}
/*EQProtocolPacket::EQProtocolPacket(uint16 op, const unsigned char *buf, uint32 len)
: BasePacket(buf, len),
opcode(op)
{
uint32 offset;
opcode=ntohs(*(const uint16 *)buf);
offset=2;
if (len-offset) {
pBuffer= new unsigned char[len-offset];
memcpy(pBuffer,buf+offset,len-offset);
size=len-offset;
} else {
pBuffer=NULL;
size=0;
}
OpMgr=&RawOpcodeManager;
}*/
bool EQProtocolPacket::combine(const EQProtocolPacket *rhs)
{
bool result=false;
if (opcode==OP_Combined && size+rhs->size+5<256) {
unsigned char *tmpbuffer=new unsigned char [size+rhs->size+3];
memcpy(tmpbuffer,pBuffer,size);
uint32 offset=size;
tmpbuffer[offset++]=rhs->Size();
offset+=rhs->serialize(tmpbuffer+offset);
size=offset;
delete[] pBuffer;
pBuffer=tmpbuffer;
result=true;
} else if (size+rhs->size+7<256) {
unsigned char *tmpbuffer=new unsigned char [size+rhs->size+6];
uint32 offset=0;
tmpbuffer[offset++]=Size();
offset+=serialize(tmpbuffer+offset);
tmpbuffer[offset++]=rhs->Size();
offset+=rhs->serialize(tmpbuffer+offset);
size=offset;
delete[] pBuffer;
pBuffer=tmpbuffer;
opcode=OP_Combined;
result=true;
}
return result;
}
/*
this is the code to do app-layer combining, instead of protocol layer.
this was taken out due to complex interactions with the opcode manager,
and will require a bit more thinking (likely moving into EQStream) to
get running again... but might be a good thing some day.
bool EQApplicationPacket::combine(const EQApplicationPacket *rhs)
{
uint32 newsize=0, offset=0;
unsigned char *tmpbuffer=NULL;
if (opcode!=OP_AppCombined) {
newsize=app_opcode_size+size+(size>254?3:1)+app_opcode_size+rhs->size+(rhs->size>254?3:1);
tmpbuffer=new unsigned char [newsize];
offset=0;
if (size>254) {
tmpbuffer[offset++]=0xff;
*(uint16 *)(tmpbuffer+offset)=htons(size);
offset+=1;
} else {
tmpbuffer[offset++]=size;
}
offset+=serialize(tmpbuffer+offset);
} else {
newsize=size+app_opcode_size+rhs->size+(rhs->size>254?3:1);
tmpbuffer=new unsigned char [newsize];
memcpy(tmpbuffer,pBuffer,size);
offset=size;
}
if (rhs->size>254) {
tmpbuffer[offset++]=0xff;
*(uint16 *)(tmpbuffer+offset)=htons(rhs->size);
offset+=1;
} else {
tmpbuffer[offset++]=rhs->size;
}
offset+=rhs->serialize(tmpbuffer+offset);
size=offset;
opcode=OP_AppCombined;
delete[] pBuffer;
pBuffer=tmpbuffer;
return true;
}
*/
bool EQProtocolPacket::ValidateCRC(const unsigned char *buffer, int length, uint32 Key)
{
bool valid=false;
// OP_SessionRequest, OP_SessionResponse, OP_OutOfSession are not CRC'd
if (buffer[0]==0x00 && (buffer[1]==OP_SessionRequest || buffer[1]==OP_SessionResponse || buffer[1]==OP_OutOfSession)) {
valid=true;
} else {
uint16 comp_crc=CRC16(buffer,length-2,Key);
uint16 packet_crc=ntohs(*(const uint16 *)(buffer+length-2));
#ifdef EQN_DEBUG
if (packet_crc && comp_crc != packet_crc) {
cout << "CRC mismatch: comp=" << hex << comp_crc << ", packet=" << packet_crc << dec << endl;
}
#endif
valid = (!packet_crc || comp_crc == packet_crc);
}
return valid;
}
uint32 EQProtocolPacket::Decompress(const unsigned char *buffer, const uint32 length, unsigned char *newbuf, uint32 newbufsize)
{
uint32 newlen=0;
uint32 flag_offset=0;
newbuf[0]=buffer[0];
if (buffer[0]==0x00) {
flag_offset=2;
newbuf[1]=buffer[1];
} else
flag_offset=1;
if (length>2 && buffer[flag_offset]==0x5a) {
newlen=InflatePacket(buffer+flag_offset+1,length-(flag_offset+1)-2,newbuf+flag_offset,newbufsize-flag_offset)+2;
newbuf[newlen++]=buffer[length-2];
newbuf[newlen++]=buffer[length-1];
} else if (length>2 && buffer[flag_offset]==0xa5) {
memcpy(newbuf+flag_offset,buffer+flag_offset+1,length-(flag_offset+1));
newlen=length-1;
} else {
memcpy(newbuf,buffer,length);
newlen=length;
}
return newlen;
}
uint32 EQProtocolPacket::Compress(const unsigned char *buffer, const uint32 length, unsigned char *newbuf, uint32 newbufsize) {
uint32 flag_offset=1,newlength;
//dump_message_column(buffer,length,"Before: ");
newbuf[0]=buffer[0];
if (buffer[0]==0) {
flag_offset=2;
newbuf[1]=buffer[1];
}
if (length>30) {
newlength=DeflatePacket(buffer+flag_offset,length-flag_offset,newbuf+flag_offset+1,newbufsize);
*(newbuf+flag_offset)=0x5a;
newlength+=flag_offset+1;
} else {
memmove(newbuf+flag_offset+1,buffer+flag_offset,length-flag_offset);
*(newbuf+flag_offset)=0xa5;
newlength=length+1;
}
//dump_message_column(newbuf,length,"After: ");
return newlength;
}
void EQProtocolPacket::ChatDecode(unsigned char *buffer, int size, int DecodeKey)
{
if ((size >= 2) && buffer[1]!=0x01 && buffer[0]!=0x02 && buffer[0]!=0x1d) {
int Key=DecodeKey;
unsigned char *test=(unsigned char *)malloc(size);
buffer+=2;
size-=2;
int i;
for (i = 0 ; i+4 <= size ; i+=4)
{
int pt = (*(int*)&buffer[i])^(Key);
Key = (*(int*)&buffer[i]);
*(int*)&test[i]=pt;
}
unsigned char KC=Key&0xFF;
for ( ; i < size ; i++)
{
test[i]=buffer[i]^KC;
}
memcpy(buffer,test,size);
free(test);
}
}
void EQProtocolPacket::ChatEncode(unsigned char *buffer, int size, int EncodeKey)
{
if (buffer[1]!=0x01 && buffer[0]!=0x02 && buffer[0]!=0x1d) {
int Key=EncodeKey;
char *test=(char*)malloc(size);
int i;
buffer+=2;
size-=2;
for ( i = 0 ; i+4 <= size ; i+=4)
{
int pt = (*(int*)&buffer[i])^(Key);
Key = pt;
*(int*)&test[i]=pt;
}
unsigned char KC=Key&0xFF;
for ( ; i < size ; i++)
{
test[i]=buffer[i]^KC;
}
memcpy(buffer,test,size);
free(test);
}
}
EQApplicationPacket *EQApplicationPacket::Copy() const {
return(new EQApplicationPacket(*this));
}
EQRawApplicationPacket *EQProtocolPacket::MakeAppPacket() const {
EQRawApplicationPacket *res = new EQRawApplicationPacket(opcode, pBuffer, size);
res->copyInfo(this);
return(res);
}
EQRawApplicationPacket::EQRawApplicationPacket(uint16 opcode, const unsigned char *buf, const uint32 len)
: EQApplicationPacket(OP_Unknown, buf, len),
opcode(opcode)
{
}
EQRawApplicationPacket::EQRawApplicationPacket(const unsigned char *buf, const uint32 len)
: EQApplicationPacket(OP_Unknown, buf+sizeof(uint16), len-sizeof(uint16))
{
if(GetExecutablePlatform() != ExePlatformUCS) {
opcode = *((const uint16 *) buf);
if(opcode == 0x0000)
{
if(len >= 3)
{
opcode = *((const uint16 *) (buf + 1));
const unsigned char *packet_start = (buf + 3);
const int32 packet_length = len - 3;
safe_delete_array(pBuffer);
if(len >= 0)
{
size = packet_length;
pBuffer = new unsigned char[size];
memcpy(pBuffer, packet_start, size);
}
else
{
size = 0;
}
}
else
{
safe_delete_array(pBuffer);
size = 0;
}
}
} else {
opcode = *((const uint8 *) buf);
}
}
void DumpPacket(const EQApplicationPacket* app, bool iShowInfo) {
if (iShowInfo) {
cout << "Dumping Applayer: 0x" << hex << setfill('0') << setw(4) << app->GetOpcode() << dec;
cout << " size:" << app->size << endl;
}
DumpPacketHex(app->pBuffer, app->size);
// DumpPacketAscii(app->pBuffer, app->size);
}

155
common/EQPacket.h Normal file
View File

@ -0,0 +1,155 @@
/*
Copyright (C) 2005 Michael S. Finger
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _EQPACKET_H
#define _EQPACKET_H
#include "BasePacket.h"
#include "EQStreamType.h"
#include "op_codes.h"
#include "platform.h"
#ifdef STATIC_OPCODE
typedef unsigned short EmuOpcode;
static const EmuOpcode OP_Unknown = 0;
#else
#include "emu_opcodes.h"
#endif
using namespace std;
class EQStream;
class EQStreamPair;
class EQPacket : public BasePacket {
friend class EQStream;
public:
virtual ~EQPacket() {}
uint32 Size() const { return size+2; }
virtual void build_raw_header_dump(char *buffer, uint16 seq=0xffff) const;
virtual void build_header_dump(char *buffer) const;
virtual void DumpRawHeader(uint16 seq=0xffff, FILE *to = stdout) const;
virtual void DumpRawHeaderNoTime(uint16 seq=0xffff, FILE *to = stdout) const;
void SetOpcode(EmuOpcode op) { emu_opcode = op; }
const EmuOpcode GetOpcode() const { return(emu_opcode); }
// const char *GetOpcodeName() const;
protected:
//this is just a cache so we dont look it up several times on Get()
//and it is mutable so we can store the cached copy even on a const object
EmuOpcode emu_opcode;
EQPacket(EmuOpcode opcode, const unsigned char *buf, const uint32 len);
// EQPacket(const EQPacket &p) { }
EQPacket() { emu_opcode=OP_Unknown; pBuffer=NULL; size=0; }
};
class EQRawApplicationPacket;
class EQProtocolPacket : public BasePacket {
friend class EQStream;
friend class EQStreamPair;
public:
EQProtocolPacket(uint16 op, const unsigned char *buf, uint32 len) : BasePacket(buf,len), opcode(op) { acked = false; }
// EQProtocolPacket(const unsigned char *buf, uint32 len);
bool combine(const EQProtocolPacket *rhs);
uint32 serialize (unsigned char *dest) const;
EQProtocolPacket *Copy() { return new EQProtocolPacket(opcode,pBuffer,size); }
EQRawApplicationPacket *MakeAppPacket() const;
bool acked;
virtual void build_raw_header_dump(char *buffer, uint16 seq=0xffff) const;
virtual void build_header_dump(char *buffer) const;
virtual void DumpRawHeader(uint16 seq=0xffff, FILE *to = stdout) const;
virtual void DumpRawHeaderNoTime(uint16 seq=0xffff, FILE *to = stdout) const;
protected:
static bool ValidateCRC(const unsigned char *buffer, int length, uint32 Key);
static uint32 Decompress(const unsigned char *buffer, const uint32 length, unsigned char *newbuf, uint32 newbufsize);
static uint32 Compress(const unsigned char *buffer, const uint32 length, unsigned char *newbuf, uint32 newbufsize);
static void ChatDecode(unsigned char *buffer, int size, int DecodeKey);
static void ChatEncode(unsigned char *buffer, int size, int EncodeKey);
uint16 GetRawOpcode() const { return(opcode); }
uint32 Size() const { return size+2; }
//the actual raw EQ opcode
uint16 opcode;
};
class EQApplicationPacket : public EQPacket {
// friend class EQProtocolPacket;
friend class EQStream;
public:
EQApplicationPacket() : EQPacket(OP_Unknown,NULL,0)
{ app_opcode_size = GetExecutablePlatform() == ExePlatformUCS ? 1 : 2; }
EQApplicationPacket(const EmuOpcode op) : EQPacket(op,NULL,0)
{ app_opcode_size = GetExecutablePlatform() == ExePlatformUCS ? 1 : 2; }
EQApplicationPacket(const EmuOpcode op, const uint32 len) : EQPacket(op,NULL,len)
{ app_opcode_size = GetExecutablePlatform() == ExePlatformUCS ? 1 : 2; }
EQApplicationPacket(const EmuOpcode op, const unsigned char *buf, const uint32 len) : EQPacket(op,buf,len)
{ app_opcode_size = GetExecutablePlatform() == ExePlatformUCS ? 1 : 2; }
bool combine(const EQApplicationPacket *rhs);
uint32 serialize (uint16 opcode, unsigned char *dest) const;
uint32 Size() const { return size+app_opcode_size; }
virtual EQApplicationPacket *Copy() const;
virtual void build_raw_header_dump(char *buffer, uint16 seq=0xffff) const;
virtual void build_header_dump(char *buffer) const;
virtual void DumpRawHeader(uint16 seq=0xffff, FILE *to = stdout) const;
virtual void DumpRawHeaderNoTime(uint16 seq=0xffff, FILE *to = stdout) const;
protected:
uint8 app_opcode_size;
private:
EQApplicationPacket(const EQApplicationPacket &p) : EQPacket(p.emu_opcode, p.pBuffer, p.size) { app_opcode_size = p.app_opcode_size; }
};
class EQRawApplicationPacket : public EQApplicationPacket {
friend class EQStream;
public:
EQRawApplicationPacket(uint16 opcode, const unsigned char *buf, const uint32 len);
uint16 GetRawOpcode() const { return(opcode); }
virtual void build_raw_header_dump(char *buffer, uint16 seq=0xffff) const;
virtual void build_header_dump(char *buffer) const;
virtual void DumpRawHeader(uint16 seq=0xffff, FILE *to = stdout) const;
virtual void DumpRawHeaderNoTime(uint16 seq=0xffff, FILE *to = stdout) const;
protected:
//the actual raw EQ opcode
uint16 opcode;
EQRawApplicationPacket(const unsigned char *buf, const uint32 len);
};
extern void DumpPacket(const EQApplicationPacket* app, bool iShowInfo = false);
#endif

1433
common/EQStream.cpp Normal file

File diff suppressed because it is too large Load Diff

281
common/EQStream.h Normal file
View File

@ -0,0 +1,281 @@
#ifndef _EQSTREAM_H
#define _EQSTREAM_H
#include <string>
#include <vector>
#include <map>
#include <queue>
#include <deque>
#ifndef WIN32
#include <netinet/in.h>
#endif
#include "EQStreamType.h"
#include "EQPacket.h"
#include "EQStreamIntf.h"
#include "Mutex.h"
#include "../common/opcodemgr.h"
#include "../common/misc.h"
#include "../common/Condition.h"
#include "../common/timer.h"
using namespace std;
#define FLAG_COMPRESSED 0x01
#define FLAG_ENCODED 0x04
#define RATEBASE 1048576 // 1 MB
#define DECAYBASE 78642 // RATEBASE/10
#pragma pack(1)
struct SessionRequest {
uint32 UnknownA;
uint32 Session;
uint32 MaxLength;
};
struct SessionResponse {
uint32 Session;
uint32 Key;
uint8 UnknownA;
uint8 Format;
uint8 UnknownB;
uint32 MaxLength;
uint32 UnknownD;
};
//Deltas are in ms, representing round trip times
struct SessionStats {
/*000*/ uint16 RequestID;
/*002*/ uint32 last_local_delta;
/*006*/ uint32 average_delta;
/*010*/ uint32 low_delta;
/*014*/ uint32 high_delta;
/*018*/ uint32 last_remote_delta;
/*022*/ uint64 packets_sent;
/*030*/ uint64 packets_recieved;
/*038*/
};
#pragma pack()
class OpcodeManager;
//extern OpcodeManager *EQNetworkOpcodeManager;
//class EQStreamFactory;
class EQStreamPair;
class EQRawApplicationPacket;
class EQStream : public EQStreamInterface {
friend class EQStreamPair; //for collector.
protected:
typedef enum {
SeqPast,
SeqInOrder,
SeqFuture
} SeqOrder;
uint32 remote_ip;
uint16 remote_port;
uint8 buffer[8192];
unsigned char *oversize_buffer;
uint32 oversize_offset,oversize_length;
uint8 app_opcode_size;
EQStreamType StreamType;
bool compressed,encoded;
uint32 retransmittimer;
uint32 retransmittimeout;
//uint32 buffer_len;
uint32 Session, Key;
uint16 NextInSeq;
uint32 MaxLen;
uint16 MaxSends;
uint8 active_users; //how many things are actively using this
Mutex MInUse;
EQStreamState State;
Mutex MState;
uint32 LastPacket;
Mutex MVarlock;
// Ack sequence tracking.
long NextAckToSend;
long LastAckSent;
long GetNextAckToSend();
long GetLastAckSent();
void AckPackets(uint16 seq);
void SetNextAckToSend(uint32);
void SetLastAckSent(uint32);
Mutex MAcks;
// Packets waiting to be sent (all protected by MOutboundQueue)
queue<EQProtocolPacket *> NonSequencedQueue;
deque<EQProtocolPacket *> SequencedQueue;
uint16 NextOutSeq;
uint16 SequencedBase; //the sequence number of SequencedQueue[0]
long NextSequencedSend; //index into SequencedQueue
Mutex MOutboundQueue;
//a buffer we use for compression/decompression
unsigned char _tempBuffer[2048];
// Packets waiting to be processed
vector<EQRawApplicationPacket *> InboundQueue;
map<unsigned short,EQProtocolPacket *> PacketQueue; //not mutex protected, only accessed by caller of Process()
Mutex MInboundQueue;
static uint16 MaxWindowSize;
int32 BytesWritten;
Mutex MRate;
int32 RateThreshold;
int32 DecayRate;
OpcodeManager **OpMgr;
// EQStreamFactory *const Factory;
EQRawApplicationPacket *MakeApplicationPacket(EQProtocolPacket *p);
EQRawApplicationPacket *MakeApplicationPacket(const unsigned char *buf, uint32 len);
EQProtocolPacket *MakeProtocolPacket(const unsigned char *buf, uint32 len);
void SendPacket(uint16 opcode, EQApplicationPacket *p);
void SetState(EQStreamState state);
void SendSessionResponse();
void SendSessionRequest();
void SendAck(uint16 seq);
void SendOutOfOrderAck(uint16 seq);
void QueuePacket(EQProtocolPacket *p);
void SendPacket(EQProtocolPacket *p);
void NonSequencedPush(EQProtocolPacket *p);
void SequencedPush(EQProtocolPacket *p);
void WritePacket(int fd,EQProtocolPacket *p);
uint32 GetKey() { return Key; }
void SetKey(uint32 k) { Key=k; }
void SetSession(uint32 s) { Session=s; }
void ProcessPacket(EQProtocolPacket *p);
// virtual void DispatchPacket(EQApplicationPacket *p) { p->DumpRaw(); }
bool Stale(uint32 now, uint32 timeout=30) { return (LastPacket && (now-LastPacket) > timeout); }
void InboundQueuePush(EQRawApplicationPacket *p);
EQRawApplicationPacket *PeekPacket(); //for collector.
EQRawApplicationPacket *PopRawPacket(); //for collector.
void InboundQueueClear();
void OutboundQueueClear();
void PacketQueueClear();
void ProcessQueue();
EQProtocolPacket *RemoveQueue(uint16 seq);
void _SendDisconnect();
void init();
public:
EQStream() { init(); remote_ip = 0; remote_port = 0; State=UNESTABLISHED; StreamType=UnknownStream; compressed=true; encoded=false; app_opcode_size=2; bytes_sent=0; bytes_recv=0; create_time=Timer::GetTimeSeconds(); }
EQStream(sockaddr_in addr) { init(); remote_ip=addr.sin_addr.s_addr; remote_port=addr.sin_port; State=UNESTABLISHED; StreamType=UnknownStream; compressed=true; encoded=false; app_opcode_size=2; bytes_sent=0; bytes_recv=0; create_time=Timer::GetTimeSeconds(); }
virtual ~EQStream() { RemoveData(); SetState(CLOSED); }
// inline void SetFactory(EQStreamFactory *f) { Factory=f; }
void SetMaxLen(uint32 length) { MaxLen=length; }
//interface used by application (EQStreamInterface)
virtual void QueuePacket(const EQApplicationPacket *p, bool ack_req=true);
virtual void FastQueuePacket(EQApplicationPacket **p, bool ack_req=true);
virtual EQApplicationPacket *PopPacket();
virtual void Close();
virtual uint32 GetRemoteIP() const { return remote_ip; }
virtual uint16 GetRemotePort() const { return remote_port; }
virtual void ReleaseFromUse() { MInUse.lock(); if(active_users > 0) active_users--; MInUse.unlock(); }
virtual void RemoveData() { InboundQueueClear(); OutboundQueueClear(); PacketQueueClear(); /*if (CombinedAppPacket) delete CombinedAppPacket;*/ }
virtual bool CheckState(EQStreamState state) { return GetState() == state; }
virtual std::string Describe() const { return("Direct EQStream"); }
void SetOpcodeManager(OpcodeManager **opm) { OpMgr = opm; }
void CheckTimeout(uint32 now, uint32 timeout=30);
bool HasOutgoingData();
void Process(const unsigned char *data, const uint32 length);
void SetLastPacketTime(uint32 t) {LastPacket=t;}
void Write(int eq_fd);
//
inline bool IsInUse() { bool flag; MInUse.lock(); flag=(active_users>0); MInUse.unlock(); return flag; }
inline void PutInUse() { MInUse.lock(); active_users++; MInUse.unlock(); }
inline EQStreamState GetState() { EQStreamState s; MState.lock(); s=State; MState.unlock(); return s; }
// static EQProtocolPacket *Read(int eq_fd, sockaddr_in *from);
static SeqOrder CompareSequence(uint16 expected_seq , uint16 seq);
// void Close() { SendDisconnect(); }
bool CheckActive() { return GetState()==ESTABLISHED; }
bool CheckClosed() { return GetState()==CLOSED; }
void SetOpcodeSize(uint8 s) { app_opcode_size = s; }
void SetStreamType(EQStreamType t);
inline const EQStreamType GetStreamType() const { return StreamType; }
static const char *StreamTypeString(EQStreamType t);
void Decay();
void AdjustRates(uint32 average_delta);
uint32 bytes_sent;
uint32 bytes_recv;
uint32 create_time;
void AddBytesSent(uint32 bytes)
{
bytes_sent += bytes;
}
void AddBytesRecv(uint32 bytes)
{
bytes_recv += bytes;
}
virtual const uint32 GetBytesSent() const { return bytes_sent; }
virtual const uint32 GetBytesRecieved() const { return bytes_recv; }
virtual const uint32 GetBytesSentPerSecond() const
{
if((Timer::GetTimeSeconds() - create_time) == 0)
return 0;
return bytes_sent / (Timer::GetTimeSeconds() - create_time);
}
virtual const uint32 GetBytesRecvPerSecond() const
{
if((Timer::GetTimeSeconds() - create_time) == 0)
return 0;
return bytes_recv / (Timer::GetTimeSeconds() - create_time);
}
//used for dynamic stream identification
class Signature {
public:
//this object could get more complicated if needed...
uint16 ignore_eq_opcode; //0=dont ignore
uint16 first_eq_opcode;
uint32 first_length; //0=dont check length
};
typedef enum {
MatchNotReady,
MatchSuccessful,
MatchFailed
} MatchState;
MatchState CheckSignature(const Signature *sig);
};
#endif

347
common/EQStreamFactory.cpp Normal file
View File

@ -0,0 +1,347 @@
#include "debug.h"
#include "EQStreamFactory.h"
#ifdef _WINDOWS
#include <winsock.h>
#include <process.h>
#include <io.h>
#include <stdio.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/select.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <pthread.h>
#endif
#include <fcntl.h>
#include <iostream>
#include "op_codes.h"
#include "EQStream.h"
#include "logsys.h"
using namespace std;
ThreadReturnType EQStreamFactoryReaderLoop(void *eqfs)
{
EQStreamFactory *fs=(EQStreamFactory *)eqfs;
#ifndef WIN32
_log(COMMON__THREADS, "Starting EQStreamFactoryReaderLoop with thread ID %d", pthread_self());
#endif
fs->ReaderLoop();
#ifndef WIN32
_log(COMMON__THREADS, "Ending EQStreamFactoryReaderLoop with thread ID %d", pthread_self());
#endif
THREAD_RETURN(NULL);
}
ThreadReturnType EQStreamFactoryWriterLoop(void *eqfs)
{
EQStreamFactory *fs=(EQStreamFactory *)eqfs;
#ifndef WIN32
_log(COMMON__THREADS, "Starting EQStreamFactoryWriterLoop with thread ID %d", pthread_self());
#endif
fs->WriterLoop();
#ifndef WIN32
_log(COMMON__THREADS, "Ending EQStreamFactoryWriterLoop with thread ID %d", pthread_self());
#endif
THREAD_RETURN(NULL);
}
EQStreamFactory::EQStreamFactory(EQStreamType type, int port, uint32 timeout)
: Timeoutable(5000), stream_timeout(timeout)
{
StreamType=type;
Port=port;
sock=-1;
}
void EQStreamFactory::Close()
{
Stop();
#ifdef _WINDOWS
closesocket(sock);
#else
close(sock);
#endif
sock=-1;
}
bool EQStreamFactory::Open()
{
struct sockaddr_in address;
#ifndef WIN32
pthread_t t1,t2;
#endif
/* Setup internet address information.
This is used with the bind() call */
memset((char *) &address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_port = htons(Port);
address.sin_addr.s_addr = htonl(INADDR_ANY);
/* Setting up UDP port for new clients */
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
return false;
}
if (bind(sock, (struct sockaddr *) &address, sizeof(address)) < 0) {
close(sock);
sock=-1;
return false;
}
#ifdef _WINDOWS
unsigned long nonblock = 1;
ioctlsocket(sock, FIONBIO, &nonblock);
#else
fcntl(sock, F_SETFL, O_NONBLOCK);
#endif
//moved these because on windows the output was delayed and causing the console window to look bad
//cout << "Starting factory Reader" << endl;
//cout << "Starting factory Writer" << endl;
#ifdef _WINDOWS
_beginthread(EQStreamFactoryReaderLoop,0, this);
_beginthread(EQStreamFactoryWriterLoop,0, this);
#else
pthread_create(&t1,NULL,EQStreamFactoryReaderLoop,this);
pthread_create(&t2,NULL,EQStreamFactoryWriterLoop,this);
#endif
return true;
}
EQStream *EQStreamFactory::Pop()
{
EQStream *s=NULL;
//cout << "Pop():Locking MNewStreams" << endl;
MNewStreams.lock();
if (NewStreams.size()) {
s=NewStreams.front();
NewStreams.pop();
s->PutInUse();
}
MNewStreams.unlock();
//cout << "Pop(): Unlocking MNewStreams" << endl;
return s;
}
void EQStreamFactory::Push(EQStream *s)
{
//cout << "Push():Locking MNewStreams" << endl;
MNewStreams.lock();
NewStreams.push(s);
MNewStreams.unlock();
//cout << "Push(): Unlocking MNewStreams" << endl;
}
void EQStreamFactory::ReaderLoop()
{
fd_set readset;
map<string,EQStream *>::iterator stream_itr;
int num;
int length;
unsigned char buffer[2048];
sockaddr_in from;
int socklen=sizeof(sockaddr_in);
timeval sleep_time;
//time_t now;
ReaderRunning=true;
while(sock!=-1) {
MReaderRunning.lock();
if (!ReaderRunning)
break;
MReaderRunning.unlock();
FD_ZERO(&readset);
FD_SET(sock,&readset);
sleep_time.tv_sec=30;
sleep_time.tv_usec=0;
if ((num=select(sock+1,&readset,NULL,NULL,&sleep_time))<0) {
// What do we wanna do?
continue;
} else if (num==0)
continue;
if(sock == -1)
break; //somebody closed us while we were sleeping.
if (FD_ISSET(sock,&readset)) {
#ifdef _WINDOWS
if ((length=recvfrom(sock,(char*)buffer,sizeof(buffer),0,(struct sockaddr*)&from,(int *)&socklen)) < 2)
#else
if ((length=recvfrom(sock,buffer,2048,0,(struct sockaddr *)&from,(socklen_t *)&socklen)) < 2)
#endif
{
// What do we wanna do?
} else {
char temp[25];
sprintf(temp,"%u.%d",ntohl(from.sin_addr.s_addr),ntohs(from.sin_port));
MStreams.lock();
if ((stream_itr=Streams.find(temp))==Streams.end()) {
if (buffer[1]==OP_SessionRequest) {
EQStream *s = new EQStream(from);
s->SetStreamType(StreamType);
Streams[temp]=s;
WriterWork.Signal();
Push(s);
s->AddBytesRecv(length);
s->Process(buffer,length);
s->SetLastPacketTime(Timer::GetCurrentTime());
}
MStreams.unlock();
} else {
EQStream *curstream = stream_itr->second;
//dont bother processing incoming packets for closed connections
if(curstream->CheckClosed())
curstream = NULL;
else
curstream->PutInUse();
MStreams.unlock(); //the in use flag prevents the stream from being deleted while we are using it.
if(curstream) {
curstream->AddBytesRecv(length);
curstream->Process(buffer,length);
curstream->SetLastPacketTime(Timer::GetCurrentTime());
curstream->ReleaseFromUse();
}
}
}
}
}
}
void EQStreamFactory::CheckTimeout()
{
//lock streams the entire time were checking timeouts, it should be fast.
MStreams.lock();
unsigned long now=Timer::GetCurrentTime();
map<string,EQStream *>::iterator stream_itr;
for(stream_itr=Streams.begin();stream_itr!=Streams.end();) {
EQStream *s = stream_itr->second;
s->CheckTimeout(now, stream_timeout);
EQStreamState state = s->GetState();
//not part of the else so we check it right away on state change
if (state==CLOSED) {
if (s->IsInUse()) {
//give it a little time for everybody to finish with it
} else {
//everybody is done, we can delete it now
//cout << "Removing connection" << endl;
map<string,EQStream *>::iterator temp=stream_itr;
stream_itr++;
//let whoever has the stream outside delete it
delete temp->second;
Streams.erase(temp);
continue;
}
}
stream_itr++;
}
MStreams.unlock();
}
void EQStreamFactory::WriterLoop()
{
map<string,EQStream *>::iterator stream_itr;
bool havework=true;
vector<EQStream *> wants_write;
vector<EQStream *>::iterator cur,end;
bool decay=false;
uint32 stream_count;
Timer DecayTimer(20);
WriterRunning=true;
DecayTimer.Enable();
while(sock!=-1) {
//if (!havework) {
//WriterWork.Wait();
//}
MWriterRunning.lock();
if (!WriterRunning)
break;
MWriterRunning.unlock();
havework = false;
wants_write.clear();
decay=DecayTimer.Check();
//copy streams into a seperate list so we dont have to keep
//MStreams locked while we are writting
MStreams.lock();
for(stream_itr=Streams.begin();stream_itr!=Streams.end();stream_itr++) {
// If it's time to decay the bytes sent, then let's do it before we try to write
if (decay)
stream_itr->second->Decay();
//bullshit checking, to see if this is really happening, GDB seems to think so...
if(stream_itr->second == NULL) {
fprintf(stderr, "ERROR: NULL Stream encountered in EQStreamFactory::WriterLoop for: %s", stream_itr->first.c_str());
continue;
}
if (stream_itr->second->HasOutgoingData()) {
havework=true;
stream_itr->second->PutInUse();
wants_write.push_back(stream_itr->second);
}
}
MStreams.unlock();
//do the actual writes
cur = wants_write.begin();
end = wants_write.end();
for(; cur != end; cur++) {
(*cur)->Write(sock);
(*cur)->ReleaseFromUse();
}
Sleep(10);
MStreams.lock();
stream_count=Streams.size();
MStreams.unlock();
if (!stream_count) {
//cout << "No streams, waiting on condition" << endl;
WriterWork.Wait();
//cout << "Awake from condition, must have a stream now" << endl;
}
}
}

58
common/EQStreamFactory.h Normal file
View File

@ -0,0 +1,58 @@
#ifndef _EQSTREAMFACTORY_H
#define _EQSTREAMFACTORY_H
#include <queue>
#include <map>
#include "../common/EQStream.h"
#include "../common/Condition.h"
#include "../common/timeoutmgr.h"
#include "../common/opcodemgr.h"
#include "../common/timer.h"
class EQStreamFactory : private Timeoutable {
private:
int sock;
int Port;
bool ReaderRunning;
Mutex MReaderRunning;
bool WriterRunning;
Mutex MWriterRunning;
Condition WriterWork;
EQStreamType StreamType;
queue<EQStream *> NewStreams;
Mutex MNewStreams;
map<string,EQStream *> Streams;
Mutex MStreams;
virtual void CheckTimeout();
Timer *DecayTimer;
uint32 stream_timeout;
public:
EQStreamFactory(EQStreamType type, uint32 timeout = 135000) : Timeoutable(5000), stream_timeout(timeout) { ReaderRunning=false; WriterRunning=false; StreamType=type; sock=-1; }
EQStreamFactory(EQStreamType type, int port, uint32 timeout = 135000);
EQStream *Pop();
void Push(EQStream *s);
bool Open();
bool Open(unsigned long port) { Port=port; return Open(); }
bool IsOpen() { return sock!=-1; }
void Close();
void ReaderLoop();
void WriterLoop();
void Stop() { StopReader(); StopWriter(); }
void StopReader() { MReaderRunning.lock(); ReaderRunning=false; MReaderRunning.unlock(); }
void StopWriter() { MWriterRunning.lock(); WriterRunning=false; MWriterRunning.unlock(); WriterWork.Signal(); }
void SignalWriter() { WriterWork.Signal(); }
};
#endif

199
common/EQStreamIdent.cpp Normal file
View File

@ -0,0 +1,199 @@
#include "debug.h"
#include "EQStreamIdent.h"
#include "EQStreamProxy.h"
#include "logsys.h"
using namespace std;
EQStreamIdentifier::~EQStreamIdentifier() {
while(!m_identified.empty()) {
m_identified.front()->ReleaseFromUse();
m_identified.pop();
}
vector<Record *>::iterator cur, end;
cur = m_streams.begin();
end = m_streams.end();
for(; cur != end; cur++) {
Record *r = *cur;
r->stream->ReleaseFromUse();
delete r;
}
vector<Patch *>::iterator curp, endp;
curp = m_patches.begin();
endp = m_patches.end();
for(; curp != endp; curp++) {
delete *curp;
}
}
void EQStreamIdentifier::RegisterPatch(const EQStream::Signature &sig, const char *name, OpcodeManager ** opcodes, const StructStrategy *structs) {
Patch *p = new Patch;
p->signature = sig;
p->name = name;
p->opcodes = opcodes;
p->structs = structs;
m_patches.push_back(p);
}
void EQStreamIdentifier::Process() {
vector<Record *>::iterator cur;
vector<Patch *>::iterator curp, endp;
//foreach pending stream.
cur = m_streams.begin();
while(cur != m_streams.end()) {
Record *r = *cur;
//first see if this stream has expired
if(r->expire.Check(false)) {
//this stream has failed to match any pattern in our timeframe.
_log(NET__IDENTIFY, "Unable to identify stream from %s:%d before timeout.", long2ip(r->stream->GetRemoteIP()).c_str(), ntohs(r->stream->GetRemotePort()));
r->stream->ReleaseFromUse();
delete r;
cur = m_streams.erase(cur);
continue;
}
//then make sure the stream is still active
//if stream hasn't finished initializing then continue;
if(r->stream->GetState() == UNESTABLISHED)
{
continue;
}
if(r->stream->GetState() != ESTABLISHED) {
//the stream closed before it was identified.
_log(NET__IDENTIFY, "Unable to identify stream from %s:%d before it closed.", long2ip(r->stream->GetRemoteIP()).c_str(), ntohs(r->stream->GetRemotePort()));
switch(r->stream->GetState())
{
case ESTABLISHED:
_log(NET__IDENTIFY, "Stream state was Established");
break;
case CLOSING:
_log(NET__IDENTIFY, "Stream state was Closing");
break;
case DISCONNECTING:
_log(NET__IDENTIFY, "Stream state was Disconnecting");
break;
case CLOSED:
_log(NET__IDENTIFY, "Stream state was Closed");
break;
default:
_log(NET__IDENTIFY, "Stream state was Unestablished or unknown");
break;
}
r->stream->ReleaseFromUse();
delete r;
cur = m_streams.erase(cur);
continue;
}
//not expired, check against all patch signatures
bool found_one = false; //"we found a matching patch for this stream"
bool all_ready = true; //"all signatures were ready to check the stream"
//foreach possbile patch...
curp = m_patches.begin();
endp = m_patches.end();
for(; !found_one && curp != endp; curp++) {
Patch *p = *curp;
//ask the stream to see if it matches the supplied signature
EQStream::MatchState res = r->stream->CheckSignature(&p->signature);
switch(res) {
case EQStream::MatchNotReady:
//the stream has not received enough packets to compare with this signature
// _log(NET__IDENT_TRACE, "%s:%d: Tried patch %s, but stream is not ready for it.", long2ip(r->stream->GetRemoteIP()).c_str(), ntohs(r->stream->GetRemotePort()), p->name.c_str());
all_ready = false;
break;
case EQStream::MatchSuccessful: {
//yay, a match.
_log(NET__IDENTIFY, "Identified stream %s:%d with signature %s", long2ip(r->stream->GetRemoteIP()).c_str(), ntohs(r->stream->GetRemotePort()), p->name.c_str());
//might want to do something less-specific here... some day..
EQStreamInterface *s = new EQStreamProxy(r->stream, p->structs, p->opcodes);
m_identified.push(s);
found_one = true;
break;
}
case EQStream::MatchFailed:
//do nothing...
_log(NET__IDENT_TRACE, "%s:%d: Tried patch %s, and it did not match.", long2ip(r->stream->GetRemoteIP()).c_str(), ntohs(r->stream->GetRemotePort()), p->name.c_str());
break;
}
}
//if we checked all patches and did not find a match.
if(all_ready && !found_one) {
//the stream cannot be identified.
_log(NET__IDENTIFY, "Unable to identify stream from %s:%d, no match found.", long2ip(r->stream->GetRemoteIP()).c_str(), ntohs(r->stream->GetRemotePort()));
r->stream->ReleaseFromUse();
}
//if we found a match, or were not able to identify it
if(found_one || all_ready) {
//cannot print ip/port here. r->stream is invalid.
delete r;
cur = m_streams.erase(cur);
} else {
cur++;
}
} //end foreach stream
}
void EQStreamIdentifier::AddStream(EQStream *&eqs) {
m_streams.push_back(new Record(eqs));
eqs = NULL;
}
EQStreamInterface *EQStreamIdentifier::PopIdentified() {
if(m_identified.empty())
return(NULL);
EQStreamInterface *res = m_identified.front();
m_identified.pop();
return(res);
}
EQStreamIdentifier::Record::Record(EQStream *s)
: stream(s),
expire(STREAM_IDENT_WAIT_MS)
{
}

50
common/EQStreamIdent.h Normal file
View File

@ -0,0 +1,50 @@
#ifndef EQSTREAMIDENT_H_
#define EQSTREAMIDENT_H_
#include "EQStream.h"
#include "timer.h"
#include <vector>
#include <string>
#include <queue>
#define STREAM_IDENT_WAIT_MS 10000
class OpcodeManager;
class StructStrategy;
class EQStreamIdentifier {
public:
~EQStreamIdentifier();
//registration interface.
void RegisterPatch(const EQStream::Signature &sig, const char *name, OpcodeManager ** opcodes, const StructStrategy *structs);
//main processing interface
void Process();
void AddStream(EQStream *& eqs);
EQStreamInterface *PopIdentified();
protected:
//registered patches..
class Patch {
public:
std::string name;
EQStream::Signature signature;
OpcodeManager ** opcodes;
const StructStrategy *structs;
};
std::vector<Patch *> m_patches; //we own these objects.
//pending streams..
class Record {
public:
Record(EQStream *s);
EQStream *stream; //we own this
Timer expire;
};
std::vector<Record *> m_streams; //we own these objects, and the streams contained in them.
std::queue<EQStreamInterface *> m_identified; //we own these objects
};
#endif /*EQSTREAMIDENT_H_*/

39
common/EQStreamIntf.h Normal file
View File

@ -0,0 +1,39 @@
#ifndef EQSTREAMINTF_H_
#define EQSTREAMINTF_H_
//this is the only part of an EQStream that is seen by the application.
#include <string>
typedef enum {
ESTABLISHED,
CLOSING, //waiting for pending data to flush.
DISCONNECTING, //have sent disconnect, waiting for their disconnect reply.
CLOSED, //received a disconnect from remote side.
UNESTABLISHED
} EQStreamState;
class EQApplicationPacket;
class EQStreamInterface {
public:
virtual ~EQStreamInterface() {}
virtual void QueuePacket(const EQApplicationPacket *p, bool ack_req=true) = 0;
virtual void FastQueuePacket(EQApplicationPacket **p, bool ack_req=true) = 0;
virtual EQApplicationPacket *PopPacket() = 0;
virtual void Close() = 0;
virtual void ReleaseFromUse() = 0;
virtual void RemoveData() = 0;
virtual uint32 GetRemoteIP() const = 0;
virtual uint16 GetRemotePort() const = 0;
virtual bool CheckState(EQStreamState state) = 0;
virtual std::string Describe() const = 0;
virtual const uint32 GetBytesSent() const { return 0; }
virtual const uint32 GetBytesRecieved() const { return 0; }
virtual const uint32 GetBytesSentPerSecond() const { return 0; }
virtual const uint32 GetBytesRecvPerSecond() const { return 0; }
};
#endif /*EQSTREAMINTF_H_*/

175
common/EQStreamLocator.h Normal file
View File

@ -0,0 +1,175 @@
/*
Copyright (C) 2005 EQEmulator Team
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _EQSTREAM_LOCATOR_H
#define _EQSTREAM_LOCATOR_H
/*
This did not turn out nearly as nice as I hoped.
*/
#include <map>
#include <string>
using namespace std;
class EQStreamInfo {
public:
EQStreamInfo() {}
EQStreamInfo(uint32 isrc_ip, uint32 idst_ip, uint16 isrc_port, uint16 idst_port) {
src_ip = isrc_ip;
dst_ip = idst_ip;
src_port = isrc_port;
dst_port = idst_port;
}
void invert(EQStreamInfo &r) const {
r.src_ip = dst_ip;
r.dst_ip = src_ip;
r.src_port = dst_port;
r.dst_port = src_port;
}
uint32 src_ip;
uint32 dst_ip;
uint16 src_port;
uint16 dst_port;
};
inline bool operator<(const EQStreamInfo &l, const EQStreamInfo &r) {
/*printf("Less than called with:\n");
printf("0x%.8x:%d -> 0x%.8x:%d < \n", l.src_ip, l.src_port, l.dst_ip, l.dst_port);
printf("0x%.8x:%d -> 0x%.8x:%d ", r.src_ip, r.src_port, r.dst_ip, r.dst_port);
bool res;
if(l.src_ip != r.src_ip)
res = (l.src_ip < r.src_ip);
else if(l.dst_ip != r.dst_ip)
res = (l.dst_ip < r.dst_ip);
else if(l.src_port != r.src_port)
res = (l.src_port < r.src_port);
else
res = (l.dst_port < r.dst_port);
if(res)
printf(": True\n");
else
printf(": False\n");*/
if(l.src_ip != r.src_ip)
return(l.src_ip < r.src_ip);
if(l.dst_ip != r.dst_ip)
return(l.dst_ip < r.dst_ip);
if(l.src_port != r.src_port)
return(l.src_port < r.src_port);
return(l.dst_port < r.dst_port);
/* //so, this turned out uglier than I had hoped
if(l.src_ip < r.src_ip)
return(true);
if(l.src_ip > r.src_ip)
return(false);
if(l.dst_ip < r.dst_ip)
return(true);
if(l.dst_ip > r.dst_ip)
return(false);
if(l.src_port < r.src_port)
return(true);
if(l.src_port > r.src_port)
return(false);
return(l.dst_port < r.dst_port);*/
}
inline bool operator==(const EQStreamInfo &l, const EQStreamInfo &r) {
// if(l.src_ip == r.dest_ip) {
// //maybe swapped
// return(l.src_port == r.dst_port && l.dst_ip == r.src_ip && l.dst_port == r.src_port);
// }
return(l.src_ip == r.src_ip && l.src_port == r.src_port && l.dst_ip == r.dst_ip && l.dst_port == r.dst_port);
}
//Forces the pointer T thing so we can return NULL
template <class T>
class EQStreamLocator {
protected:
typedef typename map<const EQStreamInfo, T *>::iterator iterator;
public:
void Clear() {
streams.clear();
}
void AddStream(const EQStreamInfo &i, T *o) {
//do we care to check if it exists?
//add this stream, and its inverse
streams[i] = o;
EQStreamInfo inv;
i.invert(inv);
streams[inv] = o;
}
//deletes this stream, and its inverse
void RemoveStream(const EQStreamInfo &i) {
iterator res;
res = streams.find(i);
if(res != streams.end())
streams.erase(res);
EQStreamInfo inv;
i.invert(inv);
res = streams.find(inv);
if(res != streams.end())
streams.erase(res);
}
//removes every occurance of this stream from the list
void RemoveStream(T *it) {
iterator cur, end;
cur = streams.begin();
end = streams.end();
for(; cur != end; cur++) {
if(cur->second == it) {
streams.erase(cur);
//lazy recursive delete for now, since we have to redo
//our iterators anyways
RemoveStream(it);
return;
}
}
}
T *GetStream(const EQStreamInfo &i) {
iterator res;
res = streams.find(i);
//possibly optimization would be to store streams.end(), since it
//may not be a constant time operation in theory, and update our
//stored copy only on insert or delete
if(res == streams.end())
return(NULL);
return(res->second);
}
//allow people to iterate over the const struct
// typedef map<const EQStreamInfo, T *>::const_iterator iterator;
// inline iterator begin() const { return(streams.begin()); }
// inline iterator end() const { return(streams.end()); }
protected:
map<const EQStreamInfo, T *> streams;
};
#endif

101
common/EQStreamProxy.cpp Normal file
View File

@ -0,0 +1,101 @@
#include "debug.h"
#include "EQStreamProxy.h"
#include "EQStream.h"
#include "StructStrategy.h"
EQStreamProxy::EQStreamProxy(EQStream *&stream, const StructStrategy *structs, OpcodeManager **opcodes)
: m_stream(stream),
m_structs(structs),
m_opcodes(opcodes)
{
stream = NULL; //take the stream.
m_stream->SetOpcodeManager(m_opcodes);
}
EQStreamProxy::~EQStreamProxy() {
//delete m_stream; //released by the stream factory.
}
std::string EQStreamProxy::Describe() const {
return(m_structs->Describe());
}
void EQStreamProxy::QueuePacket(const EQApplicationPacket *p, bool ack_req) {
if(p == NULL)
return;
EQApplicationPacket *newp = p->Copy();
FastQueuePacket(&newp, ack_req);
}
void EQStreamProxy::FastQueuePacket(EQApplicationPacket **p, bool ack_req) {
if(p == NULL || *p == NULL)
return;
m_structs->Encode(p, m_stream, ack_req);
}
EQApplicationPacket *EQStreamProxy::PopPacket() {
EQApplicationPacket *pack = m_stream->PopPacket();
if(pack == NULL)
return(NULL);
//pass this packet through the struct strategy.
m_structs->Decode(pack);
return(pack);
}
void EQStreamProxy::Close() {
m_stream->Close();
}
uint32 EQStreamProxy::GetRemoteIP() const {
return(m_stream->GetRemoteIP());
}
uint16 EQStreamProxy::GetRemotePort() const {
return(m_stream->GetRemotePort());
}
const uint32 EQStreamProxy::GetBytesSent() const
{
return(m_stream->GetBytesSent());
}
const uint32 EQStreamProxy::GetBytesRecieved() const
{
return(m_stream->GetBytesRecieved());
}
const uint32 EQStreamProxy::GetBytesSentPerSecond() const
{
return(m_stream->GetBytesSentPerSecond());
}
const uint32 EQStreamProxy::GetBytesRecvPerSecond() const
{
return(m_stream->GetBytesRecvPerSecond());
}
void EQStreamProxy::ReleaseFromUse() {
m_stream->ReleaseFromUse();
//this is so ugly, but I cant think of a better way to deal with
//it right now...
if(!m_stream->IsInUse()) {
delete this;
}
}
void EQStreamProxy::RemoveData() {
m_stream->RemoveData();
}
bool EQStreamProxy::CheckState(EQStreamState state) {
if(m_stream)
return(m_stream->CheckState(state));
return false;
}

54
common/EQStreamProxy.h Normal file
View File

@ -0,0 +1,54 @@
#ifndef EQSTREAMPROXY_H_
#define EQSTREAMPROXY_H_
#include "types.h"
#include "EQStreamIntf.h"
class EQStream;
class StructStrategy;
class OpcodeManager;
class EQApplicationPacket;
class EQStreamProxy : public EQStreamInterface {
public:
//takes ownership of the stream.
EQStreamProxy(EQStream *&stream, const StructStrategy *structs, OpcodeManager **opcodes);
virtual ~EQStreamProxy();
//EQStreamInterface:
virtual void QueuePacket(const EQApplicationPacket *p, bool ack_req=true);
virtual void FastQueuePacket(EQApplicationPacket **p, bool ack_req=true);
virtual EQApplicationPacket *PopPacket();
virtual void Close();
virtual uint32 GetRemoteIP() const;
virtual uint16 GetRemotePort() const;
virtual void ReleaseFromUse();
virtual void RemoveData();
virtual bool CheckState(EQStreamState state);
virtual std::string Describe() const;
virtual const uint32 GetBytesSent() const;
virtual const uint32 GetBytesRecieved() const;
virtual const uint32 GetBytesSentPerSecond() const;
virtual const uint32 GetBytesRecvPerSecond() const;
protected:
EQStream *const m_stream; //we own this stream object.
const StructStrategy *const m_structs; //we do not own this object.
//this is a pointer to a pointer to make it less likely that a packet will
//reference an invalid opcode manager when they are being reloaded.
OpcodeManager **const m_opcodes; //we do not own this object.
};
#endif /*EQSTREAMPROXY_H_*/

15
common/EQStreamType.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef _EQSTREAMTYPE_H
#define _EQSTREAMTYPE_H
typedef enum {
UnknownStream=0,
LoginStream,
WorldStream,
ZoneStream,
ChatOrMailStream,
ChatStream,
MailStream
} EQStreamType;
#endif

857
common/EmuTCPConnection.cpp Normal file
View File

@ -0,0 +1,857 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
*
*
*
*
* There are really two or three different objects shoe-hored into this
* connection object. Sombody really needs to factor out the relay link
* crap into its own subclass of this object, it will clean things up
* tremendously.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
#include "../common/debug.h"
#include <iostream>
using namespace std;
#include <string.h>
#include <stdio.h>
#include <iomanip>
using namespace std;
#include "EmuTCPConnection.h"
#include "EmuTCPServer.h"
#include "../common/servertalk.h"
#include "../common/packet_dump.h"
#ifdef FREEBSD //Timothy Whitman - January 7, 2003
#define MSG_NOSIGNAL 0
#endif
#define TCPN_DEBUG 0
#define TCPN_DEBUG_Console 0
#define TCPN_DEBUG_Memory 0
#define TCPN_LOG_PACKETS 0
#define TCPN_LOG_RAW_DATA_OUT 0
#define TCPN_LOG_RAW_DATA_IN 0
//server side case
EmuTCPConnection::EmuTCPConnection(uint32 ID, EmuTCPServer* iServer, SOCKET in_socket, uint32 irIP, uint16 irPort, bool iOldFormat)
: TCPConnection(ID, in_socket, irIP, irPort),
keepalive_timer(SERVER_TIMEOUT),
timeout_timer(SERVER_TIMEOUT * 2)
{
id = 0;
Server = NULL;
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
cout << "Constructor #1 on outgoing TCP# " << GetID() << 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;
if (!RemoteID)
ThrowError("Error: TCPConnection: RemoteID == 0 on RelayLink constructor");
pOldFormat = false;
ConnectionType = Incomming;
TCPMode = modePacket;
PacketMode = packetModeZone;
#if TCPN_DEBUG_Memory >= 7
cout << "Constructor #3 on outgoing TCP# " << GetID() << 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);
cout << ": Logging outgoing TCP OldPacket. OPCode: 0x" << hex << setw(4) << setfill('0') << pack->opcode << dec << ", size: " << setw(5) << setfill(' ') << pack->size << " " << inet_ntoa(in) << ":" << GetrPort() << 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);
cout << ": Logging outgoing TCP packet. OPCode: 0x" << hex << setw(4) << setfill('0') << pack->opcode << dec << ", size: " << setw(5) << setfill(' ') << pack->size << " " << inet_ntoa(in) << ":" << GetrPort() << 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);
cout << ": Logging outgoing TCP NetPacket. OPCode: 0x" << hex << setw(4) << setfill('0') << tnps->opcode << dec << ", size: " << setw(5) << setfill(' ') << tnps->size << " " << inet_ntoa(in) << ":" << GetrPort();
if (pOldFormat)
cout << " (OldFormat)";
cout << 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 NULL;
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;
cout << (5 / i) << 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();
cout "NetError: '";
if (reason)
cout << reason;
cout << "': " << inet_ntoa(in) << ":" << GetPort() << endl;
#endif
ServerPacket* pack = new ServerPacket(0);
pack->size = 1;
if (reason)
pack->size += strlen(reason) + 1;
pack->pBuffer = new uchar[pack->size];
memset(pack->pBuffer, 0, pack->size);
pack->pBuffer[0] = 255;
strcpy((char*) &pack->pBuffer[1], reason);
SendPacket(pack);
safe_delete(pack);
}
void EmuTCPConnection::RemoveRelay(EmuTCPConnection* relay, bool iSendRelayDisconnect) {
if (iSendRelayDisconnect) {
ServerPacket* pack = new ServerPacket(0, 5);
pack->pBuffer[0] = 3;
*((uint32*) &pack->pBuffer[1]) = relay->GetRemoteID();
SendPacket(pack);
safe_delete(pack);
}
RelayCount--;
}
bool EmuTCPConnection::ProcessReceivedData(char* errbuf) {
if (errbuf)
errbuf[0] = 0;
timeout_timer.Start();
if (!recvbuf)
return true;
if (TCPMode == modePacket) {
if (pOldFormat)
return ProcessReceivedDataAsOldPackets(errbuf);
else
return ProcessReceivedDataAsPackets(errbuf);
}
//else, use the base class's text processing.
bool ret = TCPConnection::ProcessReceivedData(errbuf);
//see if we made the transition to packet mode...
if(ret && TCPMode == modePacket) {
return ProcessReceivedDataAsPackets(errbuf);
}
return(ret);
}
bool EmuTCPConnection::ProcessReceivedDataAsPackets(char* errbuf) {
if (errbuf)
errbuf[0] = 0;
int32 base = 0;
int32 size = 7;
uchar* buffer;
ServerPacket* pack = 0;
while ((recvbuf_used - base) >= size) {
EmuTCPNetPacket_Struct* tnps = (EmuTCPNetPacket_Struct*) &recvbuf[base];
buffer = tnps->buffer;
size = tnps->size;
if (size >= MaxTCPReceiveBuffferSize) {
#if TCPN_DEBUG_Memory >= 1
cout << "TCPConnection[" << GetID() << "]::ProcessReceivedDataAsPackets(): size[" << size << "] >= MaxTCPReceiveBuffferSize" << 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
cout << "Received TCP Network layer packet" << endl;
#endif
ProcessNetworkLayerPacket(pack);
}
#if TCPN_DEBUG >= 5
else {
cout << "Received TCP keepalive packet. (opcode=0)" << 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);
cout << ": Logging incoming TCP packet. OPCode: 0x" << hex << setw(4) << setfill('0') << pack->opcode << dec << ", size: " << setw(5) << setfill(' ') << pack->size << " " << inet_ntoa(in) << ":" << GetrPort() << 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
cout << "Error relaying packet: con = 0" << endl;
#endif
safe_delete(pack);
}
else
con->OutQueuePush(pack);
}
else
OutQueuePush(pack);
}
base += size;
size = 7;
}
}
if (base != 0) {
if (base >= recvbuf_used) {
safe_delete_array(recvbuf);
} else {
uchar* tmpbuf = new uchar[recvbuf_size - base];
memcpy(tmpbuf, &recvbuf[base], recvbuf_used - base);
safe_delete_array(recvbuf);
recvbuf = tmpbuf;
recvbuf_used -= base;
recvbuf_size -= base;
}
}
return true;
}
bool EmuTCPConnection::ProcessReceivedDataAsOldPackets(char* errbuf) {
int32 base = 0;
int32 size = 4;
uchar* buffer;
ServerPacket* pack = 0;
while ((recvbuf_used - base) >= size) {
buffer = &recvbuf[base];
memcpy(&size, &buffer[2], 2);
if (size >= MaxTCPReceiveBuffferSize) {
#if TCPN_DEBUG_Memory >= 1
cout << "TCPConnection[" << GetID() << "]::ProcessReceivedDataAsPackets(): size[" << size << "] >= MaxTCPReceiveBuffferSize" << 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);
cout << ": Logging incoming TCP OldPacket. OPCode: 0x" << hex << setw(4) << setfill('0') << pack->opcode << dec << ", size: " << setw(5) << setfill(' ') << pack->size << " " << inet_ntoa(in) << ":" << GetrPort() << endl;
#if TCPN_LOG_PACKETS == 2
if (pack->size >= 32)
DumpPacket(pack->pBuffer, 32);
else
DumpPacket(pack);
#endif
#if TCPN_LOG_PACKETS >= 3
DumpPacket(pack);
#endif
}
#endif
OutQueuePush(pack);
}
base += size;
size = 4;
}
}
if (base != 0) {
if (base >= recvbuf_used) {
safe_delete_array(recvbuf);
}
else {
uchar* tmpbuf = new uchar[recvbuf_size - base];
memcpy(tmpbuf, &recvbuf[base], recvbuf_used - base);
safe_delete_array(recvbuf);
recvbuf = tmpbuf;
recvbuf_used -= base;
recvbuf_size -= base;
}
}
return true;
}
void EmuTCPConnection::ProcessNetworkLayerPacket(ServerPacket* pack) {
uint8 opcode = pack->pBuffer[0];
uint8* data = &pack->pBuffer[1];
switch (opcode) {
case 0: {
break;
}
case 1: { // Switch to RelayServer mode
if (pack->size != 1) {
SendNetErrorPacket("New RelayClient: wrong size, expected 1");
break;
}
if (RelayServer) {
SendNetErrorPacket("Switch to RelayServer mode when already in RelayServer mode");
break;
}
if (RemoteID) {
SendNetErrorPacket("Switch to RelayServer mode by a Relay Client");
break;
}
if (ConnectionType != Incomming) {
SendNetErrorPacket("Switch to RelayServer mode on outgoing connection");
break;
}
#if TCPC_DEBUG >= 3
struct in_addr in;
in.s_addr = GetrIP();
cout << "Switching to RelayServer mode: " << inet_ntoa(in) << ":" << GetPort() << endl;
#endif
RelayServer = true;
break;
}
case 2: { // New Relay Client
if (!RelayServer) {
SendNetErrorPacket("New RelayClient when not in RelayServer mode");
break;
}
if (pack->size != 11) {
SendNetErrorPacket("New RelayClient: wrong size, expected 11");
break;
}
if (ConnectionType != Incomming) {
SendNetErrorPacket("New RelayClient: illegal on outgoing connection");
break;
}
EmuTCPConnection* con = new EmuTCPConnection(Server->GetNextID(), Server, this, *((uint32*) data), *((uint32*) &data[4]), *((uint16*) &data[8]));
Server->AddConnection(con);
RelayCount++;
break;
}
case 3: { // Delete Relay Client
if (!RelayServer) {
SendNetErrorPacket("Delete RelayClient when not in RelayServer mode");
break;
}
if (pack->size != 5) {
SendNetErrorPacket("Delete RelayClient: wrong size, expected 5");
break;
}
EmuTCPConnection* con = Server->FindConnection(*((uint32*)data));
if (con) {
if (ConnectionType == Incomming) {
if (con->GetRelayLink() != this) {
SendNetErrorPacket("Delete RelayClient: RelayLink != this");
break;
}
}
con->Disconnect(false);
}
break;
}
case 255: {
#if TCPC_DEBUG >= 1
struct in_addr in;
in.s_addr = GetrIP();
cout "Received NetError: '";
if (pack->size > 1)
cout << (char*) data;
cout << "': " << inet_ntoa(in) << ":" << GetPort() << endl;
#endif
break;
}
}
}
bool EmuTCPConnection::SendData(bool &sent_something, char* errbuf) {
sent_something = false;
if(!TCPConnection::SendData(sent_something, errbuf))
return(false);
if(sent_something)
keepalive_timer.Start();
else if (TCPMode == modePacket && keepalive_timer.Check()) {
ServerPacket* pack = new ServerPacket(0, 0);
SendPacket(pack);
safe_delete(pack);
#if TCPN_DEBUG >= 5
cout << "Sending TCP keepalive packet. (timeout=" << timeout_timer.GetRemainingTime() << " remaining)" << 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);
}

103
common/EmuTCPConnection.h Normal file
View File

@ -0,0 +1,103 @@
#ifndef EmuTCPCONNECTION_H_
#define EmuTCPCONNECTION_H_
#include "TCPConnection.h"
#include "timer.h"
//moved out of TCPConnection:: to be more exportable
#pragma pack(1)
struct EmuTCPNetPacket_Struct {
uint32 size;
struct {
uint8
compressed : 1,
destination : 1,
flag3 : 1,
flag4 : 1,
flag5 : 1,
flag6 : 1,
flag7 : 1,
flag8 : 1;
} flags;
uint16 opcode;
uchar buffer[0];
};
#pragma pack()
struct SPackSendQueue;
class EmuTCPServer;
class EmuTCPConnection : public TCPConnection {
public:
enum eTCPMode { modeConsole, modeTransition, modePacket };
enum ePacketMode { packetModeZone, packetModeLauncher, packetModeLogin, packetModeUCS, packetModeQueryServ };
EmuTCPConnection(uint32 ID, EmuTCPServer* iServer, SOCKET iSock, uint32 irIP, uint16 irPort, bool iOldFormat = false);
EmuTCPConnection(bool iOldFormat = false, EmuTCPServer* iRelayServer = 0, eTCPMode iMode = modePacket); // for outgoing connections
EmuTCPConnection(uint32 ID, EmuTCPServer* iServer, EmuTCPConnection* iRelayLink, uint32 iRemoteID, uint32 irIP, uint16 irPort); // for relay connections
virtual ~EmuTCPConnection();
virtual bool ConnectIP(uint32 irIP, uint16 irPort, char* errbuf = 0);
virtual void Disconnect(bool iSendRelayDisconnect = true);
static EmuTCPNetPacket_Struct* MakePacket(ServerPacket* pack, uint32 iDestination = 0);
static SPackSendQueue* MakeOldPacket(ServerPacket* pack);
virtual bool SendPacket(ServerPacket* pack, uint32 iDestination = 0);
virtual bool SendPacket(EmuTCPNetPacket_Struct* tnps);
ServerPacket* PopPacket(); // OutQueuePop()
void SetPacketMode(ePacketMode mode) { PacketMode = mode; }
eTCPMode GetMode() const { return TCPMode; }
ePacketMode GetPacketMode() const { return(PacketMode); }
//relay crap:
inline bool IsRelayServer() const { return RelayServer; }
inline TCPConnection* GetRelayLink() const { return RelayLink; }
inline uint32 GetRemoteID() const { return RemoteID; }
protected:
void OutQueuePush(ServerPacket* pack);
void RemoveRelay(EmuTCPConnection* relay, bool iSendRelayDisconnect);
void SendNetErrorPacket(const char* reason = 0);
virtual bool SendData(bool &sent_something, char* errbuf = 0);
virtual bool RecvData(char* errbuf = 0);
virtual bool ProcessReceivedData(char* errbuf = 0);
bool ProcessReceivedDataAsPackets(char* errbuf = 0);
bool ProcessReceivedDataAsOldPackets(char* errbuf = 0);
void ProcessNetworkLayerPacket(ServerPacket* pack);
virtual bool LineOutQueuePush(char* line);
virtual void ClearBuffers();
EmuTCPServer* Server;
eTCPMode TCPMode;
ePacketMode PacketMode;
bool pOldFormat;
Timer keepalive_timer;
Timer timeout_timer;
//relay crap:
EmuTCPConnection* RelayLink;
int32 RelayCount;
bool RelayServer;
uint32 RemoteID;
//input queue...
void InModeQueuePush(EmuTCPNetPacket_Struct* tnps);
MyQueue<EmuTCPNetPacket_Struct> InModeQueue;
//output queue...
MyQueue<ServerPacket> OutQueue;
Mutex MOutQueueLock;
};
#endif /*EmuTCPCONNECTION_H_*/

96
common/EmuTCPServer.cpp Normal file
View File

@ -0,0 +1,96 @@
#include "debug.h"
#include "EmuTCPServer.h"
#include "EmuTCPConnection.h"
EmuTCPServer::EmuTCPServer(uint16 iPort, bool iOldFormat)
: TCPServer<EmuTCPConnection>(iPort),
pOldFormat(iOldFormat)
{
}
EmuTCPServer::~EmuTCPServer() {
MInQueue.lock();
while(!m_InQueue.empty()) {
delete m_InQueue.front();
m_InQueue.pop();
}
MInQueue.unlock();
}
void EmuTCPServer::Process() {
CheckInQueue();
TCPServer<EmuTCPConnection>::Process();
}
void EmuTCPServer::CreateNewConnection(uint32 ID, SOCKET in_socket, uint32 irIP, uint16 irPort)
{
EmuTCPConnection *conn = new EmuTCPConnection(ID, this, in_socket, irIP, irPort, pOldFormat);
AddConnection(conn);
}
void EmuTCPServer::SendPacket(ServerPacket* pack) {
EmuTCPNetPacket_Struct* tnps = EmuTCPConnection::MakePacket(pack);
SendPacket(&tnps);
}
void EmuTCPServer::SendPacket(EmuTCPNetPacket_Struct** tnps) {
MInQueue.lock();
m_InQueue.push(*tnps);
MInQueue.unlock();
tnps = NULL;
}
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 = NULL;
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(NULL);
}

38
common/EmuTCPServer.h Normal file
View File

@ -0,0 +1,38 @@
#ifndef EmuTCPSERVER_H_
#define EmuTCPSERVER_H_
#include "TCPServer.h"
class EmuTCPConnection;
struct EmuTCPNetPacket_Struct;
class ServerPacket;
class EmuTCPServer : public TCPServer<EmuTCPConnection> {
public:
EmuTCPServer(uint16 iPort = 0, bool iOldFormat = false);
virtual ~EmuTCPServer();
//packet broadcast routines.
void SendPacket(ServerPacket* pack);
void SendPacket(EmuTCPNetPacket_Struct** tnps);
//special crap for relay management
EmuTCPConnection *FindConnection(uint32 iID);
//exposed for some crap we pull. Do not call from outside this object.
TCPServer<EmuTCPConnection>::AddConnection;
protected:
virtual void Process();
virtual void CreateNewConnection(uint32 ID, SOCKET in_socket, uint32 irIP, uint16 irPort);
bool pOldFormat;
//broadcast packet queue..
void CheckInQueue();
Mutex MInQueue;
EmuTCPNetPacket_Struct* InQueuePop(); //returns ownership
std::queue<EmuTCPNetPacket_Struct *> m_InQueue;
};
#endif /*EmuTCPSERVER_H_*/

1951
common/Item.cpp Normal file

File diff suppressed because it is too large Load Diff

456
common/Item.h Normal file
View File

@ -0,0 +1,456 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2003 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// @merth notes:
// These classes could be optimized with database reads/writes by storing
// a status flag indicating how object needs to interact with database
#ifndef __ITEM_H
#define __ITEM_H
class ItemInst; // Item belonging to a client (contains info on item, dye, augments, charges, etc)
class ItemInstQueue; // Queue of ItemInst objects (i.e., cursor)
class Inventory; // Character inventory
class ItemParse; // Parses item packets
class EvoItemInst; // Extended item inst, for use with scaling/evolving items
class EvolveInfo; // Stores information about an evolving item family
#include <string>
#include <vector>
#include <map>
#include <list>
using namespace std;
#include "../common/eq_packet_structs.h"
#include "../common/eq_constants.h"
#include "../common/item_struct.h"
// Helper typedefs
typedef list<ItemInst*>::const_iterator iter_queue;
typedef map<int16, ItemInst*>::const_iterator iter_inst;
typedef map<uint8, ItemInst*>::const_iterator iter_contents;
namespace ItemField {
enum {
source=0,
#define F(x) x,
#include "item_fieldlist.h"
#undef F
updated
};
};
// Indexing positions to the beginning slot_id's for a bucket of slots
#define IDX_EQUIP 0
#define IDX_CURSOR_BAG 331
#define IDX_INV 22
#define IDX_INV_BAG 251
#define IDX_TRIBUTE 400
#define IDX_BANK 2000
#define IDX_BANK_BAG 2031
#define IDX_SHBANK 2500
#define IDX_SHBANK_BAG 2531
#define IDX_TRADE 3000
#define IDX_TRADE_BAG 3031
#define IDX_TRADESKILL 4000
#define MAX_ITEMS_PER_BAG 10
// Specifies usage type for item inside ItemInst
enum ItemUseType
{
ItemUseNormal,
ItemUseWorldContainer
};
typedef enum {
byFlagIgnore, //do not consider this flag
byFlagSet, //apply action if the flag is set
byFlagNotSet //apply action if the flag is NOT set
} byFlagSetting;
//FatherNitwit: location bits for searching specific
//places with HasItem() and HasItemByUse()
enum {
invWhereWorn = 0x01,
invWherePersonal = 0x02, //in the character's inventory
invWhereBank = 0x04,
invWhereSharedBank = 0x08,
invWhereTrading = 0x10,
invWhereCursor = 0x20
};
// ########################################
// Class: Queue
// Queue that allows a read-only iterator
class ItemInstQueue
{
public:
~ItemInstQueue();
/////////////////////////
// Public Methods
/////////////////////////
inline iter_queue begin() { return m_list.begin(); }
inline iter_queue end() { return m_list.end(); }
void push(ItemInst* inst);
void push_front(ItemInst* inst);
ItemInst* pop();
ItemInst* peek_front() const;
inline int size() { return static_cast<int>(m_list.size()); }
protected:
/////////////////////////
// Protected Members
/////////////////////////
list<ItemInst*> m_list;
};
// ########################################
// Class: Inventory
// Character inventory
class Inventory
{
friend class ItemInst;
public:
///////////////////////////////
// Public Methods
///////////////////////////////
virtual ~Inventory();
// Retrieve a writeable item at specified slot
ItemInst* GetItem(int16 slot_id) const;
ItemInst* GetItem(int16 slot_id, uint8 bagidx) const;
inline iter_queue cursor_begin() { return m_cursor.begin(); }
inline iter_queue cursor_end() { return m_cursor.end(); }
inline bool CursorEmpty() { return (m_cursor.size() == 0); }
// Retrieve a read-only item from inventory
inline const ItemInst* operator[](int16 slot_id) const { return GetItem(slot_id); }
// Add item to inventory
int16 PutItem(int16 slot_id, const ItemInst& inst);
// Add item to cursor queue
int16 PushCursor(const ItemInst& inst);
// Swap items in inventory
bool SwapItem(int16 slot_a, int16 slot_b);
// Remove item from inventory
bool DeleteItem(int16 slot_id, uint8 quantity=0);
// Checks All items in a bag for No Drop
bool CheckNoDrop(int16 slot_id);
// Remove item from inventory (and take control of memory)
ItemInst* PopItem(int16 slot_id);
// Check whether item exists in inventory
// where argument specifies OR'd list of invWhere constants to look
int16 HasItem(uint32 item_id, uint8 quantity=0, uint8 where=0xFF);
// Check whether there is space for the specified number of the specified item.
bool HasSpaceForItem(const Item_Struct *ItemToTry, int16 Quantity);
// Check whether item exists in inventory
// where argument specifies OR'd list of invWhere constants to look
int16 HasItemByUse(uint8 use, uint8 quantity=0, uint8 where=0xFF);
// Check whether item exists in inventory
// where argument specifies OR'd list of invWhere constants to look
int16 HasItemByLoreGroup(uint32 loregroup, uint8 where=0xFF);
// Locate an available inventory slot
int16 FindFreeSlot(bool for_bag, bool try_cursor, uint8 min_size = 0, bool is_arrow = false);
// Calculate slot_id for an item within a bag
static int16 CalcSlotId(int16 slot_id); // Calc parent bag's slot_id
static int16 CalcSlotId(int16 bagslot_id, uint8 bagidx); // Calc slot_id for item inside bag
static uint8 CalcBagIdx(int16 slot_id); // Calc bagidx for slot_id
static int16 CalcSlotFromMaterial(uint8 material);
static uint8 CalcMaterialFromSlot(int16 equipslot);
static bool CanItemFitInContainer(const Item_Struct *ItemToTry, const Item_Struct *Container);
// Test whether a given slot can support a container item
static bool SupportsContainers(int16 slot_id);
void dumpInventory();
void SetCustomItemData(uint32 character_id, int16 slot_id, std::string identifier, std::string value);
void SetCustomItemData(uint32 character_id, int16 slot_id, std::string identifier, int value);
void SetCustomItemData(uint32 character_id, int16 slot_id, std::string identifier, float value);
void SetCustomItemData(uint32 character_id, int16 slot_id, std::string identifier, bool value);
std::string GetCustomItemData(int16 slot_id, std::string identifier);
protected:
///////////////////////////////
// Protected Methods
///////////////////////////////
// Retrieves item within an inventory bucket
ItemInst* _GetItem(const map<int16, ItemInst*>& bucket, int16 slot_id) const;
// Private "put" item into bucket, without regard for what is currently in bucket
int16 _PutItem(int16 slot_id, ItemInst* inst);
// Checks an inventory bucket for a particular item
int16 _HasItem(map<int16, ItemInst*>& bucket, uint32 item_id, uint8 quantity);
int16 _HasItem(ItemInstQueue& iqueue, uint32 item_id, uint8 quantity);
int16 _HasItemByUse(map<int16, ItemInst*>& bucket, uint8 use, uint8 quantity);
int16 _HasItemByUse(ItemInstQueue& iqueue, uint8 use, uint8 quantity);
int16 _HasItemByLoreGroup(map<int16, ItemInst*>& bucket, uint32 loregroup);
int16 _HasItemByLoreGroup(ItemInstQueue& iqueue, uint32 loregroup);
// Player inventory
map<int16, ItemInst*> m_worn; // Items worn by character
map<int16, ItemInst*> m_inv; // Items in character personal inventory
map<int16, ItemInst*> m_bank; // Items in character bank
map<int16, ItemInst*> m_shbank; // Items in character shared bank
map<int16, ItemInst*> m_trade; // Items in a trade session
ItemInstQueue m_cursor; // Items on cursor: FIFO
};
class SharedDatabase;
// ########################################
// Class: ItemInst
// Base class for an instance of an item
// An item instance encapsulates item data + data specific
// to an item instance (includes dye, augments, charges, etc)
class ItemInst
{
public:
/////////////////////////
// Methods
/////////////////////////
// Constructors/Destructor
ItemInst(const Item_Struct* item = NULL, int16 charges = 0);
ItemInst(SharedDatabase *db, uint32 item_id, int16 charges = 0);
ItemInst(ItemUseType use_type) {
m_use_type = use_type;
m_item = NULL;
m_charges = 0;
m_price = 0;
m_instnodrop = false;
m_merchantslot = 0;
m_color = 0;
}
ItemInst(const ItemInst& copy);
virtual ~ItemInst();
// Query item type
virtual bool IsType(ItemClass item_class) const;
// Can item be stacked?
virtual bool IsStackable() const;
// Can item be equipped by/at?
virtual bool IsEquipable(uint16 race, uint16 class_) const;
virtual bool IsEquipable(int16 slot_id) const;
//
// Augements
//
inline bool IsAugmentable() const { return m_item->AugSlotType[0]!=0 || m_item->AugSlotType[1]!=0 || m_item->AugSlotType[2]!=0 || m_item->AugSlotType[3]!=0 || m_item->AugSlotType[4]!=0; }
bool AvailableWearSlot(uint32 aug_wear_slots) const;
int8 AvailableAugmentSlot(int32 augtype) const;
inline int32 GetAugmentType() const { return m_item->AugType; }
inline bool IsExpendable() const { return ((m_item->Click.Type == ET_Expendable ) || (m_item->ItemType == ItemTypePotion)); }
//
// Contents
//
ItemInst* GetItem(uint8 slot) const;
virtual uint32 GetItemID(uint8 slot) const;
inline const ItemInst* operator[](uint8 slot) const { return GetItem(slot); }
void PutItem(uint8 slot, const ItemInst& inst);
void PutItem(SharedDatabase *db, uint8 slot, uint32 item_id);
void DeleteItem(uint8 slot);
ItemInst* PopItem(uint8 index);
void Clear();
void ClearByFlags(byFlagSetting is_nodrop, byFlagSetting is_norent);
uint8 FirstOpenSlot() const;
uint8 GetTotalItemCount() const;
bool IsNoneEmptyContainer();
map<uint8, ItemInst*>* GetContents() { return &m_contents; }
//
// Augments
//
ItemInst* GetAugment(uint8 slot) const;
virtual uint32 GetAugmentItemID(uint8 slot) const;
void PutAugment(uint8 slot, const ItemInst& inst);
void PutAugment(SharedDatabase *db, uint8 slot, uint32 item_id);
void DeleteAugment(uint8 slot);
ItemInst* RemoveAugment(uint8 index);
bool IsAugmented();
// Has attack/delay?
virtual bool IsWeapon() const;
virtual bool IsAmmo() const;
// Accessors
const uint32 GetID() const { return m_item->ID; }
const uint32 GetItemScriptID() const { return m_item->ScriptFileID; }
virtual const Item_Struct* GetItem() const { return m_item; }
void SetItem(const Item_Struct* item) { m_item = item; }
int16 GetCharges() const { return m_charges; }
void SetCharges(int16 charges) { m_charges = charges; }
uint32 GetPrice() const { return m_price; }
void SetPrice(uint32 price) { m_price = price; }
void SetColor(uint32 color) { m_color = color; }
uint32 GetColor() const { return m_color; }
uint32 GetMerchantSlot() const { return m_merchantslot; }
void SetMerchantSlot(uint32 slot) { m_merchantslot = slot; }
int32 GetMerchantCount() const { return m_merchantcount; }
void SetMerchantCount(int32 count) { m_merchantcount = count; }
int16 GetCurrentSlot() const { return m_currentslot; }
void SetCurrentSlot(int16 curr_slot) { m_currentslot = curr_slot; }
// Is this item already attuned?
bool IsInstNoDrop() const { return m_instnodrop; }
void SetInstNoDrop(bool flag) { m_instnodrop=flag; }
std::string GetCustomDataString() const;
void SetCustomData(std::string identifier, std::string value);
void SetCustomData(std::string identifier, int value);
void SetCustomData(std::string identifier, float value);
void SetCustomData(std::string identifier, bool value);
std::string GetCustomData(std::string identifier);
void DeleteCustomData(std::string identifier);
// Allows treatment of this object as though it were a pointer to m_item
operator bool() const { return (m_item != NULL); }
// Compare inner Item_Struct of two ItemInst objects
bool operator==(const ItemInst& right) const { return (this->m_item == right.m_item); }
bool operator!=(const ItemInst& right) const { return (this->m_item != right.m_item); }
// Clone current item
virtual ItemInst* Clone() const;
bool IsSlotAllowed(int16 slot_id) const;
virtual bool IsScaling() const { return false; }
virtual bool IsEvolving() const { return false; }
string Serialize(int16 slot_id) const { InternalSerializedItem_Struct s; s.slot_id=slot_id; s.inst=(const void *)this; string ser; ser.assign((char *)&s,sizeof(InternalSerializedItem_Struct)); return ser; }
inline int32 GetSerialNumber() const { return m_SerialNumber; }
inline void SetSerialNumber(int32 id) { m_SerialNumber = id; }
protected:
//////////////////////////
// Protected Members
//////////////////////////
iter_contents _begin() { return m_contents.begin(); }
iter_contents _end() { return m_contents.end(); }
friend class Inventory;
void _PutItem(uint8 index, ItemInst* inst) { m_contents[index] = inst; }
ItemUseType m_use_type; // Usage type for item
const Item_Struct* m_item; // Ptr to item data
int16 m_charges; // # of charges for chargeable items
uint32 m_price; // Bazaar /trader price
uint32 m_color;
uint32 m_merchantslot;
int16 m_currentslot;
bool m_instnodrop;
int32 m_merchantcount; //number avaliable on the merchant, -1=unlimited
int32 m_SerialNumber; // Unique identifier for this instance of an item. Needed for Bazaar.
//
// Items inside of this item (augs or contents);
map<uint8, ItemInst*> m_contents; // Zero-based index: min=0, max=9
map<std::string, std::string> m_custom_data;
};
class EvoItemInst: public ItemInst {
public:
// constructor and destructor
EvoItemInst(const EvoItemInst& copy);
EvoItemInst(const ItemInst& copy);
EvoItemInst(const Item_Struct* item = NULL, int16 charges = 0);
~EvoItemInst();
// accessors... a lot of these are for evolving items (not complete yet)
bool IsScaling() const { return (m_evolveLvl == -1); }
bool IsEvolving() const { return (m_evolveLvl >= 1); }
uint32 GetExp() const { return m_exp; }
void SetExp(uint32 exp) { m_exp = exp; }
void AddExp(uint32 exp) { m_exp += exp; }
bool IsActivated() { return m_activated; }
void SetActivated(bool activated) { m_activated = activated; }
int8 GetEvolveLvl() const { return m_evolveLvl; }
EvoItemInst* Clone() const;
const Item_Struct* GetItem() const;
const Item_Struct* GetUnscaledItem() const;
void Initialize(SharedDatabase *db = NULL);
void ScaleItem();
bool EvolveOnAllKills() const;
int8 GetMaxEvolveLvl() const;
uint32 GetKillsNeeded(uint8 currentlevel);
private:
uint32 m_exp;
int8 m_evolveLvl;
bool m_activated;
Item_Struct* m_scaledItem;
const EvolveInfo* m_evolveInfo;
};
class EvolveInfo {
public:
friend class EvoItemInst;
//temporary
uint16 LvlKills[9];
uint32 FirstItem;
uint8 MaxLvl;
bool AllKills;
EvolveInfo();
EvolveInfo(uint32 first, uint8 max, bool allkills, uint32 L2, uint32 L3, uint32 L4, uint32 L5, uint32 L6, uint32 L7, uint32 L8, uint32 L9, uint32 L10);
~EvolveInfo();
};
#endif // #define __ITEM_H

1901
common/MaxSkill.cpp Normal file

File diff suppressed because it is too large Load Diff

650
common/MiscFunctions.cpp Normal file
View File

@ -0,0 +1,650 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "../common/debug.h"
#include "MiscFunctions.h"
#include <string.h>
#include <time.h>
#include <math.h>
#ifndef WIN32
#include <netinet/in.h>
#include <sys/socket.h>
#endif
#include <iostream>
#include <iomanip>
#ifdef _WINDOWS
#include <io.h>
#endif
#include "../common/timer.h"
#include "../common/seperator.h"
using namespace std;
#ifdef _WINDOWS
#include <windows.h>
#define snprintf _snprintf
#if (_MSC_VER < 1500)
#define vsnprintf _vsnprintf
#endif
#define strncasecmp _strnicmp
#define strcasecmp _stricmp
#else
#include <stdlib.h>
#include <ctype.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/time.h>
#ifdef FREEBSD //Timothy Whitman - January 7, 2003
#include <sys/socket.h>
#include <netinet/in.h>
#endif
#include <sys/stat.h>
#include <unistd.h>
#include <netdb.h>
#include <errno.h>
#endif
#ifndef va_copy
#define va_copy(d,s) ((d) = (s))
#endif
static bool WELLRNG_init = false;
static int state_i = 0;
static unsigned int STATE[R];
static unsigned int z0, z1, z2;
unsigned int (*WELLRNG19937)(void);
static unsigned int case_1 (void);
static unsigned int case_2 (void);
static unsigned int case_3 (void);
static unsigned int case_4 (void);
static unsigned int case_5 (void);
static unsigned int case_6 (void);
uint32 rnd_hash(time_t t, clock_t c);
void oneseed(const uint32 seed);
void CoutTimestamp(bool ms) {
time_t rawtime;
struct tm* gmt_t;
time(&rawtime);
gmt_t = gmtime(&rawtime);
struct timeval read_time;
gettimeofday(&read_time,0);
cout << (gmt_t->tm_year + 1900) << "/" << setw(2) << setfill('0') << (gmt_t->tm_mon + 1) << "/" << setw(2) << setfill('0') << gmt_t->tm_mday << " " << setw(2) << setfill('0') << gmt_t->tm_hour << ":" << setw(2) << setfill('0') << gmt_t->tm_min << ":" << setw(2) << setfill('0') << gmt_t->tm_sec;
if (ms)
cout << "." << setw(3) << setfill('0') << (read_time.tv_usec / 1000);
cout << " GMT";
}
// normal strncpy doesnt put a null term on copied strings, this one does
// ref: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcecrt/htm/_wcecrt_strncpy_wcsncpy.asp
char* strn0cpy(char* dest, const char* source, uint32 size) {
if (!dest)
return 0;
if (size == 0 || source == 0) {
dest[0] = 0;
return dest;
}
strncpy(dest, source, size);
dest[size - 1] = 0;
return dest;
}
// String N w/null Copy Truncated?
// return value =true if entire string(source) fit, false if it was truncated
bool strn0cpyt(char* dest, const char* source, uint32 size) {
if (!dest)
return 0;
if (size == 0 || source == 0) {
dest[0] = 0;
return false;
}
strncpy(dest, source, size);
dest[size - 1] = 0;
return (bool) (source[strlen(dest)] == 0);
}
const char *MakeUpperString(const char *source) {
static char str[128];
if (!source)
return NULL;
MakeUpperString(source, str);
return str;
}
void MakeUpperString(const char *source, char *target) {
if (!source || !target) {
*target=0;
return;
}
while (*source)
{
*target = toupper(*source);
target++;source++;
}
*target = 0;
}
const char *MakeLowerString(const char *source) {
static char str[128];
if (!source)
return NULL;
MakeLowerString(source, str);
return str;
}
void MakeLowerString(const char *source, char *target) {
if (!source || !target) {
*target=0;
return;
}
while (*source)
{
*target = tolower(*source);
target++;source++;
}
*target = 0;
}
int MakeAnyLenString(char** ret, const char* format, ...) {
int buf_len = 128;
int chars = -1;
va_list argptr, tmpargptr;
va_start(argptr, format);
while (chars == -1 || chars >= buf_len) {
safe_delete_array(*ret);
if (chars == -1)
buf_len *= 2;
else
buf_len = chars + 1;
*ret = new char[buf_len];
va_copy(tmpargptr, argptr);
chars = vsnprintf(*ret, buf_len, format, tmpargptr);
}
va_end(argptr);
return chars;
}
uint32 AppendAnyLenString(char** ret, uint32* bufsize, uint32* strlen, const char* format, ...) {
if (*bufsize == 0)
*bufsize = 256;
if (*ret == 0)
*strlen = 0;
int chars = -1;
char* oldret = 0;
va_list argptr, tmpargptr;
va_start(argptr, format);
while (chars == -1 || chars >= (int32)(*bufsize-*strlen)) {
if (chars == -1)
*bufsize += 256;
else
*bufsize += chars + 25;
oldret = *ret;
*ret = new char[*bufsize];
if (oldret) {
if (*strlen)
memcpy(*ret, oldret, *strlen);
safe_delete_array(oldret);
}
va_copy(tmpargptr, argptr);
chars = vsnprintf(&(*ret)[*strlen], (*bufsize-*strlen), format, tmpargptr);
}
va_end(argptr);
*strlen += chars;
return *strlen;
}
uint32 hextoi(char* num) {
int len = strlen(num);
if (len < 3)
return 0;
if (num[0] != '0' || (num[1] != 'x' && num[1] != 'X'))
return 0;
uint32 ret = 0;
int mul = 1;
for (int i=len-1; i>=2; i--) {
if (num[i] >= 'A' && num[i] <= 'F')
ret += ((num[i] - 'A') + 10) * mul;
else if (num[i] >= 'a' && num[i] <= 'f')
ret += ((num[i] - 'a') + 10) * mul;
else if (num[i] >= '0' && num[i] <= '9')
ret += (num[i] - '0') * mul;
else
return 0;
mul *= 16;
}
return ret;
}
uint64 hextoi64(char* num) {
int len = strlen(num);
if (len < 3)
return 0;
if (num[0] != '0' || (num[1] != 'x' && num[1] != 'X'))
return 0;
uint64 ret = 0;
int mul = 1;
for (int i=len-1; i>=2; i--) {
if (num[i] >= 'A' && num[i] <= 'F')
ret += ((num[i] - 'A') + 10) * mul;
else if (num[i] >= 'a' && num[i] <= 'f')
ret += ((num[i] - 'a') + 10) * mul;
else if (num[i] >= '0' && num[i] <= '9')
ret += (num[i] - '0') * mul;
else
return 0;
mul *= 16;
}
return ret;
}
bool atobool(char* iBool) {
if (!strcasecmp(iBool, "true"))
return true;
if (!strcasecmp(iBool, "false"))
return false;
if (!strcasecmp(iBool, "yes"))
return true;
if (!strcasecmp(iBool, "no"))
return false;
if (!strcasecmp(iBool, "on"))
return true;
if (!strcasecmp(iBool, "off"))
return false;
if (!strcasecmp(iBool, "enable"))
return true;
if (!strcasecmp(iBool, "disable"))
return false;
if (!strcasecmp(iBool, "enabled"))
return true;
if (!strcasecmp(iBool, "disabled"))
return false;
if (!strcasecmp(iBool, "y"))
return true;
if (!strcasecmp(iBool, "n"))
return false;
if (atoi(iBool))
return true;
return false;
}
int32 filesize(FILE* fp) {
#ifdef _WINDOWS
return _filelength(_fileno(fp));
#else
struct stat file_stat;
fstat(fileno(fp), &file_stat);
return (int32) file_stat.st_size;
/* uint32 tmp = 0;
while (!feof(fp)) {
fseek(fp, tmp++, SEEK_SET);
}
return tmp;*/
#endif
}
uint32 ResolveIP(const char* hostname, char* errbuf) {
#ifdef _WINDOWS
static InitWinsock ws;
#endif
if (errbuf)
errbuf[0] = 0;
if (hostname == 0) {
if (errbuf)
snprintf(errbuf, ERRBUF_SIZE, "ResolveIP(): hostname == 0");
return 0;
}
struct sockaddr_in server_sin;
#ifdef _WINDOWS
PHOSTENT phostent = NULL;
#else
struct hostent *phostent = NULL;
#endif
server_sin.sin_family = AF_INET;
if ((phostent = gethostbyname(hostname)) == NULL) {
#ifdef _WINDOWS
if (errbuf)
snprintf(errbuf, ERRBUF_SIZE, "Unable to get the host name. Error: %i", WSAGetLastError());
#else
if (errbuf)
snprintf(errbuf, ERRBUF_SIZE, "Unable to get the host name. Error: %s", strerror(errno));
#endif
return 0;
}
#ifdef _WINDOWS
memcpy ((char FAR *)&(server_sin.sin_addr), phostent->h_addr, phostent->h_length);
#else
memcpy ((char*)&(server_sin.sin_addr), phostent->h_addr, phostent->h_length);
#endif
return server_sin.sin_addr.s_addr;
}
bool ParseAddress(const char* iAddress, uint32* oIP, uint16* oPort, char* errbuf) {
Seperator sep(iAddress, ':', 2, 250, false, 0, 0);
if (sep.argnum == 1 && sep.IsNumber(1)) {
*oIP = ResolveIP(sep.arg[0], errbuf);
if (*oIP == 0)
return false;
if (oPort)
*oPort = atoi(sep.arg[1]);
return true;
}
return false;
}
#ifdef _WINDOWS
InitWinsock::InitWinsock() {
WORD version = MAKEWORD (1,1);
WSADATA wsadata;
WSAStartup (version, &wsadata);
}
InitWinsock::~InitWinsock() {
WSACleanup();
}
#endif
const char * itoa(int num) {
static char temp[_ITOA_BUFLEN];
memset(temp,0,_ITOA_BUFLEN);
snprintf(temp,_ITOA_BUFLEN,"%d",num);
return temp;
}
#ifndef WIN32
const char * itoa(int num, char* a,int b) {
static char temp[_ITOA_BUFLEN];
memset(temp,0,_ITOA_BUFLEN);
snprintf(temp,_ITOA_BUFLEN,"%d",num);
return temp;
return temp;
}
#endif
/*
* generate a random integer in the range low-high this
* should be used instead of the rand()%limit method
*/
int MakeRandomInt(int low, int high)
{
_CP(MakeRandomInt);
if(low >= high)
return(low);
//return (rand()%(high-low+1) + (low));
if(!WELLRNG_init) {
WELLRNG_init = true;
oneseed( rnd_hash( time(NULL), clock() ) );
WELLRNG19937 = case_1;
}
unsigned int randomnum = ((WELLRNG19937)());
if(randomnum == 0xffffffffUL)
return high;
return int ((randomnum / (double)0xffffffffUL) * (high - low + 1) + low);
}
double MakeRandomFloat(double low, double high)
{
_CP(MakeRandomFloat);
if(low >= high)
return(low);
//return (rand() / (double)RAND_MAX * (high - low) + low);
if(!WELLRNG_init) {
WELLRNG_init = true;
oneseed( rnd_hash( time(NULL), clock() ) );
WELLRNG19937 = case_1;
}
return ((WELLRNG19937)() / (double)0xffffffffUL * (high - low) + low);
}
uint32 rnd_hash( time_t t, clock_t c )
{
// Get a uint32 from t and c
// Better than uint32(x) in case x is floating point in [0,1]
// Based on code by Lawrence Kirby (fred@genesis.demon.co.uk)
static uint32 differ = 0; // guarantee time-based seeds will change
uint32 h1 = 0;
unsigned char *p = (unsigned char *) &t;
for( size_t i = 0; i < sizeof(t); ++i )
{
h1 *= 255 + 2U;
h1 += p[i];
}
uint32 h2 = 0;
p = (unsigned char *) &c;
for( size_t j = 0; j < sizeof(c); ++j )
{
h2 *= 255 + 2U;
h2 += p[j];
}
return ( h1 + differ++ ) ^ h2;
}
void oneseed( const uint32 seed )
{
// Initialize generator state with seed
// See Knuth TAOCP Vol 2, 3rd Ed, p.106 for multiplier.
// In previous versions, most significant bits (MSBs) of the seed affect
// only MSBs of the state array. Modified 9 Jan 2002 by Makoto Matsumoto.
register int j = 0;
STATE[j] = seed & 0xffffffffUL;
for (j = 1; j < R; j++)
{
STATE[j] = ( 1812433253UL * ( STATE[j-1] ^ (STATE[j-1] >> 30) ) + j ) & 0xffffffffUL;
}
}
// WELL RNG code
/* ***************************************************************************** */
/* Copyright: Francois Panneton and Pierre L'Ecuyer, University of Montreal */
/* Makoto Matsumoto, Hiroshima University */
/* Notice: This code can be used freely for personal, academic, */
/* or non-commercial purposes. For commercial purposes, */
/* please contact P. L'Ecuyer at: lecuyer@iro.UMontreal.ca */
/* A modified "maximally equidistributed" implementation */
/* by Shin Harase, Hiroshima University. */
/* ***************************************************************************** */
unsigned int case_1 (void){
// state_i == 0
z0 = (VRm1Under & MASKL) | (VRm2Under & MASKU);
z1 = MAT0NEG (-25, V0) ^ MAT0POS (27, VM1);
z2 = MAT3POS (9, VM2) ^ MAT0POS (1, VM3);
newV1 = z1 ^ z2;
newV0Under = MAT1 (z0) ^ MAT0NEG (-9, z1) ^ MAT0NEG (-21, z2) ^ MAT0POS (21, newV1);
state_i = R - 1;
WELLRNG19937 = case_3;
return (STATE[state_i] ^ (newVM2Over & BITMASK));
}
static unsigned int case_2 (void){
// state_i == 1
z0 = (VRm1 & MASKL) | (VRm2Under & MASKU);
z1 = MAT0NEG (-25, V0) ^ MAT0POS (27, VM1);
z2 = MAT3POS (9, VM2) ^ MAT0POS (1, VM3);
newV1 = z1 ^ z2;
newV0 = MAT1 (z0) ^ MAT0NEG (-9, z1) ^ MAT0NEG (-21, z2) ^ MAT0POS (21, newV1);
state_i = 0;
WELLRNG19937 = case_1;
return (STATE[state_i] ^ (newVM2 & BITMASK));
}
static unsigned int case_3 (void){
// state_i+M1 >= R
z0 = (VRm1 & MASKL) | (VRm2 & MASKU);
z1 = MAT0NEG (-25, V0) ^ MAT0POS (27, VM1Over);
z2 = MAT3POS (9, VM2Over) ^ MAT0POS (1, VM3Over);
newV1 = z1 ^ z2;
newV0 = MAT1 (z0) ^ MAT0NEG (-9, z1) ^ MAT0NEG (-21, z2) ^ MAT0POS (21, newV1);
state_i--;
if (state_i + M1 < R)
WELLRNG19937 = case_5;
return (STATE[state_i] ^ (newVM2Over & BITMASK));
}
static unsigned int case_4 (void){
// state_i+M3 >= R
z0 = (VRm1 & MASKL) | (VRm2 & MASKU);
z1 = MAT0NEG (-25, V0) ^ MAT0POS (27, VM1);
z2 = MAT3POS (9, VM2) ^ MAT0POS (1, VM3Over);
newV1 = z1 ^ z2;
newV0 = MAT1 (z0) ^ MAT0NEG (-9, z1) ^ MAT0NEG (-21, z2) ^ MAT0POS (21, newV1);
state_i--;
if (state_i + M3 < R)
WELLRNG19937 = case_6;
return (STATE[state_i] ^ (newVM2 & BITMASK));
}
static unsigned int case_5 (void){
// state_i+M2 >= R
z0 = (VRm1 & MASKL) | (VRm2 & MASKU);
z1 = MAT0NEG (-25, V0) ^ MAT0POS (27, VM1);
z2 = MAT3POS (9, VM2Over) ^ MAT0POS (1, VM3Over);
newV1 = z1 ^ z2;
newV0 = MAT1 (z0) ^ MAT0NEG (-9, z1) ^ MAT0NEG (-21, z2) ^ MAT0POS (21, newV1);
state_i--;
if (state_i + M2 < R)
WELLRNG19937 = case_4;
return (STATE[state_i] ^ (newVM2Over & BITMASK));
}
static unsigned int case_6 (void){
// 2 <= state_i <= (R - M3 - 1)
z0 = (VRm1 & MASKL) | (VRm2 & MASKU);
z1 = MAT0NEG (-25, V0) ^ MAT0POS (27, VM1);
z2 = MAT3POS (9, VM2) ^ MAT0POS (1, VM3);
newV1 = z1 ^ z2;
newV0 = MAT1 (z0) ^ MAT0NEG (-9, z1) ^ MAT0NEG (-21, z2) ^ MAT0POS (21, newV1);
state_i--;
if (state_i == 1)
WELLRNG19937 = case_2;
return (STATE[state_i] ^ (newVM2 & BITMASK));
}
// end WELL RNG code
// solar: removes the crap and turns the underscores into spaces.
char *CleanMobName(const char *in, char *out)
{
unsigned i, j;
for(i = j = 0; i < strlen(in); i++)
{
// convert _ to space.. any other conversions like this? I *think* this
// is the only non alpha char that's not stripped but converted.
if(in[i] == '_')
{
out[j++] = ' ';
}
else
{
if(isalpha(in[i]) || (in[i] == '`')) // numbers, #, or any other crap just gets skipped
out[j++] = in[i];
}
}
out[j] = 0; // terimnate the string before returning it
return out;
}
const char *ConvertArray(int input, char *returnchar)
{
sprintf(returnchar, "%i" ,input);
return returnchar;
}
const char *ConvertArrayF(float input, char *returnchar)
{
sprintf(returnchar, "%0.2f", input);
return returnchar;
}
float EQ13toFloat(int d)
{
return ( float(d)/float(1<<2));
}
float NewEQ13toFloat(int d)
{
return ( float(d)/float(1<<6));
}
float EQ19toFloat(int d)
{
return ( float(d)/float(1<<3));
}
int FloatToEQ13(float d)
{
return int(d*float(1<<2));
}
int NewFloatToEQ13(float d)
{
return int(d*float(1<<6));
}
int FloatToEQ19(float d)
{
return int(d*float(1<<3));
}
/*
Heading of 0 points in the pure positive Y direction
*/
int FloatToEQH(float d)
{
return(int((360.0f - d) * float(1<<11)) / 360);
}
float EQHtoFloat(int d)
{
return(360.0f - float((d * 360) >> 11));
}
void RemoveApostrophes(std::string &s)
{
for(unsigned int i = 0; i < s.length(); ++i)
if(s[i] == '\'')
s[i] = '_';
}
char *RemoveApostrophes(const char *s)
{
char *NewString = new char[strlen(s) + 1];
strcpy(NewString, s);
for(unsigned int i = 0 ; i < strlen(NewString); ++i)
if(NewString[i] == '\'')
NewString[i] = '_';
return NewString;
}

171
common/MiscFunctions.h Normal file
View File

@ -0,0 +1,171 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef MISCFUNCTIONS_H
#define MISCFUNCTIONS_H
#include "types.h"
#include <stdio.h>
#include <ctype.h>
#include <string>
#include <time.h>
#ifndef ERRBUF_SIZE
#define ERRBUF_SIZE 1024
#endif
// These are helper macros for dealing with packets of variable length, typically those that contain
// variable length strings where it is not convenient to use a fixed length struct.
//
#define VARSTRUCT_DECODE_TYPE(Type, Buffer) *(Type *)Buffer; Buffer += sizeof(Type);
#define VARSTRUCT_DECODE_STRING(String, Buffer) strcpy(String, Buffer); Buffer += strlen(String)+1;
#define VARSTRUCT_ENCODE_STRING(Buffer, String) { sprintf(Buffer, String); Buffer += strlen(String) + 1; }
#define VARSTRUCT_ENCODE_INTSTRING(Buffer, Number) { sprintf(Buffer, "%i", Number); Buffer += strlen(Buffer) + 1; }
#define VARSTRUCT_ENCODE_TYPE(Type, Buffer, Value) { *(Type *)Buffer = Value; Buffer += sizeof(Type); }
#define VARSTRUCT_SKIP_TYPE(Type, Buffer) Buffer += sizeof(Type);
#define VERIFY_PACKET_LENGTH(OPCode, Packet, StructName) \
if(Packet->size != sizeof(StructName)) \
{ \
LogFile->write(EQEMuLog::Debug, "Size mismatch in " #OPCode " expected %i got %i", sizeof(StructName), Packet->size); \
DumpPacket(Packet); \
return; \
}
// Definitions for WELLRNG
//
#define W 32
#define R 624
#define DISCARD 31
#define MASKU (0xffffffffU>>(W-DISCARD))
#define MASKL (~MASKU)
#define M1 70
#define M2 179
#define M3 449
#define MAT0POS(t,v) (v^(v>>t))
#define MAT0NEG(t,v) (v^(v<<(-(t))))
#define MAT1(v) v
#define MAT3POS(t,v) (v>>t)
#define V0 STATE[state_i]
#define VM1Over STATE[state_i+M1-R]
#define VM1 STATE[state_i+M1]
#define VM2Over STATE[state_i+M2-R]
#define VM2 STATE[state_i+M2]
#define VM3Over STATE[state_i+M3-R]
#define VM3 STATE[state_i+M3]
#define VRm1 STATE[state_i-1]
#define VRm1Under STATE[state_i+R-1]
#define VRm2 STATE[state_i-2]
#define VRm2Under STATE[state_i+R-2]
#define newV0 STATE[state_i-1]
#define newV0Under STATE[state_i-1+R]
#define newV1 STATE[state_i]
#define newVRm1 STATE[state_i-2]
#define newVRm1Under STATE[state_i-2+R]
#define newVM2Over STATE[state_i+M2-R+1]
#define newVM2 STATE[state_i+M2+1]
#define BITMASK 0x41180000
//////////////////////////////////////////////////////////////////////
//
// MakeUpperString
// i : source - allocated null-terminated string
// return: pointer to static buffer with the target string
const char *MakeUpperString(const char *source);
const char *MakeLowerString(const char *source);
//////////////////////////////////////////////////////////////////////
//
// MakeUpperString
// i : source - allocated null-terminated string
// io: target - allocated buffer, at least of size strlen(source)+1
void MakeUpperString(const char *source, char *target);
void MakeLowerString(const char *source, char *target);
int MakeAnyLenString(char** ret, const char* format, ...);
uint32 AppendAnyLenString(char** ret, uint32* bufsize, uint32* strlen, const char* format, ...);
uint32 hextoi(char* num);
uint64 hextoi64(char* num);
bool atobool(char* iBool);
int32 filesize(FILE* fp);
uint32 ResolveIP(const char* hostname, char* errbuf = 0);
bool ParseAddress(const char* iAddress, uint32* oIP, uint16* oPort, char* errbuf = 0);
void CoutTimestamp(bool ms = true);
char* strn0cpy(char* dest, const char* source, uint32 size);
// return value =true if entire string(source) fit, false if it was truncated
bool strn0cpyt(char* dest, const char* source, uint32 size);
int MakeRandomInt(int low, int high);
double MakeRandomFloat(double low, double high);
char *CleanMobName(const char *in, char *out);
const char *ConvertArray(int input, char *returnchar);
const char *ConvertArrayF(float input, char *returnchar);
float EQ13toFloat(int d);
float NewEQ13toFloat(int d);
float EQ19toFloat(int d);
float EQHtoFloat(int d);
int FloatToEQ13(float d);
int NewFloatToEQ13(float d);
int FloatToEQ19(float d);
int FloatToEQH(float d);
void RemoveApostrophes(std::string &s);
char *RemoveApostrophes(const char *s);
#define _ITOA_BUFLEN 25
const char *itoa(int num); //not thread safe
#ifndef _WINDOWS
const char *itoa(int num, char* a,int b);
#endif
class InitWinsock {
public:
InitWinsock();
~InitWinsock();
};
template<class T> class AutoDelete {
public:
AutoDelete(T** iVar, T* iSetTo = 0) {
init(iVar, iSetTo);
}
AutoDelete() { pVar = NULL; }
void init(T** iVar, T* iSetTo = 0)
{
pVar = iVar;
if (iSetTo)
*pVar = iSetTo;
}
~AutoDelete() {
if(pVar != NULL)
safe_delete(*pVar);
}
void ReallyClearIt() {
pVar = NULL;
}
private:
T** pVar;
};
#endif

285
common/Mutex.cpp Normal file
View File

@ -0,0 +1,285 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "../common/debug.h"
#include "../common/Mutex.h"
#include <iostream>
using namespace std;
#define DEBUG_MUTEX_CLASS 0
#if DEBUG_MUTEX_CLASS >= 1
#endif
#ifdef _WINDOWS
bool IsTryLockSupported();
bool TrylockSupported = IsTryLockSupported();
bool IsTryLockSupported() {
OSVERSIONINFOEX osvi;
BOOL bOsVersionInfoEx;
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
if( !(bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &osvi)) )
{
// If OSVERSIONINFOEX doesn't work, try OSVERSIONINFO.
osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
if (! GetVersionEx ( (OSVERSIONINFO *) &osvi) ) {
#if DEBUG_MUTEX_CLASS >= 1
cout << "Mutex::trylock() NOT supported" << endl;
#endif
return false;
}
}
// Tests for Windows NT product family.
if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT && osvi.dwMajorVersion >= 4) {
#if DEBUG_MUTEX_CLASS >= 1
cout << "Mutex::trylock() SUPPORTED" << endl;
#endif
return true;
}
else {
#if DEBUG_MUTEX_CLASS >= 1
cout << "Mutex::trylock() NOT supported" << endl;
#endif
return false;
}
}
#endif
Mutex::Mutex() {
#if DEBUG_MUTEX_CLASS >= 7
cout << "Constructing Mutex" << endl;
#endif
#ifdef _WINDOWS
InitializeCriticalSection(&CSMutex);
#else
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
#if defined(__CYGWIN__) || defined(__APPLE__)
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
#else
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
#endif
pthread_mutex_init(&CSMutex, &attr);
pthread_mutexattr_destroy(&attr);
#endif
}
Mutex::~Mutex() {
#if DEBUG_MUTEX_CLASS >= 7
cout << "Deconstructing Mutex" << endl;
#endif
#ifdef _WINDOWS
DeleteCriticalSection(&CSMutex);
#else
// pthread_mutex_destroy(&CSMutex);
#endif
}
void Mutex::lock() {
_CP(Mutex_lock);
#if DEBUG_MUTEX_CLASS >= 9
cout << "Locking Mutex" << endl;
#endif
#if DEBUG_MUTEX_CLASS >= 5
if (!trylock()) {
cout << "Locking Mutex: Having to wait" << endl;
#ifdef _WINDOWS
EnterCriticalSection(&CSMutex);
#else
pthread_mutex_lock(&CSMutex);
#endif
}
#else
#ifdef _WINDOWS
EnterCriticalSection(&CSMutex);
#else
pthread_mutex_lock(&CSMutex);
#endif
#endif
}
bool Mutex::trylock() {
#if DEBUG_MUTEX_CLASS >= 9
cout << "TryLocking Mutex" << endl;
#endif
#ifdef _WINDOWS
#if(_WIN32_WINNT >= 0x0400)
if (TrylockSupported)
return TryEnterCriticalSection(&CSMutex);
else {
EnterCriticalSection(&CSMutex);
return true;
}
#else
EnterCriticalSection(&CSMutex);
return true;
#endif
#else
return (pthread_mutex_trylock(&CSMutex) == 0);
#endif
}
void Mutex::unlock() {
#if DEBUG_MUTEX_CLASS >= 9
cout << "Unlocking Mutex" << endl;
#endif
#ifdef _WINDOWS
LeaveCriticalSection(&CSMutex);
#else
pthread_mutex_unlock(&CSMutex);
#endif
}
LockMutex::LockMutex(Mutex* in_mut, bool iLock) {
mut = in_mut;
locked = iLock;
if (locked) {
mut->lock();
}
}
LockMutex::~LockMutex() {
if (locked) {
mut->unlock();
}
}
void LockMutex::unlock() {
if (locked)
mut->unlock();
locked = false;
}
void LockMutex::lock() {
if (!locked)
mut->lock();
locked = true;
}
MRMutex::MRMutex() {
rl = 0;
wr = 0;
rl = 0;
}
MRMutex::~MRMutex() {
#ifdef _EQDEBUG
if (wl || rl) {
cout << "MRMutex::~MRMutex: poor cleanup detected: rl=" << rl << ", wl=" << wl << endl;
}
#endif
}
void MRMutex::ReadLock() {
while (!TryReadLock()) {
Sleep(1);
}
}
bool MRMutex::TryReadLock() {
MCounters.lock();
if (!wr && !wl) {
rl++;
MCounters.unlock();
return true;
}
else {
MCounters.unlock();
return false;
}
}
void MRMutex::UnReadLock() {
MCounters.lock();
rl--;
#ifdef _EQDEBUG
if (rl < 0) {
ThrowError("rl < 0 in MRMutex::UnReadLock()");
}
#endif
MCounters.unlock();
}
void MRMutex::WriteLock() {
MCounters.lock();
if (!rl && !wl) {
wl++;
MCounters.unlock();
return;
}
else {
wr++;
MCounters.unlock();
while (1) {
Sleep(1);
MCounters.lock();
if (!rl && !wl) {
wr--;
MCounters.unlock();
return;
}
MCounters.lock();
}
}
}
bool MRMutex::TryWriteLock() {
MCounters.lock();
if (!rl && !wl) {
wl++;
MCounters.unlock();
return true;
}
else {
MCounters.unlock();
return false;
}
}
void MRMutex::UnWriteLock() {
MCounters.lock();
wl--;
#ifdef _EQDEBUG
if (wl < 0) {
ThrowError("wl < 0 in MRMutex::UnWriteLock()");
}
#endif
MCounters.unlock();
}
int32 MRMutex::ReadLockCount() {
MCounters.lock();
int32 ret = rl;
MCounters.unlock();
return ret;
}
int32 MRMutex::WriteLockCount() {
MCounters.lock();
int32 ret = wl;
MCounters.unlock();
return ret;
}

83
common/Mutex.h Normal file
View File

@ -0,0 +1,83 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef MYMUTEX_H
#define MYMUTEX_H
#ifdef _WINDOWS
#include <winsock.h>
#include <windows.h>
#else
#include <pthread.h>
#include "../common/unix.h"
#endif
#include "../common/types.h"
class Mutex {
public:
Mutex();
~Mutex();
void lock();
void unlock();
bool trylock();
protected:
private:
#if defined WIN32 || defined WIN64
CRITICAL_SECTION CSMutex;
#else
pthread_mutex_t CSMutex;
#endif
};
class LockMutex {
public:
LockMutex(Mutex* in_mut, bool iLock = true);
~LockMutex();
void unlock();
void lock();
private:
bool locked;
Mutex* mut;
};
// Somewhat untested...
// Multi-read, single write mutex -Quagmire
class MRMutex {
public:
MRMutex();
~MRMutex();
void ReadLock();
bool TryReadLock();
void UnReadLock();
void WriteLock();
bool TryWriteLock();
void UnWriteLock();
int32 ReadLockCount();
int32 WriteLockCount();
private:
int32 rl; // read locks in effect
int32 wr; // write lock requests pending
int32 wl; // write locks in effect (should never be more than 1)
Mutex MCounters;
};
#endif

368
common/ProcLauncher.cpp Normal file
View File

@ -0,0 +1,368 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "debug.h"
#include "ProcLauncher.h"
#ifdef _WINDOWS
#include <windows.h>
#else
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#endif
using namespace std;
ProcLauncher ProcLauncher::s_launcher;
#ifdef _WINDOWS
const ProcLauncher::ProcRef ProcLauncher::ProcError = 0xFFFFFFFF;
#else
const ProcLauncher::ProcRef ProcLauncher::ProcError = -1;
#endif
ProcLauncher::ProcLauncher()
{
#ifndef WIN32
if(signal(SIGCHLD, ProcLauncher::HandleSigChild) == SIG_ERR)
fprintf(stderr, "Unable to register child signal handler. Thats bad.");
m_signalCount = 0;
#endif
}
void ProcLauncher::Process() {
#ifdef _WINDOWS
map<ProcRef, Spec *>::iterator cur, end, tmp;
cur = m_running.begin();
end = m_running.end();
while(cur != end) {
DWORD res;
if(GetExitCodeProcess(cur->second->proc_info.hProcess, &res)) {
//got exit code, see if its still running...
if(res == STILL_ACTIVE) {
cur++;
continue;
}
//else, it died, handle properly
} else {
//not sure the right thing to do here... why would this fail?
//GetLastError();
TerminateProcess(cur->second->proc_info.hProcess, 1);
}
//if we get here, the current process died.
tmp = cur;
tmp++;
ProcessTerminated(cur);
cur = tmp;
}
#else //!WIN32
while(m_signalCount > 0) {
m_signalCount--;
int status;
ProcRef died = waitpid(-1, &status, WNOHANG);
if(died == -1) {
//error waiting... shouldent really happen...
} else if(died == 0) {
//nothing pending...
break;
} else {
//one died...
map<ProcRef, Spec *>::iterator ref;
ref = m_running.find(died);
if(ref == m_running.end()) {
//unable to find this process in our list...
} else {
//found... hooray
ProcessTerminated(ref);
}
}
}
#endif //!WIN32
}
void ProcLauncher::ProcessTerminated(std::map<ProcRef, Spec *>::iterator &it) {
if(it->second->handler != NULL)
it->second->handler->OnTerminate(it->first, it->second);
#ifdef _WINDOWS
CloseHandle(it->second->proc_info.hProcess);
#else //!WIN32
#endif //!WIN32
delete it->second;
m_running.erase(it);
}
ProcLauncher::ProcRef ProcLauncher::Launch(Spec *&to_launch) {
//consume the pointer
Spec *it = to_launch;
to_launch = NULL;
#ifdef _WINDOWS
STARTUPINFO siStartInfo;
BOOL bFuncRetn = FALSE;
// Set up members of the PROCESS_INFORMATION structure.
ZeroMemory( &it->proc_info, sizeof(PROCESS_INFORMATION) );
// Set up members of the STARTUPINFO structure.
ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.dwFlags = 0;
//handle output redirection.
HANDLE logOut = NULL;
BOOL inherit_handles = FALSE;
if(it->logFile.length() > 0) {
inherit_handles = TRUE;
// Set up our log file to redirect output into.
SECURITY_ATTRIBUTES saAttr;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE; //we want this handle to be inherited by the child.
saAttr.lpSecurityDescriptor = NULL;
logOut = CreateFile(
it->logFile.c_str(), //lpFileName
FILE_WRITE_DATA, //dwDesiredAccess
FILE_SHARE_READ, //dwShareMode
&saAttr, //lpSecurityAttributes
CREATE_ALWAYS, //dwCreationDisposition
FILE_FLAG_NO_BUFFERING, //dwFlagsAndAttributes
NULL ); //hTemplateFile
//configure the startup info to redirect output appropriately.
siStartInfo.hStdError = logOut;
siStartInfo.hStdOutput = logOut;
siStartInfo.hStdInput = NULL;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
}
siStartInfo.dwFlags |= CREATE_NEW_CONSOLE;
// Create the child process.
//glue together all the nice command line arguments
string args(it->program);
vector<string>::iterator cur, end;
cur = it->args.begin();
end = it->args.end();
for(; cur != end; cur++) {
args += " ";
args += *cur;
}
bFuncRetn = CreateProcess(it->program.c_str(),
const_cast<char *>(args.c_str()), // command line
NULL, // process security attributes
NULL, // primary thread security attributes
inherit_handles, // handles are not inherited
0, // creation flags (CREATE_NEW_PROCESS_GROUP maybe)
NULL, // use parent's environment
NULL, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&it->proc_info); // receives PROCESS_INFORMATION
if (bFuncRetn == 0) {
safe_delete(it);
//GetLastError()
return(ProcError);
}
//keep process handle open to get exit code
CloseHandle(it->proc_info.hThread); //we dont need their thread handle
if(logOut != NULL)
CloseHandle(logOut); //we dont want their output handle either.
ProcRef res = it->proc_info.dwProcessId;
//record this entry..
m_running[res] = it;
return(res);
#else //!WIN32
//build argv
char **argv = new char *[it->args.size()+2];
unsigned int r;
argv[0] = const_cast<char *>(it->program.c_str());
for(r = 1; r <= it->args.size(); r++) {
argv[r] = const_cast<char *>(it->args[r-1].c_str());
}
argv[r] = NULL;
ProcRef res = fork(); //cant use vfork since we are opening the log file.
if(res == -1) {
//error forking... errno
safe_delete(it);
safe_delete_array(argv);
return(ProcError);
}
if(res == 0) {
//child... exec this bitch
//handle output redirection if requested.
if(it->logFile.length() > 0) {
//we will put their output directly into a file.
int outfd = creat(it->logFile.c_str(), S_IRUSR | S_IWUSR | S_IRGRP); // S_I + R/W/X + USR/GRP/OTH
if(outfd == -1) {
fprintf(stderr, "Unable to open log file %s: %s.\n", it->logFile.c_str(), strerror(errno));
close(STDOUT_FILENO);
close(STDERR_FILENO);
close(STDIN_FILENO);
} else {
close(STDOUT_FILENO);
if(dup2(outfd, STDOUT_FILENO) == -1) {
fprintf(stderr, "Unable to duplicate FD %d to %d. Log file will be empty: %s\n", outfd, STDOUT_FILENO, strerror(errno));
const char *err = "Unable to redirect stdout into this file. That sucks.";
write(outfd, err, strlen(err));
}
close(STDERR_FILENO);
if(dup2(outfd, STDERR_FILENO) == -1) {
//can no longer print to screen..
const char *err = "Unable to redirect stderr into this file. You might miss some error info in this log.";
write(outfd, err, strlen(err));
}
close(STDIN_FILENO);
close(outfd); //dont need this one, we have two more copies...
}
}
//call it...
execv(argv[0], argv);
_exit(1);
}
safe_delete_array(argv);
//record this entry..
m_running[res] = it;
return(res);
#endif //!WIN32
}
//if graceful is true, we try to be nice about it if possible
bool ProcLauncher::Terminate(const ProcRef &proc, bool graceful) {
//we are only willing to kill things we started...
std::map<ProcRef, Spec *>::iterator res = m_running.find(proc);
if(res == m_running.end())
return(false);
//we do not remove it from the list until we have been notified
//that they have been terminated.
#ifdef _WINDOWS
if(!TerminateProcess(res->second->proc_info.hProcess, 0)) {
return(false);
}
#else //!WIN32
int sig;
if(graceful)
sig = SIGTERM;
else
sig = SIGKILL;
if(kill(proc, sig) == -1) {
return(false);
}
#endif //!WIN32
return(true);
}
void ProcLauncher::TerminateAll(bool final) {
if(!final) {
//send a nice terminate to each process, with intention of waiting for them
std::map<ProcRef, Spec *>::iterator cur, end;
cur = m_running.begin();
end = m_running.end();
for(; cur != end; cur++) {
Terminate(cur->first, true);
}
} else {
//kill each process and remove it from the list
std::map<ProcRef, Spec *> running(m_running);
m_running.clear();
std::map<ProcRef, Spec *>::iterator cur, end;
cur = running.begin();
end = running.end();
for(; cur != end; cur++) {
Terminate(cur->first, true);
safe_delete(cur->second);
}
}
}
#ifndef WIN32
void ProcLauncher::HandleSigChild(int signum) {
if(signum == SIGCHLD) {
ProcLauncher::get()->m_signalCount++;
}
}
#endif
ProcLauncher::Spec::Spec() {
handler = NULL;
}
ProcLauncher::Spec::Spec(const Spec &other) {
program = other.program;
args = other.args;
handler = other.handler;
logFile = other.logFile;
}
ProcLauncher::Spec &ProcLauncher::Spec::operator=(const Spec &other) {
program = other.program;
args = other.args;
handler = other.handler;
logFile = other.logFile;
return(*this);
}

124
common/ProcLauncher.h Normal file
View File

@ -0,0 +1,124 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef PROCLAUNCHER_H_
#define PROCLAUNCHER_H_
#include "debug.h"
#include <string>
#include <vector>
#include <map>
//I forced this object to become a singleton because it registers its
//signal handler for UNIX
class ProcLauncher {
ProcLauncher();
public:
//Singleton method
static ProcLauncher *get() { return(&s_launcher); }
static void ProcessInThisThread();
#ifdef WIN32
typedef DWORD ProcRef;
static const ProcRef ProcError;
#else
typedef pid_t ProcRef;
static const ProcRef ProcError;
#endif
class EventHandler;
class Spec {
friend class ProcLauncher; //for visual c++
public:
Spec();
Spec(const Spec &other);
Spec &operator=(const Spec &other);
std::string program;
std::vector<std::string> args;
//std::map<std::string,std::string> environment;
EventHandler *handler; //optional, we do not own this pointer
std::string logFile; //empty = do not redirect output.
protected:
//None of these fields get copied around
#ifdef WIN32
PROCESS_INFORMATION proc_info;
#endif
};
class EventHandler {
public:
virtual ~EventHandler() {}
virtual void OnTerminate(const ProcRef &ref, const Spec *spec) = 0;
};
/*
* The main launch method, call to start a new background process.
*/
ProcRef Launch(Spec *&to_launch); //takes ownership of the pointer
/*
* The terminate method
*/
bool Terminate(const ProcRef &proc, bool graceful = true);
void TerminateAll(bool final = true);
/*
* The main processing method. Call regularly to check for terminated
* background processes.
*/
void Process();
protected:
// std::vector<Spec *> m_specs;
std::map<ProcRef, Spec *> m_running; //we own the pointers in this map
void ProcessTerminated(std::map<ProcRef, Spec *>::iterator &it);
private:
static ProcLauncher s_launcher;
#ifndef WIN32
uint32 m_signalCount;
static void HandleSigChild(int signum);
#endif
};
#endif /*PROCLAUNCHER_H_*/

117
common/SharedLibrary.cpp Normal file
View File

@ -0,0 +1,117 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "SharedLibrary.h"
#include <stdio.h>
#ifdef _WINDOWS
#define snprintf _snprintf
#if (_MSC_VER < 1500)
#define vsnprintf _vsnprintf
#endif
#define strncasecmp _strnicmp
#define strcasecmp _stricmp
#define EmuLibName "EMuShareMem"
#else
#define EmuLibName "libEMuShareMem.so"
#include "../common/unix.h"
#include <dlfcn.h>
#define GetProcAddress(a,b) dlsym(a,b)
#define LoadLibrary(a) dlopen(a, RTLD_NOW)
#define FreeLibrary(a) dlclose(a)
#define GetLastError() dlerror()
#endif
SharedLibrary::SharedLibrary() {
hDLL = NULL;
}
SharedLibrary::~SharedLibrary() {
Unload();
}
bool SharedLibrary::Load(const char *name)
{
#ifdef _WINDOWS
SetLastError(0);
#endif
hDLL = LoadLibrary(name);
if(!hDLL) {
const char *load_error = GetError();
fprintf(stderr, "[Error] Load Shared Library '%s' failed. Error=%s\n", name, load_error?load_error:"Null Return, no error");
return false;
}
#ifdef _WINDOWS
else { SetLastError(0); } // Clear the win9x error
#endif
return(true);
}
void SharedLibrary::Unload() {
if (hDLL != NULL) {
FreeLibrary(hDLL);
#ifndef WIN32
const char* error;
if ((error = GetError()) != NULL)
fprintf(stderr, "FreeLibrary() error = %s", error);
#endif
hDLL = NULL;
}
}
void *SharedLibrary::GetSym(const char *name) {
if (!Loaded())
return(NULL);
void *r = GetProcAddress(hDLL, name);
if(GetError() != NULL)
r = NULL;
return(r);
}
bool SharedLibrary::GetSym(const char *name, void **sym)
{
bool result=false;
if (Loaded()) {
*sym = GetProcAddress(hDLL, name);
result= (GetError() == NULL);
}
return result;
}
const char *SharedLibrary::GetError()
{
#ifdef _WINDOWS
//not thread safe, dont care.
static char ErrBuf[128];
unsigned long err = GetLastError();
if(err == 0)
return(NULL);
sprintf(ErrBuf, "Error #%lu", (unsigned long)err);
return(ErrBuf);
#else
return GetLastError();
#endif
}

49
common/SharedLibrary.h Normal file
View File

@ -0,0 +1,49 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _SHAREDLIBRARY_H
#define _SHAREDLIBRARY_H
#ifdef _WINDOWS
#include <windows.h>
#endif
class SharedLibrary {
public:
SharedLibrary();
virtual ~SharedLibrary();
//two call styles for GetSym, one returns bool, other NULL for fail
bool GetSym(const char *name, void **sym);
void *GetSym(const char *name);
const char *GetError();
virtual bool Load(const char *file);
virtual void Unload();
inline bool Loaded() { return (hDLL != 0); }
protected:
#ifdef _WINDOWS
HINSTANCE hDLL;
#else
void* hDLL;
#endif
};
#endif

266
common/SocketLib/Base64.cpp Normal file
View File

@ -0,0 +1,266 @@
/** \file Base64.cpp
** \date 2004-02-13
** \author grymse@alhem.net
**/
/*
Copyright (C) 2004,2005 Anders Hedstrom
This library is made available under the terms of the GNU GPL.
If you would like to use this library in a closed-source application,
a separate license agreement is available. For information about
the closed-source license agreement for the C++ sockets library,
please visit http://www.alhem.net/Sockets/license.html and/or
email license@alhem.net.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "Base64.h"
#ifdef SOCKETS_NAMESPACE
namespace SOCKETS_NAMESPACE {
#endif
const char *Base64::bstr =
"ABCDEFGHIJKLMNOPQ"
"RSTUVWXYZabcdefgh"
"ijklmnopqrstuvwxy"
"z0123456789+/";
const char Base64::rstr[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0,
0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0,
0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0};
void Base64::encode(FILE *fil, std::string& output, bool add_crlf)
{
size_t remain;
size_t i = 0;
size_t o = 0;
char input[4];
output = "";
remain = fread(input,1,3,fil);
while (remain > 0)
{
if (add_crlf && o && o % 76 == 0)
output += "\n";
switch (remain)
{
case 1:
output += bstr[ ((input[i] >> 2) & 0x3f) ];
output += bstr[ ((input[i] << 4) & 0x30) ];
output += "==";
break;
case 2:
output += bstr[ ((input[i] >> 2) & 0x3f) ];
output += bstr[ ((input[i] << 4) & 0x30) + ((input[i + 1] >> 4) & 0x0f) ];
output += bstr[ ((input[i + 1] << 2) & 0x3c) ];
output += "=";
break;
default:
output += bstr[ ((input[i] >> 2) & 0x3f) ];
output += bstr[ ((input[i] << 4) & 0x30) + ((input[i + 1] >> 4) & 0x0f) ];
output += bstr[ ((input[i + 1] << 2) & 0x3c) + ((input[i + 2] >> 6) & 0x03) ];
output += bstr[ (input[i + 2] & 0x3f) ];
}
o += 4;
//
remain = fread(input,1,3,fil);
}
}
void Base64::encode(const std::string& str_in, std::string& str_out, bool add_crlf)
{
encode(str_in.c_str(), str_in.size(), str_out, add_crlf);
}
void Base64::encode(const char* input,size_t l,std::string& output, bool add_crlf)
{
size_t i = 0;
size_t o = 0;
output = "";
while (i < l)
{
size_t remain = l - i;
if (add_crlf && o && o % 76 == 0)
output += "\n";
switch (remain)
{
case 1:
output += bstr[ ((input[i] >> 2) & 0x3f) ];
output += bstr[ ((input[i] << 4) & 0x30) ];
output += "==";
break;
case 2:
output += bstr[ ((input[i] >> 2) & 0x3f) ];
output += bstr[ ((input[i] << 4) & 0x30) + ((input[i + 1] >> 4) & 0x0f) ];
output += bstr[ ((input[i + 1] << 2) & 0x3c) ];
output += "=";
break;
default:
output += bstr[ ((input[i] >> 2) & 0x3f) ];
output += bstr[ ((input[i] << 4) & 0x30) + ((input[i + 1] >> 4) & 0x0f) ];
output += bstr[ ((input[i + 1] << 2) & 0x3c) + ((input[i + 2] >> 6) & 0x03) ];
output += bstr[ (input[i + 2] & 0x3f) ];
}
o += 4;
i += 3;
}
}
void Base64::encode(unsigned char* input,size_t l,std::string& output,bool add_crlf)
{
size_t i = 0;
size_t o = 0;
output = "";
while (i < l)
{
size_t remain = l - i;
if (add_crlf && o && o % 76 == 0)
output += "\n";
switch (remain)
{
case 1:
output += bstr[ ((input[i] >> 2) & 0x3f) ];
output += bstr[ ((input[i] << 4) & 0x30) ];
output += "==";
break;
case 2:
output += bstr[ ((input[i] >> 2) & 0x3f) ];
output += bstr[ ((input[i] << 4) & 0x30) + ((input[i + 1] >> 4) & 0x0f) ];
output += bstr[ ((input[i + 1] << 2) & 0x3c) ];
output += "=";
break;
default:
output += bstr[ ((input[i] >> 2) & 0x3f) ];
output += bstr[ ((input[i] << 4) & 0x30) + ((input[i + 1] >> 4) & 0x0f) ];
output += bstr[ ((input[i + 1] << 2) & 0x3c) + ((input[i + 2] >> 6) & 0x03) ];
output += bstr[ (input[i + 2] & 0x3f) ];
}
o += 4;
i += 3;
}
}
void Base64::decode(const std::string& input,std::string& output)
{
size_t i = 0;
size_t l = input.size();
output = "";
while (i < l)
{
while (i < l && (input[i] == 13 || input[i] == 10))
i++;
if (i < l)
{
char b1 = (char)((rstr[(int)input[i]] << 2 & 0xfc) +
(rstr[(int)input[i + 1]] >> 4 & 0x03));
output += b1;
if (input[i + 2] != '=')
{
char b2 = (char)((rstr[(int)input[i + 1]] << 4 & 0xf0) +
(rstr[(int)input[i + 2]] >> 2 & 0x0f));
output += b2;
}
if (input[i + 3] != '=')
{
char b3 = (char)((rstr[(int)input[i + 2]] << 6 & 0xc0) +
rstr[(int)input[i + 3]]);
output += b3;
}
i += 4;
}
}
}
void Base64::decode(const std::string& input, unsigned char *output, size_t& sz)
{
size_t i = 0;
size_t l = input.size();
size_t j = 0;
while (i < l)
{
while (i < l && (input[i] == 13 || input[i] == 10))
i++;
if (i < l)
{
unsigned char b1 = (unsigned char)((rstr[(int)input[i]] << 2 & 0xfc) +
(rstr[(int)input[i + 1]] >> 4 & 0x03));
if (output)
{
output[j] = b1;
}
j++;
if (input[i + 2] != '=')
{
unsigned char b2 = (unsigned char)((rstr[(int)input[i + 1]] << 4 & 0xf0) +
(rstr[(int)input[i + 2]] >> 2 & 0x0f));
if (output)
{
output[j] = b2;
}
j++;
}
if (input[i + 3] != '=')
{
unsigned char b3 = (unsigned char)((rstr[(int)input[i + 2]] << 6 & 0xc0) +
rstr[(int)input[i + 3]]);
if (output)
{
output[j] = b3;
}
j++;
}
i += 4;
}
}
sz = j;
}
size_t Base64::decode_length(const std::string& str64)
{
if (!str64.size() || str64.size() % 4)
return 0;
size_t l = 3 * (str64.size() / 4 - 1) + 1;
if (str64[str64.size() - 2] != '=')
l++;
if (str64[str64.size() - 1] != '=')
l++;
return l;
}
#ifdef SOCKETS_NAMESPACE
}
#endif

67
common/SocketLib/Base64.h Normal file
View File

@ -0,0 +1,67 @@
/** \file Base64.h
** \date 2004-02-13
** \author grymse@alhem.net
**/
/*
Copyright (C) 2004,2005 Anders Hedstrom
This library is made available under the terms of the GNU GPL.
If you would like to use this library in a closed-source application,
a separate license agreement is available. For information about
the closed-source license agreement for the C++ sockets library,
please visit http://www.alhem.net/Sockets/license.html and/or
email license@alhem.net.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _BASE64_H
#define _BASE64_H
#include <stdio.h>
#include <string>
#ifdef SOCKETS_NAMESPACE
namespace SOCKETS_NAMESPACE {
#endif
/** \defgroup util Utilities */
/** Base64 encode/decode.
\ingroup util */
class Base64 {
public:
static void encode(FILE *, std::string& , bool add_crlf = true);
static void encode(const std::string&, std::string& , bool add_crlf = true);
static void encode(const char *, size_t, std::string& , bool add_crlf = true);
static void encode(unsigned char *, size_t, std::string& , bool add_crlf = true);
static void decode(const std::string&, std::string& );
static void decode(const std::string& in, unsigned char *out, size_t&);
static size_t decode_length(const std::string& );
private:
static const char *bstr;
static const char rstr[128];
};
#ifdef SOCKETS_NAMESPACE
}
#endif
#endif // _BASE64_H

126
common/SocketLib/File.cpp Normal file
View File

@ -0,0 +1,126 @@
/** \file File.cpp
** \date 2005-04-25
** \author grymse@alhem.net
**/
/*
Copyright (C) 2004,2005 Anders Hedstrom
This library is made available under the terms of the GNU GPL.
If you would like to use this library in a closed-source application,
a separate license agreement is available. For information about
the closed-source license agreement for the C++ sockets library,
please visit http://www.alhem.net/Sockets/license.html and/or
email license@alhem.net.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifndef _WIN32
#include <unistd.h>
#endif
#include "File.h"
#ifdef SOCKETS_NAMESPACE
namespace SOCKETS_NAMESPACE {
#endif
File::File()
:m_fil(NULL)
{
}
File::~File()
{
}
bool File::fopen(const std::string& path, const std::string& mode)
{
m_path = path;
m_mode = mode;
m_fil = ::fopen(path.c_str(), mode.c_str());
return m_fil ? true : false;
}
void File::fclose()
{
if (m_fil)
::fclose(m_fil);
}
size_t File::fread(char *ptr, size_t size, size_t nmemb)
{
return m_fil ? ::fread(ptr, size, nmemb, m_fil) : 0;
}
size_t File::fwrite(const char *ptr, size_t size, size_t nmemb)
{
return m_fil ? ::fwrite(ptr, size, nmemb, m_fil) : 0;
}
char *File::fgets(char *s, int size)
{
return m_fil ? ::fgets(s, size, m_fil) : NULL;
}
void File::fprintf(char *format, ...)
{
va_list ap;
va_start(ap, format);
vfprintf(m_fil, format, ap);
va_end(ap);
}
off_t File::size()
{
struct stat st;
if (stat(m_path.c_str(), &st) == -1)
{
return 0;
}
return st.st_size;
}
bool File::eof()
{
if (m_fil)
{
if (feof(m_fil))
return true;
}
return false;
}
#ifdef SOCKETS_NAMESPACE
}
#endif

76
common/SocketLib/File.h Normal file
View File

@ -0,0 +1,76 @@
/** \file File.h
** \date 2005-04-25
** \author grymse@alhem.net
**/
/*
Copyright (C) 2004,2005 Anders Hedstrom
This library is made available under the terms of the GNU GPL.
If you would like to use this library in a closed-source application,
a separate license agreement is available. For information about
the closed-source license agreement for the C++ sockets library,
please visit http://www.alhem.net/Sockets/license.html and/or
email license@alhem.net.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _FILE_H
#define _FILE_H
#include "IFile.h"
#ifdef SOCKETS_NAMESPACE
namespace SOCKETS_NAMESPACE {
#endif
/** IFile implementation of a disk file.
\ingroup file */
class File : public IFile
{
public:
File();
~File();
bool fopen(const std::string&, const std::string&);
void fclose();
size_t fread(char *, size_t, size_t);
size_t fwrite(const char *, size_t, size_t);
char *fgets(char *, int);
void fprintf(char *format, ...);
off_t size();
bool eof();
private:
File(const File& ) {} // copy constructor
File& operator=(const File& ) { return *this; } // assignment operator
std::string m_path;
std::string m_mode;
FILE *m_fil;
};
#ifdef SOCKETS_NAMESPACE
}
#endif
#endif // _FILE_H

View File

@ -0,0 +1,366 @@
/* EQEMu: Everquest Server Emulator
*
* This code originated from `C++ Sockets Library` referenced below.
* Taken and stripped/modified to remove dependancies on parts of
* the library which we are not using, and to suit other needs.
* 2006 - EQEMu Development Team (http://eqemulator.net)
*
*
*/
/** \file HTTPSocket.cpp
** \date 2004-04-06
** \author grymse@alhem.net
**/
/*
Copyright (C) 2004,2005 Anders Hedstrom
This library is made available under the terms of the GNU GPL.
If you would like to use this library in a closed-source application,
a separate license agreement is available. For information about
the closed-source license agreement for the C++ sockets library,
please visit http://www.alhem.net/Sockets/license.html and/or
email license@alhem.net.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef _WIN32
#pragma warning(disable:4786)
#endif
#include "../debug.h"
#include <stdio.h>
#include <string>
#include <stdarg.h>
#include "Parse.h"
#include "HTTPSocket.h"
#include "../TCPConnection.h"
#include <cstdlib>
#include <cstring>
#ifdef SOCKETS_NAMESPACE
namespace SOCKETS_NAMESPACE {
#endif
HTTPSocket::HTTPSocket(uint32 ID, SOCKET in_socket, uint32 irIP, uint16 irPort)
:TCPConnection(ID,in_socket,irIP,irPort)
,m_first(true)
,m_header(true)
,m_http_version("HTTP/1.0")
,m_request(false)
,m_response(false)
{
}
HTTPSocket::~HTTPSocket()
{
}
/*
* eqemu stuff
*/
bool HTTPSocket::ProcessReceivedData(char *errbuf)
{
if (errbuf)
errbuf[0] = 0;
if (!recvbuf)
return true;
char *buff=(char *)recvbuf;
unsigned long bufflen=recvbuf_used;
while(1) {
if (m_header) {
char *ptr=(char *)memchr(buff,'\n',bufflen);
if (!ptr)
break;
int length=(ptr-buff)+1;
std::string line;
line.append(buff,length-2);
OnLine(line);
buff+=length;
bufflen-=length;
} else {
OnData(buff,bufflen);
buff+=bufflen;
bufflen=0;
break;
}
}
if (bufflen) {
memmove(recvbuf,buff,bufflen);
recvbuf_used=bufflen;
} else {
safe_delete_array(recvbuf);
}
}
bool HTTPSocket::SendString(const char *str) {
return(TCPConnection::Send((const uchar *) str, strlen(str)));
}
bool HTTPSocket::SendBuf(const char *dat, unsigned int len) {
return(TCPConnection::Send((const uchar *) dat, len));
}
/*
* /eqemu stuff
*/
void HTTPSocket::OnLine(const std::string& line)
{
if (m_first)
{
Parse pa(line);
std::string str = pa.getword();
if (str.substr(0,4) == "HTTP") // response
{
m_http_version = str;
m_status = pa.getword();
m_status_text = pa.getrest();
m_response = true;
}
else // request
{
m_method = str;
m_url = pa.getword();
size_t spl = m_url.find("?");
if (spl != std::string::npos)
{
m_uri = m_url.substr(0,spl);
m_query_string = m_url.substr(spl + 1);
}
else
{
m_uri = m_url;
}
m_http_version = pa.getword();
m_request = true;
}
m_first = false;
OnFirst();
return;
}
if (!line.size())
{
// SetLineProtocol(false);
m_header = false;
OnHeaderComplete();
return;
}
Parse pa(line,":");
std::string key = pa.getword();
std::string value = pa.getrest();
OnHeader(key,value);
/* If remote end tells us to keep connection alive, and we're operating
in http/1.1 mode (not http/1.0 mode), then we mark the socket to be
retained. */
/* if (!strcasecmp(key.c_str(), "connection") &&
!strcasecmp(value.c_str(), "keep-alive") )
{
SetRetain();
}*/
}
void HTTPSocket::SendResponse()
{
std::string msg;
msg = m_http_version + " " + m_status + " " + m_status_text + "\r\n";
for (string_m::iterator it = m_response_header.begin(); it != m_response_header.end(); it++)
{
std::string key = (*it).first;
std::string val = (*it).second;
msg += key + ": " + val + "\r\n";
}
msg += "\r\n";
SendString( msg.c_str() );
}
void HTTPSocket::AddResponseHeader(const std::string& header, const char *format, ...)
{
static char slask[5000];
va_list ap;
va_start(ap, format);
#ifdef _WIN32
vsprintf(slask, format, ap);
#else
vsnprintf(slask, 5000, format, ap);
#endif
va_end(ap);
m_response_header[header] = slask;
}
void HTTPSocket::SendRequest()
{
std::string msg;
msg = m_method + " " + m_url + " " + m_http_version + "\r\n";
for (string_m::iterator it = m_response_header.begin(); it != m_response_header.end(); it++)
{
std::string key = (*it).first;
std::string val = (*it).second;
msg += key + ": " + val + "\r\n";
}
msg += "\r\n";
SendString( msg.c_str() );
}
std::string HTTPSocket::MyUseragent()
{
std::string version = "C++Sockets/";
#ifdef _VERSION
version += _VERSION;
#endif
return version;
}
void HTTPSocket::Reset()
{
m_first = true;
m_header = true;
m_request = false;
m_response = false;
// SetLineProtocol(true);
while (m_response_header.size())
{
string_m::iterator it = m_response_header.begin();
m_response_header.erase(it);
}
}
const std::string& HTTPSocket::GetMethod()
{
return m_method;
}
void HTTPSocket::SetMethod(const std::string& x)
{
m_method = x;
}
const std::string& HTTPSocket::GetUrl()
{
return m_url;
}
void HTTPSocket::SetUrl(const std::string& x)
{
m_url = x;
}
const std::string& HTTPSocket::GetUri()
{
return m_uri;
}
const std::string& HTTPSocket::GetQueryString()
{
return m_query_string;
}
const std::string& HTTPSocket::GetHttpVersion()
{
return m_http_version;
}
const std::string& HTTPSocket::GetStatus()
{
return m_status;
}
const std::string& HTTPSocket::GetStatusText()
{
return m_status_text;
}
bool HTTPSocket::IsRequest()
{
return m_request;
}
bool HTTPSocket::IsResponse()
{
return m_response;
}
void HTTPSocket::SetHttpVersion(const std::string& x)
{
m_http_version = x;
}
void HTTPSocket::SetStatus(const std::string& num, const std::string& text) {
m_status = num;
m_status_text = text;
}
void HTTPSocket::SetStatus(const std::string& x)
{
m_status = x;
}
void HTTPSocket::SetStatusText(const std::string& x)
{
m_status_text = x;
}
void HTTPSocket::AddResponseHeader(const std::string& x,const std::string& y)
{
m_response_header[x] = y;
}
void HTTPSocket::SetUri(const std::string& x)
{
m_uri = x;
}
void HTTPSocket::SendResponse(const std::string& status_num, const std::string& status_text) {
SetStatus(status_num, status_text);
SendResponse();
}
#ifdef SOCKETS_NAMESPACE
}
#endif

View File

@ -0,0 +1,137 @@
/* EQEMu: Everquest Server Emulator
*
* This code originated from `C++ Sockets Library` referenced below.
* Taken and stripped/modified to remove dependancies on parts of
* the library which we are not using, and to suit other needs.
* 2006 - EQEMu Development Team (http://eqemulator.net)
*
*
*/
/** \file HTTPSocket.h Class HTTPSocket definition.
** \date 2004-04-06
** \author grymse@alhem.net
**/
/*
Copyright (C) 2004,2005 Anders Hedstrom
This library is made available under the terms of the GNU GPL.
If you would like to use this library in a closed-source application,
a separate license agreement is available. For information about
the closed-source license agreement for the C++ sockets library,
please visit http://www.alhem.net/Sockets/license.html and/or
email license@alhem.net.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _HTTPSOCKET_H
#define _HTTPSOCKET_H
#include <map>
#include <string>
#include "../TCPConnection.h"
#ifdef SOCKETS_NAMESPACE
namespace SOCKETS_NAMESPACE {
#endif
/** \defgroup http HTTP Sockets */
/** HTTP request/response base class.
\ingroup http */
class HTTPSocket : public TCPConnection
{
/** map to hold http header values. */
typedef std::map<std::string,std::string> string_m;
public:
HTTPSocket(uint32 ID, SOCKET in_socket, uint32 irIP, uint16 irPort);
virtual ~HTTPSocket();
void OnLine(const std::string& line);
/** Callback executes when first line has been received.
GetMethod, GetUrl/GetUri, and GetHttpVersion are valid when this callback is executed. */
virtual void OnFirst() = 0;
/** For each header line this callback is executed.
\param key Http header name
\param value Http header value */
virtual void OnHeader(const std::string& key,const std::string& value) = 0;
/** Callback fires when all http headers have been received. */
virtual void OnHeaderComplete() = 0;
/** Chunk of http body data recevied. */
virtual void OnData(const char *,size_t) = 0;
const std::string& GetMethod();
void SetMethod(const std::string& x);
const std::string& GetUrl();
void SetUrl(const std::string& x);
const std::string& GetUri();
void SetUri(const std::string& x);
const std::string& GetQueryString();
const std::string& GetHttpVersion();
const std::string& GetStatus();
const std::string& GetStatusText();
bool IsRequest();
bool IsResponse();
void SetHttpVersion(const std::string& x);
void SetStatus(const std::string& x);
void SetStatus(const std::string& num, const std::string& text);
void SetStatusText(const std::string& x);
void AddResponseHeader(const std::string& x,const std::string& y);
void AddResponseHeader(const std::string& x,const char *format, ...);
void SendResponse();
void SendResponse(const std::string& status_num, const std::string& status_text);
void SendRequest();
/** Implement this to return your own User-agent string. */
virtual std::string MyUseragent();
protected:
/** Reset state of socket to sucessfully implement keep-alive. */
virtual void Reset();
//stubs for crap which used to be in our parent class (TcpSocket)
bool SendString(const char *str);
bool SendBuf(const char *dat, unsigned int len);
virtual bool ProcessReceivedData(char* errbuf = 0);
private:
// HTTPSocket& operator=(const HTTPSocket& ) { return *this; }
bool m_first;
bool m_header;
std::string m_line;
std::string m_method;
std::string m_url;
std::string m_uri;
std::string m_query_string;
std::string m_http_version;
std::string m_status;
std::string m_status_text;
bool m_request;
bool m_response;
string_m m_response_header;
};
#ifdef SOCKETS_NAMESPACE
}
#endif
#endif // _HTTPSOCKET_H

View File

@ -0,0 +1,250 @@
/** \file HttpdCookies.cpp
*/
/*
Copyright (C) 2003-2005 Anders Hedstrom
This library is made available under the terms of the GNU GPL.
If you would like to use this library in a closed-source application,
a separate license agreement is available. For information about
the closed-source license agreement for the C++ sockets library,
please visit http://www.alhem.net/Sockets/license.html and/or
email license@alhem.net.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "../debug.h"
#ifdef _WIN32
#pragma warning(disable:4786)
#endif
#include "Parse.h"
#include "Utility.h"
#include "HTTPSocket.h"
#include "HttpdCookies.h"
#include "../types.h"
#include <time.h>
#include <cstdlib>
#include <cstring>
#ifdef SOCKETS_NAMESPACE
namespace SOCKETS_NAMESPACE {
#endif
HttpdCookies::HttpdCookies()
{
}
HttpdCookies::HttpdCookies(const std::string& s)
{
Parse *pa = new Parse(s,";");
std::string slask = pa -> getword();
while (slask.size())
{
Parse *pa2 = new Parse(slask,"=");
std::string name = pa2 -> getword();
std::string value = pa2 -> getword();
delete pa2;
COOKIE *c = new COOKIE(name,value);
m_cookies.push_back(c);
//
slask = pa -> getword();
}
delete pa;
}
HttpdCookies::~HttpdCookies()
{
for (cookie_v::iterator it = m_cookies.begin(); it != m_cookies.end(); it++)
{
COOKIE *c = *it;
delete c;
}
}
bool HttpdCookies::getvalue(const std::string& name,std::string& buffer) //char *buffer,size_t length)
{
for (cookie_v::iterator it = m_cookies.begin(); it != m_cookies.end(); it++)
{
COOKIE *c = *it;
if (!strcasecmp(c -> name.c_str(),name.c_str()))
{
buffer = c -> value;
return true;
}
}
buffer = "";
return false;
}
void HttpdCookies::replacevalue(const std::string& name,const std::string& value)
{
COOKIE *c = NULL;
for (cookie_v::iterator it = m_cookies.begin(); it != m_cookies.end(); it++)
{
c = *it;
if (!strcasecmp(c -> name.c_str(),name.c_str()))
break;
c = NULL;
}
if (c)
{
c -> value = value;
}
else
{
c = new COOKIE(name,value);
m_cookies.push_back(c);
}
}
void HttpdCookies::replacevalue(const std::string& name,long l)
{
replacevalue(name, Utility::l2string(l));
}
void HttpdCookies::replacevalue(const std::string& name,int i)
{
replacevalue(name, Utility::l2string(i));
}
size_t HttpdCookies::getlength(const std::string& name)
{
COOKIE *c = NULL;
for (cookie_v::iterator it = m_cookies.begin(); it != m_cookies.end(); it++)
{
c = *it;
if (!strcasecmp(c -> name.c_str(),name.c_str()))
break;
c = NULL;
}
return c ? c -> value.size() : 0;
}
void HttpdCookies::setcookie(HTTPSocket *sock, const std::string& domain, const std::string& path, const std::string& name, const std::string& value)
{
char *str = new char[name.size() + value.size() + domain.size() + path.size() + 100];
// set-cookie response
if (domain.size())
{
sprintf(str, "%s=%s; domain=%s; path=%s; expires=%s",
name.c_str(), value.c_str(),
domain.c_str(),
path.c_str(),
expiredatetime().c_str());
}
else
{
sprintf(str, "%s=%s; path=%s; expires=%s",
name.c_str(), value.c_str(),
path.c_str(),
expiredatetime().c_str());
}
sock -> AddResponseHeader("Set-cookie", str);
delete[] str;
replacevalue(name, value);
}
void HttpdCookies::setcookie(HTTPSocket *sock, const std::string& domain, const std::string& path, const std::string& name, long value)
{
char *str = new char[name.size() + domain.size() + path.size() + 100];
char dt[80];
// set-cookie response
if (domain.size())
{
sprintf(str, "%s=%ld; domain=%s; path=%s; expires=%s",
name.c_str(), value,
domain.c_str(),
path.c_str(),
expiredatetime().c_str());
}
else
{
sprintf(str, "%s=%ld; path=%s; expires=%s",
name.c_str(), value,
path.c_str(),
expiredatetime().c_str());
}
sock -> AddResponseHeader("Set-cookie", str);
delete[] str;
sprintf(dt, "%ld", value);
replacevalue(name, dt);
}
void HttpdCookies::setcookie(HTTPSocket *sock, const std::string& domain, const std::string& path, const std::string& name, int value)
{
char *str = new char[name.size() + domain.size() + path.size() + 100];
char dt[80];
// set-cookie response
if (domain.size())
{
sprintf(str, "%s=%d; domain=%s; path=%s; expires=%s",
name.c_str(), value,
domain.c_str(),
path.c_str(),
expiredatetime().c_str());
}
else
{
sprintf(str, "%s=%d; path=%s; expires=%s",
name.c_str(), value,
path.c_str(),
expiredatetime().c_str());
}
sock -> AddResponseHeader("Set-cookie", str);
delete[] str;
sprintf(dt, "%d", value);
replacevalue(name, dt);
}
const std::string& HttpdCookies::expiredatetime()
{
time_t t = time(NULL);
struct tm * tp = gmtime(&t);
const char *days[7] = {"Sunday", "Monday",
"Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
const char *months[12] = {"Jan", "Feb", "Mar", "Apr", "May",
"Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
char dt[100];
sprintf(dt, "%s, %02d-%s-%04d %02d:%02d:%02d GMT",
days[tp -> tm_wday],
tp -> tm_mday,
months[tp -> tm_mon],
tp -> tm_year + 1910,
tp -> tm_hour,
tp -> tm_min,
tp -> tm_sec);
m_date = dt;
return m_date;
}
#ifdef SOCKETS_NAMESPACE
}
#endif

View File

@ -0,0 +1,91 @@
/** \file HttpdCookies.h
*/
/*
Copyright (C) 2003-2005 Anders Hedstrom
This library is made available under the terms of the GNU GPL.
If you would like to use this library in a closed-source application,
a separate license agreement is available. For information about
the closed-source license agreement for the C++ sockets library,
please visit http://www.alhem.net/Sockets/license.html and/or
email license@alhem.net.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _COOKIES_H
#define _COOKIES_H
#include <list>
#include <string>
#ifdef SOCKETS_NAMESPACE
namespace SOCKETS_NAMESPACE {
#endif
//! Store the cookies name/value pairs.
//! Retrieve and manage cookies during a cgi call.
class HTTPSocket;
/** HTTP Cookie parse/container class.
\sa HttpdSocket
\sa HttpdForm
\ingroup webserver */
class HttpdCookies
{
/** Name/value pair store struct.
\ingroup webserver */
struct COOKIE
{
COOKIE(const std::string& n,const std::string& v) : name(n),value(v) {}
std::string name;
std::string value;
};
/** list of key/value structs. */
typedef std::list<COOKIE *> cookie_v;
public:
HttpdCookies();
HttpdCookies(const std::string& query_string);
~HttpdCookies();
// int getvalue(const std::string& ,char *,size_t); // (name, buffer, length)
bool getvalue(const std::string&,std::string&);
void replacevalue(const std::string& ,const std::string& );
void replacevalue(const std::string& ,long);
void replacevalue(const std::string& ,int);
size_t getlength(const std::string& );
void setcookie(HTTPSocket *,const std::string& d,const std::string& p,const std::string& c,const std::string& v);
void setcookie(HTTPSocket *,const std::string& d,const std::string& p,const std::string& c,long v);
void setcookie(HTTPSocket *,const std::string& d,const std::string& p,const std::string& c,int v);
const std::string& expiredatetime();
cookie_v& GetHttpdCookies() { return m_cookies; }
private:
cookie_v m_cookies;
std::string m_date;
};
#ifdef SOCKETS_NAMESPACE
}
#endif
#endif // _COOKIES_H

View File

@ -0,0 +1,621 @@
/** \file HttpdForm.cpp - read stdin, parse cgi input
**
** Written: 1999-Feb-10 grymse@alhem.net
**/
/*
Copyright (C) 1999-2005 Anders Hedstrom
This library is made available under the terms of the GNU GPL.
If you would like to use this library in a closed-source application,
a separate license agreement is available. For information about
the closed-source license agreement for the C++ sockets library,
please visit http://www.alhem.net/Sockets/license.html and/or
email license@alhem.net.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
#ifdef _WIN32
#pragma warning(disable:4786)
#include <windows.h>
#endif
#include "socket_include.h"
#include "Parse.h"
#include "IFile.h"
#include "HttpdForm.h"
#include <cstdlib>
#include <cstring>
#ifdef SOCKETS_NAMESPACE
namespace SOCKETS_NAMESPACE {
#endif
HttpdForm::HttpdForm(IFile *infil) : raw(false)
{
CGI *cgi = NULL;
char *c_t = getenv("CONTENT_TYPE");
char *c_l = getenv("CONTENT_LENGTH");
size_t extra = 2;
char name[200];
m_current = m_cgi.end();
*name = 0;
if (c_t && !strncmp(c_t, "multipart/form-data",19))
{
Parse pa(c_t,";=");
char *tempcmp = NULL;
size_t tc = 0;
size_t l = 0;
std::string str = pa.getword();
m_strBoundary = "";
while (str.size())
{
if (!strcmp(str.c_str(),"boundary"))
{
m_strBoundary = pa.getword();
l = m_strBoundary.size();
tempcmp = new char[l + extra];
}
//
str = pa.getword();
}
if (m_strBoundary.size())
{
std::string content_type;
std::string current_name;
std::string current_filename;
char slask[200];
infil -> fgets(slask, 200);
while (!infil -> eof())
{
while (strlen(slask) && (slask[strlen(slask) - 1] == 13 || slask[strlen(slask) - 1] == 10))
{
slask[strlen(slask) - 1] = 0;
}
content_type = "";
current_name = "";
current_filename = "";
if ((strstr(slask,m_strBoundary.c_str()) || strstr(m_strBoundary.c_str(),slask)) && strcmp(slask, m_strBoundary.c_str()))
{
m_strBoundary = slask;
l = m_strBoundary.size();
delete[] tempcmp;
tempcmp = new char[l + extra];
}
if (!strcmp(slask, m_strBoundary.c_str()))
{
// Get headers until empty line
infil -> fgets(slask, 200);
while (strlen(slask) && (slask[strlen(slask) - 1] == 13 || slask[strlen(slask) - 1] == 10))
{
slask[strlen(slask) - 1] = 0;
}
while (!infil -> eof() && *slask)
{
Parse pa(slask,";");
std::string h = pa.getword();
if (!strcasecmp(h.c_str(),"Content-type:"))
{
content_type = pa.getword();
}
else
if (!strcasecmp(h.c_str(),"Content-Disposition:"))
{
h = pa.getword();
if (!strcmp(h.c_str(),"form-data"))
{
pa.EnableQuote(true);
h = pa.getword();
while (h.size())
{
Parse pa2(slask,"=");
std::string name = pa2.getword();
std::string h = pa2.getrest();
if (!strcmp(name.c_str(),"name"))
{
if (h.size() && h[0] == '"')
{
current_name = h.substr(1, h.size() - 2);
}
else
{
current_name = h;
}
}
else
if (!strcmp(name.c_str(),"filename"))
{
if (h.size() && h[0] == '"')
{
current_filename = h.substr(1, h.size() - 2);
}
else
{
current_filename = h;
}
size_t x = 0;
for (size_t i = 0; i < current_filename.size(); i++)
{
if (current_filename[i] == '/' || current_filename[i] == '\\')
x = i + 1;
}
if (x)
{
current_filename = current_filename.substr(x);
}
}
h = pa.getword();
}
}
}
// get next header value
infil -> fgets(slask, 200);
while (strlen(slask) && (slask[strlen(slask) - 1] == 13 || slask[strlen(slask) - 1] == 10))
{
slask[strlen(slask) - 1] = 0;
}
}
// Read content, save...?
if (!current_filename.size()) // not a file
{
std::string val;
infil -> fgets(slask,1000);
while (!infil -> eof() && strncmp(slask,m_strBoundary.c_str(),m_strBoundary.size() ))
{
val += slask;
infil -> fgets(slask,1000);
}
// remove trailing cr/linefeed
while (val.size() && (val[val.size() - 1] == 13 || val[val.size() - 1] == 10))
{
val = val.substr(0,val.size() - 1);
}
cgi = new CGI(current_name, val);
m_cgi.push_back(cgi);
}
else // current_filename.size() > 0
{
// read until m_strBoundary...
FILE *fil;
int out = 0;
char c;
char fn[1000]; // where post'd file will be saved
#ifdef _WIN32
{
char tmp_path[1000];
::GetTempPath(1000, tmp_path);
if (tmp_path[strlen(tmp_path) - 1] != '\\')
{
strcat(tmp_path, "\\");
}
sprintf(fn,"%s%s",tmp_path,current_filename.c_str());
}
#else
sprintf(fn,"/tmp/%s",current_filename.c_str());
#endif
if ((fil = fopen(fn, "wb")) != NULL)
{
infil -> fread(&c,1,1);
while (!infil -> eof())
{
if (out)
{
fwrite(&tempcmp[tc],1,1,fil);
}
tempcmp[tc] = c;
tc++;
if (tc >= l + extra)
{
tc = 0;
out = 1;
}
if (tc)
{
if (!strncmp(tempcmp + tc + extra, m_strBoundary.c_str(), l - tc) &&
!strncmp(tempcmp, m_strBoundary.c_str() + l - tc, tc))
{
break;
}
}
else
{
if (!strncmp(tempcmp + extra, m_strBoundary.c_str(), l))
{
break;
}
}
infil -> fread(&c,1,1);
}
fclose(fil);
cgi = new CGI(current_name,fn,fn);
m_cgi.push_back(cgi);
strcpy(slask, m_strBoundary.c_str());
infil -> fgets(slask + strlen(slask), 200); // next line
}
else
{
// couldn't open file
break;
}
}
}
else
{
// Probably '<m_strBoundary>--'
break;
}
} // while (!infil -> eof())
} // if (m_strBoundary)
if (tempcmp)
{
delete[] tempcmp;
}
}
else
{
int i = 0;
int cl = c_l ? atoi(c_l) : -1;
char c,chigh,clow;
char *slask = new char[8888];
bool got_name = false;
m_current = m_cgi.end();
*name = 0;
infil -> fread(&c,1,1);
cl--;
while (cl >= 0)
{
switch (c)
{
case '=': /* end of name */
slask[i] = 0;
i = 0;
strcpy(name,slask);
got_name = true;
break;
case '&': /* end of value */
slask[i] = 0;
i = 0;
if(got_name) {
got_name = false;
cgi = new CGI(name,slask);
m_cgi.push_back(cgi);
} else {
cgi = new CGI(slask,"");
m_cgi.push_back(cgi);
}
break;
case '+': /* space */
slask[i++] = ' ';
break;
case '%': /* hex value */
infil -> fread(&chigh,1,1);
cl--;
chigh -= 48;
chigh &= 0xff - 32;
if (chigh > 9)
chigh -= 7;
infil -> fread(&clow,1,1);
cl--;
clow -= 48;
clow &= 0xff - 32;
if (clow > 9)
clow -= 7;
slask[i++] = (char)(chigh * 16 + clow);
break;
default: /* just another char */
slask[i++] = c;
break;
}
if(infil -> eof())
break;
//
if (cl > 0)
{
infil -> fread(&c,1,1);
}
cl--;
}
slask[i] = 0;
i = 0;
if(got_name) {
cgi = new CGI(name,slask);
m_cgi.push_back(cgi);
} else {
cgi = new CGI(slask,"");
m_cgi.push_back(cgi);
}
delete[] slask;
}
}
// HttpdForm(buffer,l) -- request_method GET
HttpdForm::HttpdForm(const std::string& buffer,size_t l) : raw(false)
{
CGI *cgi = NULL;
char slask[8888];
char name[200];
int i = 0;
char c,chigh,clow;
bool got_name = false;
size_t ptr = 0;
m_current = m_cgi.end();
*name = 0;
ptr = 0;
while (ptr < l)
{
c = buffer[ptr++];
switch (c)
{
case '=': /* end of name */
slask[i] = 0;
i = 0;
got_name = true;
strcpy(name,slask);
break;
case '&': /* end of value */
slask[i] = 0;
i = 0;
if(got_name) {
got_name = false;
cgi = new CGI(name,slask);
m_cgi.push_back(cgi);
} else {
cgi = new CGI(slask, "");
m_cgi.push_back(cgi);
}
break;
case '+': /* space */
slask[i++] = ' ';
break;
case '%': /* hex value */
chigh = buffer[ptr++];
chigh -= 48;
chigh &= 0xff - 32;
if (chigh > 9)
chigh -= 7;
clow = buffer[ptr++];
clow -= 48;
clow &= 0xff - 32;
if (clow > 9)
clow -= 7;
slask[i++] = (char)(chigh * 16 + clow);
break;
default: /* just another char */
slask[i++] = c;
break;
}
}
slask[i] = 0;
i = 0;
if(got_name) {
cgi = new CGI(name,slask);
m_cgi.push_back(cgi);
} else {
cgi = new CGI(slask, "");
m_cgi.push_back(cgi);
}
}
HttpdForm::~HttpdForm()
{
CGI *cgi = NULL; //,*tmp;
for (cgi_v::iterator it = m_cgi.begin(); it != m_cgi.end(); it++)
{
cgi = *it;
delete cgi;
}
}
void HttpdForm::EnableRaw(bool b)
{
raw = b;
}
void HttpdForm::strcpyval(std::string& v,const char *value) //,size_t len)
{
v = "";
for (size_t i = 0; i < strlen(value); i++)
{
if (value[i] == '<')
{
v += "&lt;";
}
else
if (value[i] == '>')
{
v += "&gt;";
}
else
if (value[i] == '&')
{
v += "&amp;";
}
else
{
v += value[i];
}
}
}
bool HttpdForm::getfirst(std::string& n) //char *n,size_t len)
{
m_current = m_cgi.begin();
return getnext(n);
}
bool HttpdForm::getnext(std::string& n) //char *n,size_t len)
{
if (m_current != m_cgi.end() )
{
CGI *current = *m_current;
n = current -> name;
m_current++;
return true;
}
else
{
n = "";
}
return false;
}
bool HttpdForm::getfirst(std::string& n,std::string& v) //char *n,size_t len,char *v,size_t vlen)
{
m_current = m_cgi.begin();
return getnext(n,v);
}
bool HttpdForm::getnext(std::string& n,std::string& v) //char *n,size_t len,char *v,size_t vlen)
{
if (m_current != m_cgi.end() )
{
CGI *current = *m_current;
n = current -> name;
if (raw)
{
v = current -> value;
}
else
{
strcpyval(v,current -> value.c_str());
}
m_current++;
return true;
}
else
{
n = "";
}
return false;
}
int HttpdForm::getvalue(const std::string& n,std::string& v) //char *v,size_t len)
{
CGI *cgi = NULL;
int r = 0;
for (cgi_v::iterator it = m_cgi.begin(); it != m_cgi.end(); it++)
{
cgi = *it;
if (cgi -> name == n)
break;
cgi = NULL;
}
if (cgi)
{
if (raw)
{
v = cgi -> value;
}
else
{
strcpyval(v,cgi -> value.c_str());
}
r++;
}
else
{
v = "";
}
return r;
}
std::string HttpdForm::getvalue(const std::string& n)
{
for (cgi_v::iterator it = m_cgi.begin(); it != m_cgi.end(); it++)
{
CGI *cgi = *it;
if (cgi -> name == n)
{
return cgi -> value;
}
}
return "";
}
size_t HttpdForm::getlength(const std::string& n)
{
CGI *cgi = NULL;
size_t l;
for (cgi_v::iterator it = m_cgi.begin(); it != m_cgi.end(); it++)
{
cgi = *it;
if (cgi -> name == n)
break;
cgi = NULL;
}
l = cgi ? cgi -> value.size() : 0;
if (cgi && !raw)
{
for (size_t i = 0; i < cgi -> value.size(); i++)
{
switch (cgi -> value[i])
{
case '<': // &lt;
case '>': // &gt;
l += 4;
break;
case '&': // &amp;
l += 5;
break;
}
}
}
return l;
}
HttpdForm::cgi_v& HttpdForm::getbase()
{
return m_cgi;
}
const std::string& HttpdForm::GetBoundary()
{
return m_strBoundary;
}
#ifdef SOCKETS_NAMESPACE
}
#endif

View File

@ -0,0 +1,115 @@
/** \file HttpdForm.h - read stdin, parse cgi input
**
** Written: 1999-Feb-10 grymse@alhem.net
**/
/*
Copyright (C) 1999-2005 Anders Hedstrom
This library is made available under the terms of the GNU GPL.
If you would like to use this library in a closed-source application,
a separate license agreement is available. For information about
the closed-source license agreement for the C++ sockets library,
please visit http://www.alhem.net/Sockets/license.html and/or
email license@alhem.net.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _FORM_H
#define _FORM_H
#include <string>
#include <list>
#ifdef SOCKETS_NAMESPACE
namespace SOCKETS_NAMESPACE {
#endif
class IFile;
/** Parse/store a http query_string/form-data body.
\ingroup webserver */
class HttpdForm
{
/**
* Store the name/value pairs from a GET/POST operation.
* "name" does not have to be unique.
\ingroup webserver
*/
struct CGI
{
CGI(const std::string& n,const std::string& v) : name(n),value(v) {}
CGI(const std::string& n,const std::string& v,const std::string& p) : name(n),value(v),path(p) {}
std::string name;
std::string value;
std::string path;
};
/** list of key/value pairs. */
typedef std::list<CGI *> cgi_v;
public:
/**
* Default constructor (used in POST operations).
* Input is read from stdin. Number of characters to read
* can be found in the environment variable CONTENT_LENGTH.
*/
HttpdForm(IFile *);
/**
* Another constructor (used in GET operations).
* Input is read from the environment variable QUERY_STRING.
* @param query_string The httpd server provided QUERY_STRING
* @param length Query string length.
*/
HttpdForm(const std::string& query_string,size_t length);
~HttpdForm();
void EnableRaw(bool);
void strcpyval(std::string&,const char *); //,size_t);
/* get names */
bool getfirst(std::string& n); //char *,size_t);
bool getnext(std::string& n); //char *,size_t);
/* get names and values */
bool getfirst(std::string& n,std::string& v); //char *,size_t,char *,size_t);
bool getnext(std::string& n,std::string& v); //char *,size_t,char *,size_t);
/* get value */
int getvalue(const std::string& ,std::string& ); //char *,size_t);
std::string getvalue(const std::string& );
size_t getlength(const std::string& );
cgi_v& getbase();
const std::string& GetBoundary();
private:
HttpdForm(const HttpdForm& ) {}
HttpdForm& operator=(const HttpdForm& ) { return *this; }
cgi_v m_cgi;
cgi_v::iterator m_current;
std::string m_strBoundary;
bool raw;
};
#ifdef SOCKETS_NAMESPACE
}
#endif
#endif // _FORM_H

View File

@ -0,0 +1,355 @@
/** \file HttpdSocket.cpp
*/
/*
Copyright (C) 2001-2004,2005 Anders Hedstrom (grymse@alhem.net)
This library is made available under the terms of the GNU GPL.
If you would like to use this library in a closed-source application,
a separate license agreement is available. For information about
the closed-source license agreement for the C++ sockets library,
please visit http://www.alhem.net/Sockets/license.html and/or
email license@alhem.net.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef _WIN32
#pragma warning(disable:4786)
#endif
#include "../debug.h"
#include "Utility.h"
#include "HttpdCookies.h"
#include "HttpdForm.h"
#include "MemFile.h"
#include "HttpdSocket.h"
#include "../types.h"
#include <time.h>
#include <stdio.h>
#include <cstdlib>
#include <cstring>
#define DEB(x)
/*
#define DEB(x) { \
FILE *fil = fopen("httpdlog","at"); \
if (!fil) \
fil = fopen("httpdlog","wt"); \
if (fil) { x; fclose(fil); } \
}
*/
#ifdef SOCKETS_NAMESPACE
namespace SOCKETS_NAMESPACE {
#endif
// statics
int HttpdSocket::m_request_count = 0;
std::string HttpdSocket::m_start = "";
HttpdSocket::HttpdSocket(uint32 ID, SOCKET in_socket, uint32 irIP, uint16 irPort)
: HTTPSocket(ID,in_socket,irIP,irPort)
,m_content_length(0)
,m_file(NULL)
,m_received(0)
,m_request_id(++m_request_count)
,m_cookies(NULL)
,m_form(NULL)
{
m_http_date = datetime2httpdate(GetDate());
if (!m_start.size())
m_start = m_http_date;
}
HttpdSocket::~HttpdSocket()
{
if (m_file)
{
delete m_file;
}
if (m_cookies)
delete m_cookies;
if (m_form)
delete m_form;
}
void HttpdSocket::OnFirst()
{
// printf("Request: %s %s %s\n",GetMethod().c_str(),GetUrl().c_str(),GetHttpVersion().c_str());
}
void HttpdSocket::OnHeader(const std::string& key,const std::string& value)
{
if (!strcasecmp(key.c_str(),"content-length"))
{
m_content_length = atoi(value.c_str());
m_content_length_str = value;
}
else
if (!strcasecmp(key.c_str(),"cookie"))
{
m_http_cookie = value;
}
else
if (!strcasecmp(key.c_str(),"content-type"))
{
m_content_type = value;
}
else
if (!strcasecmp(key.c_str(),"if-modified-since"))
{
m_if_modified_since = value;
}
}
void HttpdSocket::OnHeaderComplete()
{
m_cookies = new HttpdCookies(m_http_cookie);
#if (defined(SOLARIS8) || defined(SOLARIS))
{
char slask[1000];
if (GetMethod() == "GET")
{
sprintf(slask,"QUERY_STRING=%s", GetQueryString().c_str());
putenv(slask);
}
sprintf(slask,"REQUEST_METHOD=%s", GetMethod().c_str());
putenv(slask);
sprintf(slask,"HTTP_COOKIE=%s", m_http_cookie.c_str());
putenv(slask);
sprintf(slask,"CONTENT_TYPE=%s", m_content_type.c_str());
putenv(slask);
sprintf(slask,"CONTENT_LENGTH=%s", m_content_length_str.c_str());
putenv(slask);
}
#elif defined _WIN32
{
char slask[1000];
if (GetMethod() == "GET")
{
sprintf(slask,"QUERY_STRING=%s", GetQueryString().c_str());
_putenv(slask);
}
sprintf(slask,"REQUEST_METHOD=%s", GetMethod().c_str());
_putenv(slask);
sprintf(slask,"HTTP_COOKIE=%s", m_http_cookie.c_str());
_putenv(slask);
sprintf(slask,"CONTENT_TYPE=%s", m_content_type.c_str());
_putenv(slask);
sprintf(slask,"CONTENT_LENGTH=%s", m_content_length_str.c_str());
_putenv(slask);
}
#else
if (GetMethod() == "GET")
{
setenv("QUERY_STRING", GetQueryString().c_str(), 1);
}
setenv("REQUEST_METHOD", GetMethod().c_str(), 1);
setenv("HTTP_COOKIE", m_http_cookie.c_str(), 1);
setenv("CONTENT_TYPE", m_content_type.c_str(), 1);
setenv("CONTENT_LENGTH", m_content_length_str.c_str(), 1);
#endif
if (GetMethod() == "POST")
{
m_file = new MemFile;
}
else
if (GetMethod() == "GET")
{
m_form = new HttpdForm(GetQueryString(), GetQueryString().size() );
AddResponseHeader("Date", datetime2httpdate(GetDate()) );
Exec();
Reset(); // prepare for next request
}
else
{
AddResponseHeader("Date", GetHttpDate());
AddResponseHeader("Connection", "close");
SetStatus("405");
SetStatusText("Method not allowed");
SendResponse();
}
}
void HttpdSocket::OnData(const char *p,size_t l)
{
//printf("Got %d bytes: %.*s\n", l, l, p);
if (m_file)
{
m_file -> fwrite(p,1,l);
}
m_received += l;
if (m_received >= m_content_length && m_content_length)
{
// all done
if (m_file && !m_form)
{
m_form = new HttpdForm(m_file);
AddResponseHeader("Date", datetime2httpdate(GetDate()) );
Exec();
Reset(); // prepare for next request
}
}
}
void HttpdSocket::Send64(const std::string& str64, const std::string& type)
{
Base64 bb;
if (!strcasecmp(m_start.c_str(), m_if_modified_since.c_str()))
{
SetStatus("304");
SetStatusText("Not Modified");
SendResponse();
}
else
{
size_t len = bb.decode_length(str64);
unsigned char *buf = new unsigned char[len];
SetStatus("200");
SetStatusText("OK");
AddResponseHeader("Content-length", Utility::l2string( (long)len) );
AddResponseHeader("Content-type", type );
AddResponseHeader("Last-modified", m_start);
SendResponse();
bb.decode(str64, buf, len);
SendBuf( (char *)buf, len);
delete[] buf;
}
}
std::string HttpdSocket::datetime2httpdate(const std::string& dt)
{
struct tm tp;
time_t t;
const char *days[] = { "Sun","Mon","Tue","Wed","Thu","Fri","Sat" };
const char *months[] = { "Jan","Feb","Mar","Apr","May","Jun",
"Jul","Aug","Sep","Oct","Nov","Dec" };
int i;
char s[40];
/* 1997-12-16 09:50:40 */
if (dt.size() == 19)
{
tp.tm_year = atoi(dt.substr(0,4).c_str()) - 1900;
i = atoi(dt.substr(5,2).c_str()) - 1;
tp.tm_mon = i >= 0 ? i : 0;
tp.tm_mday = atoi(dt.substr(8,2).c_str());
tp.tm_hour = atoi(dt.substr(11,2).c_str());
tp.tm_min = atoi(dt.substr(14,2).c_str());
tp.tm_sec = atoi(dt.substr(17,2).c_str());
tp.tm_wday = 0;
tp.tm_yday = 0;
tp.tm_isdst = 0;
t = mktime(&tp);
/*if (t == -1)
{
Handler().LogError(this, "datetime2httpdate", 0, "mktime() failed");
}*/
sprintf(s,"%s, %02d %s %d %02d:%02d:%02d GMT",
days[tp.tm_wday],
tp.tm_mday,
months[tp.tm_mon],
tp.tm_year + 1900,
tp.tm_hour,tp.tm_min,tp.tm_sec);
}
else
{
*s = 0;
}
return s;
}
std::string HttpdSocket::GetDate()
{
time_t t = time(NULL);
struct tm* tp = localtime(&t);
char slask[40];
if (tp)
{
sprintf(slask,"%d-%02d-%02d %02d:%02d:%02d",
tp -> tm_year + 1900,
tp -> tm_mon + 1,
tp -> tm_mday,
tp -> tm_hour,tp -> tm_min,tp -> tm_sec);
}
else
{
*slask = 0;
}
return slask;
}
void HttpdSocket::Reset()
{
HTTPSocket::Reset();
m_content_length = 0;
if (m_file)
{
delete m_file;
m_file = NULL;
}
m_received = 0;
m_request_id = ++m_request_count;
if (m_cookies)
delete m_cookies;
m_cookies = NULL;
if (m_form)
delete m_form;
m_form = NULL;
}
const std::string& HttpdSocket::GetHttpDate()
{
return m_http_date;
}
HttpdCookies *HttpdSocket::GetCookies()
{
return m_cookies;
}
HttpdForm *HttpdSocket::GetHttpForm()
{
return m_form;
}
#ifdef SOCKETS_NAMESPACE
}
#endif

View File

@ -0,0 +1,99 @@
/** \file HttpdSocket.h
*/
/*
Copyright (C) 2001-2004,2005 Anders Hedstrom (grymse@alhem.net)
This library is made available under the terms of the GNU GPL.
If you would like to use this library in a closed-source application,
a separate license agreement is available. For information about
the closed-source license agreement for the C++ sockets library,
please visit http://www.alhem.net/Sockets/license.html and/or
email license@alhem.net.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _HTTPDSOCKET_H
#define _HTTPDSOCKET_H
#include "HTTPSocket.h"
class TCPConnection;
#ifdef SOCKETS_NAMESPACE
namespace SOCKETS_NAMESPACE {
#endif
class HttpdCookies;
class HttpdForm;
class IFile;
/** \defgroup webserver Webserver framework */
/** Web server socket framework.
\ingroup webserver */
class HttpdSocket : public HTTPSocket
{
public:
HttpdSocket(uint32 ID, SOCKET in_socket, uint32 irIP, uint16 irPort);
~HttpdSocket();
void OnFirst();
void OnHeader(const std::string& key,const std::string& value);
void OnHeaderComplete();
void OnData(const char *,size_t);
/** This method needs to be implemented with logic to produce
a response to an incoming request. */
virtual void Exec() = 0;
/** Get current date in http rfc format. */
const std::string& GetHttpDate();
/** Get pointer to cookie class. */
HttpdCookies *GetCookies();
/** Get pointer to query string/form data class. */
HttpdForm *GetHttpForm();
protected:
/** Decode and send a base64-encoded string.
\param str64 Base64-encoded string
\param type Mime type of content (content-type header) */
void Send64(const std::string& str64, const std::string& type);
std::string datetime2httpdate(const std::string& dt);
std::string GetDate();
void Reset();
// headers
std::string m_http_cookie;
std::string m_content_type;
std::string m_content_length_str;
std::string m_if_modified_since;
private:
static int m_request_count;
static std::string m_start;
size_t m_content_length;
IFile *m_file;
size_t m_received;
int m_request_id;
std::string m_http_date;
HttpdCookies *m_cookies;
HttpdForm *m_form;
};
#ifdef SOCKETS_NAMESPACE
}
#endif
#endif // _HTTPDSOCKET_H

65
common/SocketLib/IFile.h Normal file
View File

@ -0,0 +1,65 @@
/** \file IFile.h
** \date 2005-04-25
** \author grymse@alhem.net
**/
/*
Copyright (C) 2004,2005 Anders Hedstrom
This library is made available under the terms of the GNU GPL.
If you would like to use this library in a closed-source application,
a separate license agreement is available. For information about
the closed-source license agreement for the C++ sockets library,
please visit http://www.alhem.net/Sockets/license.html and/or
email license@alhem.net.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _IFILE_H
#define _IFILE_H
#include <string>
#ifdef SOCKETS_NAMESPACE
namespace SOCKETS_NAMESPACE {
#endif
/** \defgroup file File handling */
/** Pure virtual file I/O interface.
\ingroup file */
class IFile
{
public:
virtual ~IFile() {}
virtual bool fopen(const std::string&, const std::string&) = 0;
virtual void fclose() = 0;
virtual size_t fread(char *, size_t, size_t) = 0;
virtual size_t fwrite(const char *, size_t, size_t) = 0;
virtual char *fgets(char *, int) = 0;
virtual void fprintf(char *format, ...) = 0;
virtual off_t size() = 0;
virtual bool eof() = 0;
};
#ifdef SOCKETS_NAMESPACE
}
#endif
#endif // _IFILE_H

View File

@ -0,0 +1,214 @@
/** \file MemFile.cpp
** \date 2005-04-25
** \author grymse@alhem.net
**/
/*
Copyright (C) 2004,2005 Anders Hedstrom
This library is made available under the terms of the GNU GPL.
If you would like to use this library in a closed-source application,
a separate license agreement is available. For information about
the closed-source license agreement for the C++ sockets library,
please visit http://www.alhem.net/Sockets/license.html and/or
email license@alhem.net.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef _WIN32
#pragma warning(disable:4786)
#endif
#include <stdio.h>
#include <stdarg.h>
#include "MemFile.h"
#include <cstdlib>
#include <cstring>
#ifdef _DEBUG
#define DEB(x) x
#else
#define DEB(x)
#endif
#ifdef SOCKETS_NAMESPACE
namespace SOCKETS_NAMESPACE {
#endif
std::map<std::string,MemFile::block_t *> MemFile::m_files;
MemFile::MemFile()
:m_temporary(true)
,m_base(new block_t)
,m_current_read(m_base)
,m_current_write(m_base)
,m_read_ptr(0)
,m_write_ptr(0)
{
}
MemFile::MemFile(const std::string& path)
:m_path(path)
,m_temporary(false)
,m_base(m_files[path])
,m_current_read(NULL)
,m_current_write(NULL)
,m_read_ptr(0)
,m_write_ptr(0)
{
if (!m_base)
{
m_base = new block_t;
m_files[path] = m_base;
}
m_current_read = m_base;
m_current_write = m_base;
}
MemFile::~MemFile()
{
while (m_base && m_temporary)
{
block_t *p = m_base;
m_base = p -> next;
delete p;
}
}
bool MemFile::fopen(const std::string& path, const std::string& mode)
{
return true;
}
void MemFile::fclose()
{
}
size_t MemFile::fread(char *ptr, size_t size, size_t nmemb)
{
size_t p = m_read_ptr % BLOCKSIZE;
size_t sz = size * nmemb;
if (p + sz < BLOCKSIZE)
{
//printf("Read @ %d(%d). %d bytes. (%c)\n", m_read_ptr, p, sz, *(m_current_read -> data + p));
memcpy(ptr, m_current_read -> data + p, sz);
m_read_ptr += sz;
}
else
{
size_t sz1 = BLOCKSIZE - p;
size_t sz2 = size - sz1;
memcpy(ptr, m_current_read -> data + p, sz1);
m_read_ptr += sz1;
if (m_current_read -> next)
{
m_current_read = m_current_read -> next;
memcpy(ptr + sz1, m_current_read -> data, sz2);
m_read_ptr += sz2;
}
else
{
DEB(printf("Read beyond available data\n");)
return sz1;
}
}
return sz;
}
size_t MemFile::fwrite(const char *ptr, size_t size, size_t nmemb)
{
size_t p = m_write_ptr % BLOCKSIZE;
size_t sz = size * nmemb;
if (p + sz < BLOCKSIZE)
{
//printf("Write @ %d(%d). %d bytes.\n", m_write_ptr, p, sz);
memcpy(m_current_write -> data + p, ptr, sz);
m_write_ptr += sz;
}
else
{
size_t sz1 = BLOCKSIZE - p;
size_t sz2 = size - sz1;
memcpy(m_current_write -> data + p, ptr, sz1);
block_t *next = new block_t;
m_current_write -> next = next;
m_current_write = next;
memcpy(m_current_write -> data, ptr + sz1, sz2);
m_write_ptr += sz;
}
return sz;
}
char *MemFile::fgets(char *s, int size)
{
int n = 0;
while (n < size - 1 && !eof())
{
char c;
fread(&c, 1, 1);
if (c == 10)
{
s[n] = 0;
return s;
}
s[n++] = c;
}
s[n] = 0;
return s;
}
void MemFile::fprintf(char *format, ...)
{
va_list ap;
char tmp[BLOCKSIZE];
va_start(ap, format);
#ifdef _WIN32
vsprintf(tmp, format, ap);
#else
vsnprintf(tmp, BLOCKSIZE - 1, format, ap);
#endif
va_end(ap);
fwrite(tmp, 1, strlen(tmp));
}
off_t MemFile::size()
{
return (off_t)m_write_ptr;
}
bool MemFile::eof()
{
return (m_read_ptr < m_write_ptr) ? false : true;
}
#ifdef SOCKETS_NAMESPACE
}
#endif

View File

@ -0,0 +1,93 @@
/** \file MemFile.h
** \date 2005-04-25
** \author grymse@alhem.net
**/
/*
Copyright (C) 2004,2005 Anders Hedstrom
This library is made available under the terms of the GNU GPL.
If you would like to use this library in a closed-source application,
a separate license agreement is available. For information about
the closed-source license agreement for the C++ sockets library,
please visit http://www.alhem.net/Sockets/license.html and/or
email license@alhem.net.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _MEMFILE_H
#define _MEMFILE_H
#include <map>
#include "IFile.h"
#define BLOCKSIZE 32768
#ifdef SOCKETS_NAMESPACE
namespace SOCKETS_NAMESPACE {
#endif
/** Implements a memory file.
\ingroup file */
class MemFile : public IFile
{
public:
/** File block structure.
\ingroup file */
struct block_t {
block_t() : next(NULL) {}
struct block_t *next;
char data[BLOCKSIZE];
};
public:
MemFile();
MemFile(const std::string& path);
~MemFile();
bool fopen(const std::string& path, const std::string& mode);
void fclose();
size_t fread(char *ptr, size_t size, size_t nmemb);
size_t fwrite(const char *ptr, size_t size, size_t nmemb);
char *fgets(char *s, int size);
void fprintf(char *format, ...);
off_t size();
bool eof();
private:
MemFile(const MemFile& ) {} // copy constructor
MemFile& operator=(const MemFile& ) { return *this; } // assignment operator
static std::map<std::string,block_t *> m_files;
std::string m_path;
bool m_temporary;
block_t *m_base;
block_t *m_current_read;
block_t *m_current_write;
size_t m_read_ptr;
size_t m_write_ptr;
};
#ifdef SOCKETS_NAMESPACE
}
#endif
#endif // _MEMFILE_H

92
common/SocketLib/Mime.cpp Normal file
View File

@ -0,0 +1,92 @@
/**
** File ......... Mime.cpp
** Published .... 2004-07-13
** Author ....... grymse@alhem.net
**/
/*
Copyright (C) 2004 Anders Hedstrom
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
#include "Parse.h"
#include "Mime.h"
#include <cstring>
Mime::Mime() {
}
Mime::Mime(const std::string& filename) {
LoadMimeFile(filename);
}
bool Mime::LoadMimeFile(const std::string& filename) {
FILE *fil;
if ((fil = fopen(filename.c_str(),"rt")) != NULL) {
char * slask = new char[1000];
fgets(slask,1000,fil);
while (!feof(fil))
{
while (strlen(slask) && (slask[strlen(slask) - 1] == 13 || slask[strlen(slask) - 1] == 10))
{
slask[strlen(slask) - 1] = 0;
}
Parse pa(slask);
std::string mime_type = pa.getword();
std::string ext = pa.getword();
while (ext.size())
{
m_mime[ext] = mime_type;
ext = pa.getword();
}
//
fgets(slask,1000,fil);
}
delete[] slask;
fclose(fil);
return(true);
}
return(false);
}
Mime::~Mime()
{
}
void Mime::Clear() {
m_mime.clear();
}
std::string Mime::GetMimeFromFilename(const std::string &filename) const {
std::string::size_type pos = filename.find_last_of('.');
if(pos == std::string::npos)
return(std::string("text/plain"));
return(GetMimeFromExtension(filename.substr(pos+1)));
}
std::string Mime::GetMimeFromExtension(const std::string& ext) const {
mime_m::const_iterator res;
res = m_mime.find(ext);
if(res == m_mime.end())
return(std::string("text/plain"));
return res->second;
}

55
common/SocketLib/Mime.h Normal file
View File

@ -0,0 +1,55 @@
/**
** File ......... Mime.h
** Published .... 2004-07-13
** Author ....... grymse@alhem.net
**/
/*
Copyright (C) 2004 Anders Hedstrom
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _MIME_H
#define _MIME_H
#include <string>
#include <map>
#ifdef SOCKETS_NAMESPACE
namespace SOCKETS_NAMESPACE {
#endif
class Mime {
typedef std::map<std::string,std::string> mime_m;
public:
Mime();
Mime(const std::string& mime_file);
~Mime();
void Clear();
bool LoadMimeFile(const std::string& mime_file);
std::string GetMimeFromFilename(const std::string &filename) const;
std::string GetMimeFromExtension(const std::string &ext) const;
private:
mime_m m_mime;
};
#ifdef SOCKETS_NAMESPACE
}
#endif
#endif // _MIME_H

327
common/SocketLib/Parse.cpp Normal file
View File

@ -0,0 +1,327 @@
/** \file Parse.cpp - parse a string
**
** Written: 1999-Feb-10 grymse@alhem.net
**/
/*
Copyright (C) 1999-2005 Anders Hedstrom
This library is made available under the terms of the GNU GPL.
If you would like to use this library in a closed-source application,
a separate license agreement is available. For information about
the closed-source license agreement for the C++ sockets library,
please visit http://www.alhem.net/Sockets/license.html and/or
email license@alhem.net.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Parse.h"
#ifdef _DEBUG
#define DEB(x)
#else
#define DEB(x)
#endif
#ifdef SOCKETS_NAMESPACE
namespace SOCKETS_NAMESPACE {
#endif
/* implementation of class Parse */
Parse::Parse()
:pa_the_str("")
,pa_splits("")
,pa_ord("")
,pa_the_ptr(0)
,pa_breakchar(0)
,pa_enable(0)
,pa_disable(0)
,pa_nospace(0)
,pa_quote(false)
{
}
Parse::Parse(const std::string&s)
:pa_the_str(s)
,pa_splits("")
,pa_ord("")
,pa_the_ptr(0)
,pa_breakchar(0)
,pa_enable(0)
,pa_disable(0)
,pa_nospace(0)
,pa_quote(false)
{
}
Parse::Parse(const std::string&s,const std::string&sp)
:pa_the_str(s)
,pa_splits(sp)
,pa_ord("")
,pa_the_ptr(0)
,pa_breakchar(0)
,pa_enable(0)
,pa_disable(0)
,pa_nospace(0)
,pa_quote(false)
{
}
Parse::Parse(const std::string&s,const std::string&sp,short nospace)
:pa_the_str(s)
,pa_splits(sp)
,pa_ord("")
,pa_the_ptr(0)
,pa_breakchar(0)
,pa_enable(0)
,pa_disable(0)
,pa_nospace(1)
,pa_quote(false)
{
}
Parse::~Parse()
{
}
#define C ((pa_the_ptr<pa_the_str.size()) ? pa_the_str[pa_the_ptr] : 0)
short Parse::issplit(char c)
{
for (size_t i = 0; i < pa_splits.size(); i++)
if (pa_splits[i] == c)
return 1;
return 0;
}
void Parse::getsplit(void)
{
size_t x;
if (C == '=')
{
x = pa_the_ptr++;
} else
{
while (C && (issplit(C)))
pa_the_ptr++;
x = pa_the_ptr;
while (C && !issplit(C) && C != '=')
pa_the_ptr++;
}
if (x == pa_the_ptr && C == '=')
pa_the_ptr++;
pa_ord = (x < pa_the_str.size()) ? pa_the_str.substr(x,pa_the_ptr - x) : "";
}
std::string Parse::getword(void)
{
size_t x;
int disabled = 0;
int quote = 0;
int rem = 0;
if (pa_nospace)
{
while (C && issplit(C))
pa_the_ptr++;
x = pa_the_ptr;
while (C && !issplit(C) && (C != pa_breakchar || !pa_breakchar || disabled))
{
if (pa_breakchar && C == pa_disable)
disabled = 1;
if (pa_breakchar && C == pa_enable)
disabled = 0;
if (pa_quote && C == '"')
quote = 1;
pa_the_ptr++;
while (quote && C && C != '"')
{
pa_the_ptr++;
}
if (pa_quote && C == '"')
{
pa_the_ptr++;
}
quote = 0;
}
} else
{
if (C == pa_breakchar && pa_breakchar)
{
x = pa_the_ptr++;
rem = 1;
} else
{
while (C && (C == ' ' || C == 9 || C == 13 || C == 10 || issplit(C)))
pa_the_ptr++;
x = pa_the_ptr;
while (C && C != ' ' && C != 9 && C != 13 && C != 10 && !issplit(C) &&
(C != pa_breakchar || !pa_breakchar || disabled))
{
if (pa_breakchar && C == pa_disable)
disabled = 1;
if (pa_breakchar && C == pa_enable)
disabled = 0;
if (pa_quote && C == '"')
{
quote = 1;
pa_the_ptr++;
while (quote && C && C != '"')
{
pa_the_ptr++;
}
if (pa_quote && C == '"')
{
pa_the_ptr++;
}
}
else
pa_the_ptr++;
quote = 0;
}
pa_the_ptr++;
rem = 1;
}
if (x == pa_the_ptr && C == pa_breakchar && pa_breakchar)
pa_the_ptr++;
}
if (x < pa_the_str.size())
{
pa_ord = pa_the_str.substr(x,pa_the_ptr - x - rem);
}
else
{
pa_ord = "";
}
return pa_ord;
}
void Parse::getword(std::string&s)
{
s = Parse::getword();
}
void Parse::getsplit(std::string&s)
{
Parse::getsplit();
s = pa_ord;
}
void Parse::getword(std::string&s,std::string&fill,int l)
{
Parse::getword();
s = "";
while (s.size() + pa_ord.size() < (size_t)l)
s += fill;
s += pa_ord;
}
std::string Parse::getrest()
{
std::string s;
while (C && (C == ' ' || C == 9 || issplit(C)))
pa_the_ptr++;
s = (pa_the_ptr < pa_the_str.size()) ? pa_the_str.substr(pa_the_ptr) : "";
return s;
}
void Parse::getrest(std::string&s)
{
while (C && (C == ' ' || C == 9 || issplit(C)))
pa_the_ptr++;
s = (pa_the_ptr < pa_the_str.size()) ? pa_the_str.substr(pa_the_ptr) : "";
}
long Parse::getvalue(void)
{
Parse::getword();
return atol(pa_ord.c_str());
}
void Parse::setbreak(char c)
{
pa_breakchar = c;
}
int Parse::getwordlen(void)
{
size_t x,y = pa_the_ptr,len;
if (C == pa_breakchar && pa_breakchar)
{
x = pa_the_ptr++;
} else
{
while (C && (C == ' ' || C == 9 || C == 13 || C == 10 || issplit(C)))
pa_the_ptr++;
x = pa_the_ptr;
while (C && C != ' ' && C != 9 && C != 13 && C != 10 && !issplit(C) && (C != pa_breakchar || !pa_breakchar))
pa_the_ptr++;
}
if (x == pa_the_ptr && C == pa_breakchar && pa_breakchar)
pa_the_ptr++;
len = pa_the_ptr - x;
pa_the_ptr = y;
return (int)len;
}
int Parse::getrestlen(void)
{
size_t y = pa_the_ptr;
size_t len;
while (C && (C == ' ' || C == 9 || issplit(C)))
pa_the_ptr++;
len = strlen(pa_the_str.c_str() + pa_the_ptr);
pa_the_ptr = y;
return (int)len;
}
void Parse::getline(void)
{
size_t x;
x = pa_the_ptr;
while (C && C != 13 && C != 10)
pa_the_ptr++;
pa_ord = (x < pa_the_str.size()) ? pa_the_str.substr(x,pa_the_ptr - x) : "";
if (C == 13)
pa_the_ptr++;
if (C == 10)
pa_the_ptr++;
}
void Parse::getline(std::string&s)
{
getline();
s = pa_ord;
}
/* end of implementation of class Parse */
/***************************************************/
#ifdef SOCKETS_NAMESPACE
}
#endif

95
common/SocketLib/Parse.h Normal file
View File

@ -0,0 +1,95 @@
/** \file Parse.h - parse a string
**
** Written: 1999-Feb-10 grymse@alhem.net
**/
/*
Copyright (C) 1999-2005 Anders Hedstrom
This library is made available under the terms of the GNU GPL.
If you would like to use this library in a closed-source application,
a separate license agreement is available. For information about
the closed-source license agreement for the C++ sockets library,
please visit http://www.alhem.net/Sockets/license.html and/or
email license@alhem.net.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _PARSE_H
#define _PARSE_H
#include <string>
#ifdef SOCKETS_NAMESPACE
namespace SOCKETS_NAMESPACE {
#endif
/***************************************************/
/* interface of class Parse */
/** Splits a string whatever way you want.
\ingroup util */
class Parse
{
public:
Parse();
Parse(const std::string&);
Parse(const std::string&,const std::string&);
Parse(const std::string&,const std::string&,short);
~Parse();
short issplit(char);
void getsplit(void);
void getsplit(std::string&);
std::string getword(void);
void getword(std::string&);
void getword(std::string&,std::string&,int);
std::string getrest();
void getrest(std::string&);
long getvalue(void);
void setbreak(char);
int getwordlen(void);
int getrestlen(void);
void enablebreak(char c) {
pa_enable = c;
}
void disablebreak(char c) {
pa_disable = c;
}
void getline(void);
void getline(std::string&);
size_t getptr(void) { return pa_the_ptr; }
void EnableQuote(bool b) { pa_quote = b; }
private:
std::string pa_the_str;
std::string pa_splits;
std::string pa_ord;
size_t pa_the_ptr;
char pa_breakchar;
char pa_enable;
char pa_disable;
short pa_nospace;
bool pa_quote;
};
#ifdef SOCKETS_NAMESPACE
}
#endif
#endif // _PARSE_H

View File

@ -0,0 +1,5 @@
EQEmu took this code from `C++ Sockets Library`
http://www.alhem.net/Sockets/
and integrated it into our world server. We did not care for the actual
socket code (didnt work on windows) so we scrapped all of it, and just
used the HTTP framework code.

View File

@ -0,0 +1,5 @@
Find uuid.h here
http://www.die.net/doc/linux/include/uuid/uuid.h
or here
http://www.thedna.net/uuid.h

View File

@ -0,0 +1,169 @@
/** \file Utility.cpp
** \date 2004-02-13
** \author grymse@alhem.net
**/
/*
Copyright (C) 2004,2005 Anders Hedstrom
This library is made available under the terms of the GNU GPL.
If you would like to use this library in a closed-source application,
a separate license agreement is available. For information about
the closed-source license agreement for the C++ sockets library,
please visit http://www.alhem.net/Sockets/license.html and/or
email license@alhem.net.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "Utility.h"
#ifdef SOCKETS_NAMESPACE
namespace SOCKETS_NAMESPACE {
#endif
std::string Utility::base64(const std::string& str_in)
{
std::string str;
Base64 m_b;
m_b.encode(str_in, str, false); // , false == do not add cr/lf
return str;
}
std::string Utility::base64d(const std::string& str_in)
{
std::string str;
Base64 m_b;
m_b.decode(str_in, str);
return str;
}
std::string Utility::l2string(long l)
{
std::string str;
char tmp[100];
sprintf(tmp,"%ld",l);
str = tmp;
return str;
}
std::string Utility::bigint2string(uint64_t l)
{
std::string str;
uint64_t tmp = l;
while (tmp)
{
uint64_t a = tmp % 10;
str = (char)(a + 48) + str;
tmp /= 10;
}
if (!str.size())
{
str = "0";
}
return str;
}
uint64_t Utility::atoi64(const std::string& str)
{
uint64_t l = 0;
for (size_t i = 0; i < str.size(); i++)
{
l = l * 10 + str[i] - 48;
}
return l;
}
unsigned int Utility::hex2unsigned(const std::string& str)
{
unsigned int r = 0;
for (size_t i = 0; i < str.size(); i++)
{
r = r * 16 + str[i] - 48 - ((str[i] >= 'A') ? 7 : 0) - ((str[i] >= 'a') ? 32 : 0);
}
return r;
}
/*
* Encode string per RFC1738 URL encoding rules
* tnx rstaveley
*/
std::string Utility::rfc1738_encode(const std::string& src)
{
static char hex[] = "0123456789ABCDEF";
std::string dst;
for (size_t i = 0; i < src.size(); i++)
{
if (isalnum(src[i]))
{
dst += src[i];
}
else
if (src[i] == ' ')
{
dst += '+';
}
else
{
dst += '%';
dst += hex[src[i] / 16];
dst += hex[src[i] % 16];
}
}
return dst;
} // rfc1738_encode
/*
* Decode string per RFC1738 URL encoding rules
* tnx rstaveley
*/
std::string Utility::rfc1738_decode(const std::string& src)
{
std::string dst;
for (size_t i = 0; i < src.size(); i++)
{
if (src[i] == '%' && isxdigit(src[i + 1]) && isxdigit(src[i + 2]))
{
char c1 = src[++i];
char c2 = src[++i];
c1 = c1 - 48 - ((c1 >= 'A') ? 7 : 0) - ((c1 >= 'a') ? 32 : 0);
c2 = c2 - 48 - ((c2 >= 'A') ? 7 : 0) - ((c2 >= 'a') ? 32 : 0);
dst += (char)(c1 * 16 + c2);
}
else
if (src[i] == '+')
{
dst += ' ';
}
else
{
dst += src[i];
}
}
return dst;
} // rfc1738_decode
#ifdef SOCKETS_NAMESPACE
}
#endif

View File

@ -0,0 +1,70 @@
/** \file Utility.h
** \date 2004-02-13
** \author grymse@alhem.net
**/
/*
Copyright (C) 2004,2005 Anders Hedstrom
This library is made available under the terms of the GNU GPL.
If you would like to use this library in a closed-source application,
a separate license agreement is available. For information about
the closed-source license agreement for the C++ sockets library,
please visit http://www.alhem.net/Sockets/license.html and/or
email license@alhem.net.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _UTILITY_H
#define _UTILITY_H
#include <ctype.h>
#ifdef _WIN32
typedef unsigned __int64 uint64_t;
#else
#include <stdlib.h>
#ifdef SOLARIS
# include <sys/types.h>
#else
# include <stdint.h>
#endif
#endif
#include "Base64.h"
#ifdef SOCKETS_NAMESPACE
namespace SOCKETS_NAMESPACE {
#endif
/** Conversion utilities.
\ingroup util */
class Utility
{
public:
static std::string base64(const std::string& str_in);
static std::string base64d(const std::string& str_in);
static std::string l2string(long l);
static std::string bigint2string(uint64_t l);
static uint64_t atoi64(const std::string& str);
static unsigned int hex2unsigned(const std::string& str);
static std::string rfc1738_encode(const std::string& src);
static std::string rfc1738_decode(const std::string& src);
};
#ifdef SOCKETS_NAMESPACE
}
#endif
#endif // _UTILITY_H

340
common/SocketLib/gpl.txt Normal file
View File

@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

Some files were not shown because too many files have changed in this diff Show More