Skip to content

Commit

Permalink
- Added: client commands ADDITEM and ADDCHAR, to be used in place of …
Browse files Browse the repository at this point in the history
….ADD when there's the need to force the argument to be an item or a char.

This can be useful when using raw IDs (like 01, 0bd1, etc) instead of defnames.
- Improvement: changed the logic behind script files reading and caching, now it will be faster and require less memory.
- Fixed: correct thread name not being shown in the stack trace.
- Renamed ResourceGetID_Advance to ResourceGetID_EatStr, added fCanFail argument.
- Added some string functions, starting from POSIX C getline and getdelim (got the source from NetBSD and renamed to fReadUntilDelimiter), then added some more custom functions to help read from file or string buffers.
  • Loading branch information
cbnolok committed Jun 4, 2024
1 parent 5b0ed57 commit c7f4eb5
Show file tree
Hide file tree
Showing 22 changed files with 393 additions and 150 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
- name: CMake
run: cmake -G "Visual Studio 17 2022" .\
- name: MSBuild
run: msbuild SphereServer.sln /verbosity:minimal /maxcpucount /p:Configuration=Nightly
run: msbuild SphereServer.sln /verbosity:normal /maxcpucount /p:Configuration=Nightly
- name: Create package
run: |
pwd
Expand Down Expand Up @@ -50,7 +50,7 @@ jobs:
- name: CMake
run: cmake -G "Visual Studio 17 2022" -A Win32 .\
- name: MSBuild
run: msbuild SphereServer.sln /verbosity:minimal /maxcpucount /p:Configuration=Nightly
run: msbuild SphereServer.sln /verbosity:normal /maxcpucount /p:Configuration=Nightly
- name: Create package
run: |
pwd
Expand Down
17 changes: 9 additions & 8 deletions Changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3718,14 +3718,12 @@ Added: 'H' shortcut for variables to get the value as hexadecimal.
when you switch this setting.
- Fixed: SPELLFLAG_NOUNPARALYZE flag wasn't working as intended.

02-06-2024, Nolok
03-06-2024, Nolok
- Added ini settings:
// Maximum number of connection requests before rejecting/blocking IP. Reset after <NetTTL> seconds elapsed after last connection attempt.
MaxConnectRequestsPerIP=5

// Maximum time in milliseconds to wait before closing a connection request wich did not make it into a successful login (classic DDoS just asks to connect without doing anything else, or sends garbage data).
TimeoutIncompleteConn=5 * 1000 // 5 seconds

// Maximum number of connection requests before rejecting/blocking IP. Reset after <NetTTL> seconds elapsed after last connection attempt.
MaxConnectRequestsPerIP=5
// Maximum time in milliseconds to wait before closing a connection request wich did not make it into a successful login (classic DDoS just asks to connect without doing anything else, or sends garbage data).
TimeoutIncompleteConn=5 * 1000 // 5 seconds
- Added serv_trig function f_onserver_connectreq_ex, called after an IP exceeds MaxConnectRequestsPerIP:
ARGS (RO): IP address.
ARGN1 (RO): System time in milliseconds since the last connection.
Expand All @@ -3734,8 +3732,11 @@ TimeoutIncompleteConn=5 * 1000 // 5 seconds
LOCAL.BAN_TIMEOUT (RW): 5 * 60 (default), seconds to keep banned the ip from new connections to the server (permanent if negative).
RETURN 1: Only reject the connection.
RETURN 2: Reject and ban the IP for <LOCAL.BAN_TIMEOUT> seconds.

- Added serv_trig function f_onserver_connection_acquired, called after an IP successifully establishes a connection with the server and passess the security checks:
ARGS (RO): IP address.
ARGN1 (RO): System time in milliseconds since the last connection.
ARGN2 (RO): System time in milliseconds of this connection attempt.

04-06-2024, Nolok
- Added: client commands ADDITEM and ADDCHAR, to be used in place of .ADD when there's the need to force the argument to be an item or a char.
This can be useful when using raw IDs (like 01, 0bd1, etc) instead of defnames.
7 changes: 4 additions & 3 deletions cmake/toolchains/Windows-MSVC.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,10 @@ function (toolchain_exe_stuff)
set(CMAKE_EXE_LINKER_FLAGS_NIGHTLY CACHE INTERNAL ${CMAKE_EXE_LINKER_FLAGS_RELEASE} "")

target_link_options(spheresvr PRIVATE
$<$<CONFIG:Release>: ${EXE_LINKER_EXTRA} /OPT:REF,ICF /LTCG>
$<$<CONFIG:Nightly>: ${EXE_LINKER_EXTRA} /OPT:REF,ICF /LTCG>
$<$<CONFIG:Debug>: ${EXE_LINKER_EXTRA} /DEBUG /LTCG:OFF /SAFESEH:NO $<$<NOT:$<BOOL:${ENABLED_SANITIZER}>>:/INCREMENTAL /EDITANDCONTINUE>>
$<$<CONFIG:Release>: ${EXE_LINKER_EXTRA} /OPT:REF,ICF /LTCG /NODEFAULTLIB:libcmtd>
$<$<CONFIG:Nightly>: ${EXE_LINKER_EXTRA} /OPT:REF,ICF /LTCG /NODEFAULTLIB:libcmtd>
$<$<CONFIG:Debug>: ${EXE_LINKER_EXTRA} /DEBUG /LTCG:OFF /SAFESEH:NO /NODEFAULTLIB:libcmt
$<$<NOT:$<BOOL:${ENABLED_SANITIZER}>>:/INCREMENTAL /EDITANDCONTINUE> >
)
# MSVC doesn't yet have an option to statically link against *san sanitizer libraries.
# /INCREMENTAL and /EDITANDCONTINUE not compatible with a MSVC Asan build.
Expand Down
11 changes: 10 additions & 1 deletion cmake/toolchains/include/OSX-AppleClang_common.inc.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ function (toolchain_exe_stuff_common)
SET (COMPILE_OPTIONS_EXTRA -fno-omit-frame-pointer -fno-inline)
ENDIF ()
IF (TARGET spheresvr_release)
TARGET_COMPILE_OPTIONS ( spheresvr_release PUBLIC -s -O3 ${COMPILE_OPTIONS_EXTRA})
TARGET_COMPILE_OPTIONS ( spheresvr_release PUBLIC -O3 ${COMPILE_OPTIONS_EXTRA})
ENDIF ()
IF (TARGET spheresvr_nightly)
IF (ENABLED_SANITIZER)
Expand All @@ -119,6 +119,15 @@ function (toolchain_exe_stuff_common)
)


#-- Apply linker flags, only the ones specific per build type.
IF (TARGET spheresvr_release)
target_link_options (spheresvr_release PRIVATE -s)
ENDIF ()
IF (TARGET spheresvr_nightly AND NOT ${ENABLED_SANITIZER})
target_link_options (spheresvr_nightly PRIVATE -s)
ENDIF ()


#-- Store common define macros.

set(cxx_compiler_definitions_common
Expand Down
7 changes: 3 additions & 4 deletions lib/lib_build_flags_common_c.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,9 @@ if (MSVC)
$<$<CONFIG:Debug>: $<IF:$<BOOL:${RUNTIME_STATIC_LINK}>,/MTd,/MDd> $<IF:$<BOOL:${ENABLED_SANITIZER}>,/Zi,/ZI>>
)
set (c_linker_options_common
/NODEFAULTLIB:libcmt /NODEFAULTLIB:libcmtd
$<$<CONFIG:Release>: /OPT:REF,ICF /LTCG:ON>
$<$<CONFIG:Nightly>: /OPT:REF,ICF /LTCG:ON>
$<$<CONFIG:Debug>: /DEBUG /LTCG:OFF>
$<$<CONFIG:Release>: /OPT:REF,ICF /LTCG:ON /NODEFAULTLIB:libcmtd>
$<$<CONFIG:Nightly>: /OPT:REF,ICF /LTCG:ON /NODEFAULTLIB:libcmtd>
$<$<CONFIG:Debug>: /DEBUG /LTCG:OFF /NODEFAULTLIB:libcmt>
)

else (MSVC)
Expand Down
88 changes: 49 additions & 39 deletions src/common/CCacheableScriptFile.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

#include "../sphere/threads.h"
#include "CLog.h"
#include "CCacheableScriptFile.h"

#ifdef _WIN32
Expand Down Expand Up @@ -68,49 +68,59 @@ bool CCacheableScriptFile::_Open(lpctstr ptcFilename, uint uiModeFlags)
}
else
{
TemporaryString tsBuf;
tchar* ptcBuf = tsBuf.buffer();
size_t uiStrLen;
bool fUTF = false, fFirstLine = true;
const int iFileLength = _GetLength();
_fileContent = new std::vector<std::string>;
_fileContent->reserve(iFileLength / 20);

while ( !feof(_pStream) )
ASSERT(iFileLength >= 0);
bool fUTF = false, fFirstLine = true;
if (iFileLength > 5 * 1'000'000)
{
tsBuf.setAt(0, '\0');
fgets(ptcBuf, SCRIPT_MAX_LINE_LEN, _pStream);
uiStrLen = strlen(ptcBuf);
ASSERT(SCRIPT_MAX_LINE_LEN < INT_MAX);
if (uiStrLen > SCRIPT_MAX_LINE_LEN)
uiStrLen = SCRIPT_MAX_LINE_LEN;

// first line may contain utf marker (byte order mark)
if (fFirstLine && uiStrLen >= 3 &&
(uchar)(ptcBuf[0]) == 0xEF &&
(uchar)(ptcBuf[1]) == 0xBB &&
(uchar)(ptcBuf[2]) == 0xBF)
{
fUTF = true;
}
g_Log.EventError("Single script file bigger than %d MB? Skipping.\n", iFileLength / 1'000'000);
}
else
{
// Fastest method: read the script file all at once.
auto fileContentCopy = std::make_unique<char[]>((size_t)iFileLength + 1u);
fread(fileContentCopy.get(), sizeof(char), (size_t)iFileLength, _pStream);

// Allocate string vectors for each script line.
_fileContent = new std::vector<std::string>;
_fileContent->reserve(iFileLength / 25);

const lpctstr str_start = (fUTF ? &ptcBuf[3] : ptcBuf);
size_t len_to_copy = uiStrLen - (fUTF ? 3 : 0);
while (len_to_copy > 0)
ssize_t iStrLen;
for (const char *fileCursor = fileContentCopy.get();; fileCursor += (size_t)iStrLen + 1u)
{
const int ch = str_start[len_to_copy - 1];
if (ch == '\n' || ch == '\r')
len_to_copy -= 1;
else
iStrLen = sGetLine_StaticBuf(fileCursor, SCRIPT_MAX_LINE_LEN);
if (iStrLen < 0)
break;
}
if (len_to_copy == 0)
_fileContent->emplace_back();
else
_fileContent->emplace_back(str_start, len_to_copy);
fFirstLine = false;
fUTF = false;
}
if (iStrLen < 1 || (fileCursor[iStrLen] != '\n'))
continue;

// first line may contain utf marker (byte order mark)
if (fFirstLine && iStrLen >= 3 &&
(uchar)(fileCursor[0]) == 0xEF &&
(uchar)(fileCursor[1]) == 0xBB &&
(uchar)(fileCursor[2]) == 0xBF)
{
fUTF = true;
}

const lpctstr str_start = (fUTF ? &fileCursor[3] : fileCursor);
size_t len_to_copy = (size_t)iStrLen - (fUTF ? 3 : 0);
while (len_to_copy > 0)
{
const int ch = str_start[len_to_copy - 1];
if (ch == '\n' || ch == '\r')
len_to_copy -= 1;
else
break;
}
if (len_to_copy == 0)
_fileContent->emplace_back();
else
_fileContent->emplace_back(str_start, len_to_copy);
fFirstLine = false;
fUTF = false;
} // closes while
} // closes else

fclose(_pStream);
_pStream = nullptr;
Expand Down
22 changes: 17 additions & 5 deletions src/common/resource/CResourceHolder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -337,9 +337,9 @@ CResourceScript * CResourceHolder::GetResourceFile( size_t i )
return m_ResourceFiles[i];
}

CResourceID CResourceHolder::ResourceGetID_Advance(RES_TYPE restype, lpctstr &ptcName, word wPage)
CResourceID CResourceHolder::ResourceGetID_EatStr(RES_TYPE restype, lpctstr &ptcName, word wPage, bool fCanFail)
{
ADDTOCALLSTACK("CResourceHolder::ResourceGetID_Advance");
ADDTOCALLSTACK("CResourceHolder::ResourceGetID_EatStr");
// Find the Resource ID given this name.
// We are NOT creating a new resource. just looking up an existing one
// NOTE: Do not enforce the restype.
Expand All @@ -366,6 +366,7 @@ CResourceID CResourceHolder::ResourceGetID_Advance(RES_TYPE restype, lpctstr &pt
}
*/

lpctstr ptcNameStart = ptcName;
dword dwEvalPrivateUID = Exp_GetDWVal(ptcName); // May be some complex expression {}
int iEvalResType = RES_GET_TYPE(dwEvalPrivateUID);
int iEvalResIndex = RES_GET_INDEX(dwEvalPrivateUID);
Expand All @@ -374,22 +375,33 @@ CResourceID CResourceHolder::ResourceGetID_Advance(RES_TYPE restype, lpctstr &pt
if ((restype != RES_UNKNOWN) && (iEvalResType == RES_UNKNOWN))
{
// Label it with the type we want.
ASSERT(restype > RES_UNKNOWN && restype <= RES_QTY);
if (restype == RES_QTY)
{
// RES_QTY means i don't care, because i pass a defname and it already carries data about which kind of resource it is.
// If it doesn't (?!), or simply i pass an ID instead of a defname (which i expected), i'll have unexpected results, so better throw an error.
// If i pass a bare ID, Sphere cannot know if you meant a char, item, etc...
if (!fCanFail)
g_Log.EventError("Can't get the resource type from a bare ID ('%s')!\n", ptcNameStart);
return CResourceID(RES_UNKNOWN /* 0 */, 0, 0u);
}
return CResourceID(restype, iEvalResIndex, wPage);
}
// CResourceID always needs to be a valid resource (there's an ASSERT in CResourceID copy constructor).
return CResourceID((RES_TYPE)iEvalResType, iEvalResIndex, wPage);
}

CResourceID CResourceHolder::ResourceGetID( RES_TYPE restype, lpctstr ptcName, word wPage )
CResourceID CResourceHolder::ResourceGetID( RES_TYPE restype, lpctstr ptcName, word wPage, bool fCanFail )
{
ADDTOCALLSTACK("CResourceHolder::ResourceGetID");
return ResourceGetID_Advance(restype, ptcName, wPage);
return ResourceGetID_EatStr(restype, ptcName, wPage, fCanFail);
}

CResourceID CResourceHolder::ResourceGetIDType( RES_TYPE restype, lpctstr pszName, word wPage )
{
// Get a resource of just this index type.
CResourceID rid = ResourceGetID( restype, pszName, wPage );
ASSERT(restype != RES_QTY);
CResourceID rid = ResourceGetID( restype, pszName, wPage, true );
if ( rid.GetResType() != restype )
{
rid.Init();
Expand Down
4 changes: 2 additions & 2 deletions src/common/resource/CResourceHolder.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ class CResourceHolder : public CScriptObj
lpctstr ResourceGetName( const CResourceID& rid ) const;
lpctstr ResourceGetName(const CResourceIDBase& rid, const RES_TYPE iExpectedType);
CResourceScript * GetResourceFile( size_t i );
CResourceID ResourceGetID_Advance( RES_TYPE restype, lpctstr &pszName, word wPage = 0 ); // this moves forward (changes!) the ptcName pointer!
CResourceID ResourceGetID( RES_TYPE restype, lpctstr ptcName, word wPage = 0 );
CResourceID ResourceGetID_EatStr( RES_TYPE restype, lpctstr &pszName, word wPage = 0, bool fCanFail = false ); // this moves forward (changes!) the ptcName pointer!
CResourceID ResourceGetID( RES_TYPE restype, lpctstr ptcName, word wPage = 0, bool fCanFail = false);
CResourceID ResourceGetIDType( RES_TYPE restype, lpctstr pszName, word wPage = 0 );
int ResourceGetIndexType( RES_TYPE restype, lpctstr pszName, word wPage = 0 );
bool ResourceLock( CResourceLock & s, const CResourceID& rid );
Expand Down
21 changes: 21 additions & 0 deletions src/common/resource/CResourceID.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,24 @@ CResourceID& CResourceID::operator = (const CResourceIDBase& rid)
m_wPage = 0;
return *this;
}

bool CResourceID::operator == (const CResourceID & rid) const noexcept
{
return ((rid.m_wPage == m_wPage) && (rid.m_dwInternalVal == m_dwInternalVal));
}

void CResourceID::Init() noexcept
{
m_dwInternalVal = UID_UNUSED;
m_wPage = 0;
}
void CResourceID::Clear() noexcept
{
m_dwInternalVal = UID_PLAIN_CLEAR;
m_wPage = 0;
}

bool CResourceID::IsEmpty() const noexcept
{
return ((m_dwInternalVal & UID_O_INDEX_MASK) == 0 /* means also that restype = 0/RES_UNKNOWN */) && (m_wPage == 0);
}
Loading

0 comments on commit c7f4eb5

Please sign in to comment.