mirror of
https://github.com/rehlds/rehlds.git
synced 2024-12-29 08:05:50 +03:00
Merge branch 'master' into ipconnlimit
This commit is contained in:
commit
1328b28304
@ -52,7 +52,7 @@ Bugfixed version of rehlds contains an additional cvars:
|
||||
<li>sv_rehlds_stringcmdrate_avg_punish // Time in minutes for which the player will be banned (0 - Permanent, use a negative number for a kick). Default: 5
|
||||
<li>sv_rehlds_stringcmdrate_max_burst // Max burst level of 'string' cmds for ban. Default: 400
|
||||
<li>sv_rehlds_stringcmdrate_burst_punish // Time in minutes for which the player will be banned (0 - Permanent, use a negative number for a kick). Default: 5
|
||||
<li>sv_rehlds_userinfo_transmitted_fields // Userinfo fields only with these keys will be transmitted to clients via network. If not set then all fields will be transmitted (except prefixed with underscore). Each key must be prefixed by backslash, for example "\name\model\*sid\*hltv\bottomcolor\topcolor". Default: ""
|
||||
<li>sv_rehlds_userinfo_transmitted_fields // Userinfo fields only with these keys will be transmitted to clients via network. If not set then all fields will be transmitted (except prefixed with underscore). Each key must be prefixed by backslash, for example "\name\model\*sid\*hltv\bottomcolor\topcolor". See [wiki](https://github.com/dreamstalker/rehlds/wiki/Userinfo-keys) to collect sufficient set of keys for your server. Default: ""
|
||||
<li>sv_rehlds_attachedentities_playeranimationspeed_fix // Fixes bug with gait animation speed increase when player has some attached entities (aiments). Can cause animation lags when cl_updaterate is low. Default: 0
|
||||
<li>sv_rehlds_maxclients_from_single_ip // Limit number of connections from the single ip address. Default: 5
|
||||
</ul>
|
||||
|
@ -159,7 +159,7 @@
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>HLTV;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>HLTV;HLTV_FIXES;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)\..\src;$(ProjectDir)\..\..\;$(ProjectDir)\..\..\..\;$(ProjectDir)\..\..\..\common;$(ProjectDir)\..\..\..\engine;$(ProjectDir)\..\..\..\public;$(ProjectDir)\..\..\..\public\rehlds;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PrecompiledHeaderFile>precompiled.h</PrecompiledHeaderFile>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
@ -190,7 +190,7 @@
|
||||
<Optimization>Disabled</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>HLTV;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>HLTV;HLTV_FIXES;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)\..\src;$(ProjectDir)\..\..\;$(ProjectDir)\..\..\..\;$(ProjectDir)\..\..\..\common;$(ProjectDir)\..\..\..\engine;$(ProjectDir)\..\..\..\public;$(ProjectDir)\..\..\..\public\rehlds;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PrecompiledHeaderFile>precompiled.h</PrecompiledHeaderFile>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
|
@ -20,7 +20,7 @@ void setupToolchain(NativeBinarySpec b) {
|
||||
cfg.projectInclude(project, '/..', '/../..', '/src', '/../../common', '/../../engine', '/../../public', '/../../public/rehlds', '/../../pm_shared');
|
||||
cfg.projectInclude(dep_bzip2, '/include')
|
||||
|
||||
cfg.singleDefines 'USE_BREAKPAD_HANDLER', 'HLTV', 'CORE_MODULE'
|
||||
cfg.singleDefines 'USE_BREAKPAD_HANDLER', 'HLTV', 'HLTV_FIXES', 'CORE_MODULE'
|
||||
|
||||
if (cfg instanceof MsvcToolchainConfig) {
|
||||
cfg.compilerOptions.pchConfig = new MsvcToolchainConfig.PrecompiledHeadersConfig(
|
||||
|
@ -77,7 +77,7 @@
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>HLTV;WIN32;_DEBUG;_WINDOWS;_USRDLL;CORE_MODULE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>HLTV;HLTV_FIXES;WIN32;_DEBUG;_WINDOWS;_USRDLL;CORE_MODULE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>
|
||||
</SDLCheck>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)\..\src;$(ProjectDir)\..\..\;$(ProjectDir)\..\..\..\;$(ProjectDir)\..\..\..\common;$(ProjectDir)\..\..\..\engine;$(ProjectDir)\..\..\..\public;$(ProjectDir)\..\..\..\public\rehlds;$(ProjectDir)\..\..\..\pm_shared;$(ProjectDir)\..\..\..\..\dep\bzip2\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
@ -112,7 +112,7 @@
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>HLTV;WIN32;NDEBUG;_WINDOWS;_USRDLL;CORE_MODULE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>HLTV;HLTV_FIXES;WIN32;NDEBUG;_WINDOWS;_USRDLL;CORE_MODULE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>
|
||||
</SDLCheck>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)\..\src;$(ProjectDir)\..\..\;$(ProjectDir)\..\..\..\;$(ProjectDir)\..\..\..\common;$(ProjectDir)\..\..\..\engine;$(ProjectDir)\..\..\..\public;$(ProjectDir)\..\..\..\public\rehlds;$(ProjectDir)\..\..\..\pm_shared;$(ProjectDir)\..\..\..\..\dep\bzip2\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
|
@ -297,6 +297,14 @@ int NetSocket::GetLong(unsigned char *pData, int size)
|
||||
{
|
||||
m_NetSplitPacket.currentSequence = sequenceNumber;
|
||||
m_NetSplitPacket.splitCount = packetCount;
|
||||
|
||||
#ifdef HLTV_FIXES
|
||||
m_NetSplitPacket.totalSize = 0;
|
||||
|
||||
// clear part's sequence
|
||||
for (int i = 0; i < MAX_SPLIT_FRAGMENTS; i++)
|
||||
netSplitFlags[i] = -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned int packetPayloadSize = size - sizeof(SPLITPACKET);
|
||||
@ -310,16 +318,47 @@ int NetSocket::GetLong(unsigned char *pData, int size)
|
||||
m_NetSplitPacket.totalSize = packetPayloadSize + SPLIT_SIZE * (packetCount - 1);
|
||||
}
|
||||
|
||||
--m_NetSplitPacket.splitCount;
|
||||
m_NetSplitPacket.splitCount--;
|
||||
netSplitFlags[packetNumber] = sequenceNumber;
|
||||
|
||||
#ifdef HLTV_FIXES
|
||||
if (SPLIT_SIZE * packetNumber + packetPayloadSize > MAX_UDP_PACKET)
|
||||
{
|
||||
m_System->DPrintf("WARNING! NetSocket::GetLong: Malformed packet size (%i, %i)\n", SPLIT_SIZE * packetNumber, packetPayloadSize);
|
||||
m_NetSplitPacket.currentSequence = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
Q_memcpy(&m_NetSplitPacket.buffer[SPLIT_SIZE * packetNumber], pHeader + 1, packetPayloadSize);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#ifndef HLTV_FIXES
|
||||
Q_memcpy(&m_NetSplitPacket.buffer[SPLIT_SIZE * packetNumber], pHeader + 1, packetPayloadSize);
|
||||
#endif
|
||||
|
||||
if (m_NetSplitPacket.splitCount > 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HLTV_FIXES
|
||||
for (unsigned int i = 0; i < packetCount; i++)
|
||||
{
|
||||
if (netSplitFlags[i] != m_NetSplitPacket.currentSequence)
|
||||
{
|
||||
m_System->DPrintf("WARNING! NetSocket::GetLong: Split packet without all %i parts, part %i had wrong sequence %i/%i\n",
|
||||
packetCount,
|
||||
i + 1,
|
||||
netSplitFlags[i],
|
||||
m_NetSplitPacket.currentSequence);
|
||||
|
||||
m_NetSplitPacket.currentSequence = -1;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
m_NetSplitPacket.currentSequence = -1;
|
||||
if (m_NetSplitPacket.totalSize > MAX_UDP_PACKET)
|
||||
{
|
||||
|
@ -252,11 +252,11 @@ protected:
|
||||
|
||||
int m_MaxInstanced_BaseLine;
|
||||
|
||||
#ifdef HOOK_HLTV
|
||||
char m_Lightstyles[MAX_LIGHTSTYLES][65];
|
||||
#else
|
||||
#if defined(HLTV_FIXES) && !defined(HOOK_HLTV)
|
||||
char m_Lightstyles[MAX_LIGHTSTYLES][64];
|
||||
#endif // HOOK_HLTV
|
||||
#else
|
||||
char m_Lightstyles[MAX_LIGHTSTYLES][65];
|
||||
#endif
|
||||
|
||||
movevars_t m_MoveVars;
|
||||
BSPModel m_WorldModel;
|
||||
|
@ -16,7 +16,7 @@ void setupToolchain(NativeBinarySpec b) {
|
||||
boolean useGcc = project.hasProperty("useGcc")
|
||||
def cfg = rootProject.createToolchainConfig(b);
|
||||
cfg.projectInclude(project, '/..', '/../..', '/src', '/../common', '/../../common', '/../../engine', '/../../public', '/../../public/rehlds', '/../../pm_shared');
|
||||
cfg.singleDefines 'USE_BREAKPAD_HANDLER', 'HLTV', 'DEMOPLAYER_MODULE'
|
||||
cfg.singleDefines 'USE_BREAKPAD_HANDLER', 'HLTV', 'HLTV_FIXES', 'DEMOPLAYER_MODULE'
|
||||
|
||||
if (cfg instanceof MsvcToolchainConfig) {
|
||||
cfg.compilerOptions.pchConfig = new MsvcToolchainConfig.PrecompiledHeadersConfig(
|
||||
|
@ -125,7 +125,7 @@
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>HLTV;WIN32;_DEBUG;_WINDOWS;_USRDLL;DEMOPLAYER_MODULE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>HLTV;HLTV_FIXES;WIN32;_DEBUG;_WINDOWS;_USRDLL;DEMOPLAYER_MODULE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeaderFile>precompiled.h</PrecompiledHeaderFile>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)\..\src;$(ProjectDir)\..\..\;$(ProjectDir)\..\..\..\;$(ProjectDir)\..\..\..\common;$(ProjectDir)\..\..\..\engine;$(ProjectDir)\..\..\..\public;$(ProjectDir)\..\..\..\public\rehlds;$(ProjectDir)\..\..\..\pm_shared;$(ProjectDir)\..\..\..\game_shared;$(ProjectDir)\..\..\..\..\dep\bzip2\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
@ -155,7 +155,7 @@
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>HLTV;WIN32;NDEBUG;_WINDOWS;_USRDLL;DEMOPLAYER_MODULE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitiHOOons)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>HLTV;HLTV_FIXES;WIN32;NDEBUG;_WINDOWS;_USRDLL;DEMOPLAYER_MODULE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitiHOOons)</PreprocessorDefinitions>
|
||||
<PrecompiledHeaderFile>precompiled.h</PrecompiledHeaderFile>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)\..\src;$(ProjectDir)\..\..\;$(ProjectDir)\..\..\..\;$(ProjectDir)\..\..\..\common;$(ProjectDir)\..\..\..\engine;$(ProjectDir)\..\..\..\public;$(ProjectDir)\..\..\..\public\rehlds;$(ProjectDir)\..\..\..\pm_shared;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
|
@ -16,7 +16,7 @@ void setupToolchain(NativeBinarySpec b) {
|
||||
boolean useGcc = project.hasProperty("useGcc")
|
||||
def cfg = rootProject.createToolchainConfig(b);
|
||||
cfg.projectInclude(project, '/..', '/../..', '/src', '/../../common', '/../../engine', '/../../public', '/../../public/rehlds', '/../../pm_shared');
|
||||
cfg.singleDefines 'USE_BREAKPAD_HANDLER', 'HLTV', 'DIRECTOR_MODULE'
|
||||
cfg.singleDefines 'USE_BREAKPAD_HANDLER', 'HLTV', 'HLTV_FIXES', 'DIRECTOR_MODULE'
|
||||
|
||||
if (cfg instanceof MsvcToolchainConfig) {
|
||||
cfg.compilerOptions.pchConfig = new MsvcToolchainConfig.PrecompiledHeadersConfig(
|
||||
|
@ -76,7 +76,7 @@
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>HLTV;WIN32;_DEBUG;_WINDOWS;_USRDLL;DIRECTOR_MODULE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>HLTV;HLTV_FIXES;WIN32;_DEBUG;_WINDOWS;_USRDLL;DIRECTOR_MODULE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)\..\..\;$(ProjectDir)\..\src;$(ProjectDir)\..\..\..\common;$(ProjectDir)\..\..\..\engine;$(ProjectDir)\..\..\..\public;$(ProjectDir)\..\..\..\public\rehlds;$(ProjectDir)\..\..\..\pm_shared;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PrecompiledHeaderFile>precompiled.h</PrecompiledHeaderFile>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
@ -107,7 +107,7 @@
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>HLTV;WIN32;NDEBUG;_WINDOWS;_USRDLL;DIRECTOR_MODULE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>HLTV;HLTV_FIXES;WIN32;NDEBUG;_WINDOWS;_USRDLL;DIRECTOR_MODULE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)\..\..\;$(ProjectDir)\..\src;$(ProjectDir)\..\..\..\common;$(ProjectDir)\..\..\..\engine;$(ProjectDir)\..\..\..\public;$(ProjectDir)\..\..\..\public\rehlds;$(ProjectDir)\..\..\..\pm_shared;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PrecompiledHeaderFile>precompiled.h</PrecompiledHeaderFile>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
|
@ -16,11 +16,12 @@ project.ext.dep_bzip2 = project(':dep/bzip2')
|
||||
|
||||
void setupToolchain(NativeBinarySpec b) {
|
||||
boolean useGcc = project.hasProperty("useGcc")
|
||||
|
||||
def cfg = rootProject.createToolchainConfig(b);
|
||||
cfg.projectInclude(project, '/..', '/../..', '/src', '/../Director/src', '/../../common', '/../../engine', '/../../public', '/../../public/rehlds', '/../../pm_shared');
|
||||
cfg.projectInclude(dep_bzip2, '/include')
|
||||
|
||||
cfg.singleDefines 'USE_BREAKPAD_HANDLER', 'HLTV', 'CORE_MODULE'
|
||||
cfg.singleDefines 'USE_BREAKPAD_HANDLER', 'HLTV', 'HLTV_FIXES', 'PROXY_MODULE'
|
||||
|
||||
if (cfg instanceof MsvcToolchainConfig) {
|
||||
cfg.compilerOptions.pchConfig = new MsvcToolchainConfig.PrecompiledHeadersConfig(
|
||||
|
@ -384,7 +384,7 @@
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>HLTV;WIN32;_DEBUG;_WINDOWS;_USRDLL;PROXY_MODULE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>HLTV;HLTV_FIXES;WIN32;_DEBUG;_WINDOWS;_USRDLL;PROXY_MODULE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)\..\src;$(ProjectDir)\..\..\;$(ProjectDir)\..\..\..\;$(ProjectDir)\..\..\Director\src;$(ProjectDir)\..\..\..\common;$(ProjectDir)\..\..\..\engine;$(ProjectDir)\..\..\..\public;$(ProjectDir)\..\..\..\public\rehlds;$(ProjectDir)\..\..\..\pm_shared;$(ProjectDir)\..\..\..\..\dep\bzip2\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PrecompiledHeaderFile>precompiled.h</PrecompiledHeaderFile>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
@ -418,7 +418,7 @@
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>HLTV;WIN32;NDEBUG;_WINDOWS;_USRDLL;PROXY_MODULE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>HLTV;HLTV_FIXES;WIN32;NDEBUG;_WINDOWS;_USRDLL;PROXY_MODULE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)\..\src;$(ProjectDir)\..\..\;$(ProjectDir)\..\..\..\;$(ProjectDir)\..\..\Director\src;$(ProjectDir)\..\..\..\common;$(ProjectDir)\..\..\..\engine;$(ProjectDir)\..\..\..\public;$(ProjectDir)\..\..\..\public\rehlds;$(ProjectDir)\..\..\..\pm_shared;$(ProjectDir)\..\..\..\..\dep\bzip2\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PrecompiledHeaderFile>precompiled.h</PrecompiledHeaderFile>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
|
@ -69,7 +69,7 @@ const uint32 INVBITTABLE[] =
|
||||
|
||||
BitBuffer::BitBuffer() : m_Data(nullptr),
|
||||
m_CurByte(nullptr),
|
||||
m_CurSize(0),
|
||||
m_CurBit(0),
|
||||
m_MaxSize(0),
|
||||
m_Overflowed(false),
|
||||
m_LittleEndian(false),
|
||||
@ -83,7 +83,7 @@ BitBuffer::BitBuffer(void *newData, unsigned int size)
|
||||
m_Data = (unsigned char *)newData;
|
||||
m_CurByte = m_Data;
|
||||
|
||||
m_CurSize = 0;
|
||||
m_CurBit = 0;
|
||||
m_MaxSize = size;
|
||||
m_Overflowed = false;
|
||||
m_LittleEndian = true;
|
||||
@ -100,7 +100,7 @@ BitBuffer::BitBuffer(unsigned int size)
|
||||
m_Data = nullptr;
|
||||
m_CurByte = nullptr;
|
||||
|
||||
m_CurSize = 0;
|
||||
m_CurBit = 0;
|
||||
m_MaxSize = size;
|
||||
m_Overflowed = false;
|
||||
m_LittleEndian = false;
|
||||
@ -114,7 +114,7 @@ bool BitBuffer::Resize(unsigned int size)
|
||||
Free();
|
||||
|
||||
m_Data = (unsigned char *)Mem_ZeroMalloc(size + 4);
|
||||
m_CurSize = 0;
|
||||
m_CurBit = 0;
|
||||
m_Overflowed = false;
|
||||
|
||||
if (m_Data)
|
||||
@ -139,7 +139,7 @@ void BitBuffer::Clear()
|
||||
Q_memset(m_Data, 0, m_MaxSize);
|
||||
|
||||
m_CurByte = m_Data;
|
||||
m_CurSize = 0;
|
||||
m_CurBit = 0;
|
||||
|
||||
m_Overflowed = false;
|
||||
m_LittleEndian = true;
|
||||
@ -147,13 +147,13 @@ void BitBuffer::Clear()
|
||||
|
||||
int BitBuffer::CurrentBit()
|
||||
{
|
||||
return m_CurSize + 8 * (m_CurByte - m_Data);
|
||||
return m_CurBit + 8 * (m_CurByte - m_Data);
|
||||
}
|
||||
|
||||
void BitBuffer::Reset()
|
||||
{
|
||||
m_CurByte = m_Data;
|
||||
m_CurSize = 0;
|
||||
m_CurBit = 0;
|
||||
|
||||
m_Overflowed = false;
|
||||
m_LittleEndian = true;
|
||||
@ -168,7 +168,7 @@ void BitBuffer::Free()
|
||||
m_Data = nullptr;
|
||||
m_CurByte = nullptr;
|
||||
|
||||
m_CurSize = 0;
|
||||
m_CurBit = 0;
|
||||
m_MaxSize = 0;
|
||||
|
||||
m_OwnData = false;
|
||||
@ -187,26 +187,26 @@ unsigned int BitBuffer::ReadBits(int numbits)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int bits = m_CurSize + numbits;
|
||||
int bits = m_CurBit + numbits;
|
||||
if (bits <= 32)
|
||||
{
|
||||
result = (*(unsigned int *)m_CurByte >> m_CurSize) & ROWBITTABLE[numbits];
|
||||
result = (*(unsigned int *)m_CurByte >> m_CurBit) & ROWBITTABLE[numbits];
|
||||
|
||||
m_CurByte += numbits >> 3;
|
||||
m_CurSize += numbits & 7;
|
||||
m_CurBit += numbits & 7;
|
||||
|
||||
if (m_CurSize > 7)
|
||||
if (m_CurBit > 7)
|
||||
{
|
||||
m_CurSize &= 7;
|
||||
m_CurBit &= 7;
|
||||
m_CurByte++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int data = *(unsigned int *)m_CurByte >> m_CurSize;
|
||||
unsigned int data = *(unsigned int *)m_CurByte >> m_CurBit;
|
||||
m_CurByte += 4;
|
||||
result = ((ROWBITTABLE[bits & 7] & *(unsigned int *)m_CurByte) << (32 - m_CurSize)) | data;
|
||||
m_CurSize = bits & 7;
|
||||
result = ((ROWBITTABLE[bits & 7] & *(unsigned int *)m_CurByte) << (32 - m_CurBit)) | data;
|
||||
m_CurBit = bits & 7;
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -235,26 +235,26 @@ int BitBuffer::ReadBit()
|
||||
{
|
||||
if (m_LittleEndian)
|
||||
{
|
||||
if (m_CurSize == 7)
|
||||
if (m_CurBit == 7)
|
||||
{
|
||||
m_CurSize = 0;
|
||||
m_CurBit = 0;
|
||||
result = (*m_CurByte++ >> 7) & 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = ((unsigned int)*m_CurByte >> m_CurSize++) & 1;
|
||||
result = ((unsigned int)*m_CurByte >> m_CurBit++) & 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_CurSize == 7)
|
||||
if (m_CurBit == 7)
|
||||
{
|
||||
m_CurSize = 0;
|
||||
m_CurBit = 0;
|
||||
result = *m_CurByte++ & 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = ((unsigned int)*m_CurByte >> (7 - m_CurSize++)) & 1;
|
||||
result = ((unsigned int)*m_CurByte >> (7 - m_CurBit++)) & 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -264,11 +264,11 @@ int BitBuffer::ReadBit()
|
||||
|
||||
unsigned int BitBuffer::PeekBits(int numbits)
|
||||
{
|
||||
int oldcurrentBit = m_CurSize;
|
||||
int oldcurrentBit = m_CurBit;
|
||||
unsigned char *oldcurrentByte = m_CurByte;
|
||||
unsigned int data = ReadBits(numbits);
|
||||
|
||||
m_CurSize = oldcurrentBit;
|
||||
m_CurBit = oldcurrentBit;
|
||||
m_CurByte = oldcurrentByte;
|
||||
return data;
|
||||
}
|
||||
@ -316,7 +316,7 @@ bool BitBuffer::ReadBuf(int iSize, void *pbuf)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_CurSize)
|
||||
if (m_CurBit)
|
||||
{
|
||||
int i, j;
|
||||
unsigned int *p = (unsigned int *)pbuf;
|
||||
@ -402,7 +402,7 @@ void BitBuffer::WriteBit(int c)
|
||||
|
||||
if (m_LittleEndian)
|
||||
{
|
||||
if (m_CurSize == 7)
|
||||
if (m_CurBit == 7)
|
||||
{
|
||||
if (c)
|
||||
{
|
||||
@ -414,20 +414,20 @@ void BitBuffer::WriteBit(int c)
|
||||
}
|
||||
|
||||
m_CurByte++;
|
||||
m_CurSize = 0;
|
||||
m_CurBit = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (c)
|
||||
{
|
||||
m_CurByte[0] |= BITTABLE[ m_CurSize ];
|
||||
m_CurByte[0] |= BITTABLE[ m_CurBit ];
|
||||
}
|
||||
else
|
||||
{
|
||||
m_CurByte[0] &= INVBITTABLE[ m_CurSize ];
|
||||
m_CurByte[0] &= INVBITTABLE[ m_CurBit ];
|
||||
}
|
||||
|
||||
m_CurSize++;
|
||||
m_CurBit++;
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -436,13 +436,13 @@ void BitBuffer::WriteBit(int c)
|
||||
static unsigned char inv_masks[] = { 0x7Fu, 0xBFu, 0xDFu, 0xEFu, 0xF7u, 0xFBu, 0xFDu, 0xFEu };
|
||||
|
||||
if (c)
|
||||
m_CurByte[0] |= masks[ m_CurSize ];
|
||||
m_CurByte[0] |= masks[ m_CurBit ];
|
||||
else
|
||||
m_CurByte[0] &= inv_masks[ m_CurSize ];
|
||||
m_CurByte[0] &= inv_masks[ m_CurBit ];
|
||||
|
||||
if (++m_CurSize == 8)
|
||||
if (++m_CurBit == 8)
|
||||
{
|
||||
m_CurSize = 0;
|
||||
m_CurBit = 0;
|
||||
m_CurByte++;
|
||||
}
|
||||
}
|
||||
@ -461,26 +461,26 @@ void BitBuffer::WriteBits(unsigned int data, int numbits)
|
||||
return;
|
||||
}
|
||||
|
||||
int bits = numbits + m_CurSize;
|
||||
int bits = numbits + m_CurBit;
|
||||
if (bits <= 32)
|
||||
{
|
||||
*(uint32 *)m_CurByte |= (ROWBITTABLE[numbits] & data) << m_CurSize;
|
||||
*(uint32 *)m_CurByte |= (ROWBITTABLE[numbits] & data) << m_CurBit;
|
||||
|
||||
m_CurByte = &m_CurByte[numbits >> 3];
|
||||
m_CurSize = m_CurSize + (numbits & 7);
|
||||
m_CurBit = m_CurBit + (numbits & 7);
|
||||
|
||||
if (m_CurSize > 7)
|
||||
if (m_CurBit > 7)
|
||||
{
|
||||
m_CurSize = m_CurSize & 7;
|
||||
m_CurBit = m_CurBit & 7;
|
||||
m_CurByte = m_CurByte + 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*(uint32 *)m_CurByte |= (ROWBITTABLE[numbits] & data) << m_CurSize;
|
||||
*(uint32 *)m_CurByte |= (ROWBITTABLE[numbits] & data) << m_CurBit;
|
||||
|
||||
int leftBits = (32 - m_CurSize);
|
||||
m_CurSize = (m_CurSize + numbits) & 7;
|
||||
int leftBits = (32 - m_CurBit);
|
||||
m_CurBit = (m_CurBit + numbits) & 7;
|
||||
|
||||
m_CurByte += 4;
|
||||
*(uint32 *)m_CurByte |= (ROWBITTABLE[numbits] & data) >> leftBits;
|
||||
@ -581,7 +581,7 @@ void BitBuffer::WriteBuf(const void *buf, int iSize)
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_CurSize)
|
||||
if (m_CurBit)
|
||||
{
|
||||
int i, j;
|
||||
unsigned int *p = (unsigned int *)buf;
|
||||
@ -623,7 +623,7 @@ void BitBuffer::WriteHiresAngle(float f)
|
||||
|
||||
int BitBuffer::CurrentSize()
|
||||
{
|
||||
return (m_CurSize != 0) + m_CurByte - m_Data;
|
||||
return (m_CurBit != 0) + m_CurByte - m_Data;
|
||||
}
|
||||
|
||||
unsigned char *BitBuffer::CurrentByte()
|
||||
@ -638,10 +638,10 @@ int BitBuffer::SpaceLeft()
|
||||
|
||||
void BitBuffer::AlignByte()
|
||||
{
|
||||
if (m_CurSize)
|
||||
if (m_CurBit)
|
||||
{
|
||||
m_CurByte++;
|
||||
m_CurSize = 0;
|
||||
m_CurBit = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -712,7 +712,7 @@ void BitBuffer::WriteBitString(const char *p)
|
||||
|
||||
void BitBuffer::StartBitMode()
|
||||
{
|
||||
if (m_CurSize) {
|
||||
if (m_CurBit) {
|
||||
m_Overflowed = true;
|
||||
}
|
||||
}
|
||||
@ -739,7 +739,7 @@ void BitBuffer::SetBuffer(void *buffer, int size)
|
||||
m_Data = (unsigned char *)buffer;
|
||||
m_CurByte = (unsigned char *)buffer;
|
||||
m_MaxSize = size;
|
||||
m_CurSize = 0;
|
||||
m_CurBit = 0;
|
||||
|
||||
m_OwnData = false;
|
||||
m_Overflowed = false;
|
||||
@ -811,22 +811,22 @@ void BitBuffer::SkipBits(int numbits)
|
||||
return;
|
||||
}
|
||||
|
||||
int bits = m_CurSize + numbits;
|
||||
int bits = m_CurBit + numbits;
|
||||
if (bits <= 32)
|
||||
{
|
||||
m_CurByte += numbits >> 3;
|
||||
m_CurSize += numbits & 7;
|
||||
m_CurBit += numbits & 7;
|
||||
|
||||
if (m_CurSize > 7)
|
||||
if (m_CurBit > 7)
|
||||
{
|
||||
m_CurSize &= 7;
|
||||
m_CurBit &= 7;
|
||||
m_CurByte++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_CurByte += 4;
|
||||
m_CurSize = bits & 7;
|
||||
m_CurBit = bits & 7;
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -835,14 +835,14 @@ void BitBuffer::SkipBits(int numbits)
|
||||
while (d > 0)
|
||||
{
|
||||
--d;
|
||||
if (m_CurSize == 7)
|
||||
if (m_CurBit == 7)
|
||||
{
|
||||
m_CurByte++;
|
||||
m_CurSize = 0;
|
||||
m_CurBit = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_CurSize++;
|
||||
m_CurBit++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -870,7 +870,7 @@ void BitBuffer::FastClear()
|
||||
Q_memset(m_Data, 0, iSize);
|
||||
|
||||
m_CurByte = m_Data;
|
||||
m_CurSize = 0;
|
||||
m_CurBit = 0;
|
||||
|
||||
m_Overflowed = false;
|
||||
m_LittleEndian = true;
|
||||
|
@ -41,7 +41,6 @@ public:
|
||||
unsigned char *CurrentByte();
|
||||
|
||||
int GetMaxSize() const { return m_MaxSize; }
|
||||
unsigned int GetCurSize() const { return m_CurSize; }
|
||||
unsigned char *GetData() const { return m_Data; }
|
||||
bool IsOverflowed() const { return m_Overflowed; }
|
||||
|
||||
@ -108,7 +107,7 @@ public:
|
||||
bool m_Overflowed;
|
||||
unsigned char *m_Data;
|
||||
unsigned char *m_CurByte;
|
||||
int m_CurSize;
|
||||
int m_CurBit;
|
||||
int m_MaxSize;
|
||||
|
||||
protected:
|
||||
|
@ -81,7 +81,7 @@ bool InfoString::SetString(char *string)
|
||||
return false;
|
||||
}
|
||||
|
||||
Q_strnlcpy(m_String, string, m_MaxSize);
|
||||
Q_strlcpy(m_String, string, m_MaxSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -95,7 +95,7 @@ void InfoString::SetMaxSize(unsigned int maxSize)
|
||||
if (m_String)
|
||||
{
|
||||
if (maxSize > Q_strlen(m_String)) {
|
||||
Q_strnlcpy(newBuffer, m_String, maxSize);
|
||||
Q_strlcpy(newBuffer, m_String, maxSize);
|
||||
}
|
||||
|
||||
Mem_Free(m_String);
|
||||
|
@ -310,7 +310,12 @@ void NetChannel::UpdateFlow(int stream)
|
||||
|
||||
void NetChannel::TransmitOutgoing()
|
||||
{
|
||||
#ifdef HLTV_FIXES
|
||||
byte send_buf[MAX_UDP_PACKET];
|
||||
#else
|
||||
byte send_buf[NET_MAX_MESSAGE];
|
||||
#endif
|
||||
|
||||
BitBuffer data(send_buf, sizeof(send_buf));
|
||||
|
||||
bool send_reliable;
|
||||
@ -336,7 +341,7 @@ void NetChannel::TransmitOutgoing()
|
||||
// check for reliable message overflow
|
||||
if (m_reliableStream.IsOverflowed())
|
||||
{
|
||||
m_System->DPrintf("Transmit:Outgoing m_reliableStream overflow (%s)\n", m_remote_address.ToString());
|
||||
m_System->DPrintf("NetChannel::Transmit:Outgoing m_reliableStream overflow (%s)\n", m_remote_address.ToString());
|
||||
m_reliableStream.Clear();
|
||||
return;
|
||||
}
|
||||
@ -344,7 +349,7 @@ void NetChannel::TransmitOutgoing()
|
||||
// check for unreliable message overflow
|
||||
if (m_unreliableStream.IsOverflowed())
|
||||
{
|
||||
m_System->DPrintf("Transmit:Outgoing m_unreliableStream overflow (%s)\n", m_remote_address.ToString());
|
||||
m_System->DPrintf("NetChannel::Transmit:Outgoing m_unreliableStream overflow (%s)\n", m_remote_address.ToString());
|
||||
m_unreliableStream.Clear();
|
||||
}
|
||||
|
||||
@ -653,6 +658,46 @@ bool NetChannel::CheckForCompletion(int stream, int intotalbuffers)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NetChannel::ValidateFragments(BitBuffer &buf, bool *frag_message, unsigned int *fragid, int *frag_offset, int *frag_length)
|
||||
{
|
||||
for (int i = 0; i < MAX_STREAMS; i++)
|
||||
{
|
||||
if (!frag_message[i])
|
||||
continue;
|
||||
|
||||
// total fragments should be <= MAX_FRAGMENTS and current fragment can't be > total fragments
|
||||
if (i == FRAG_NORMAL_STREAM && FRAG_GETCOUNT(fragid[i]) > MAX_NORMAL_FRAGMENTS)
|
||||
return false;
|
||||
|
||||
if (i == FRAG_FILE_STREAM && FRAG_GETCOUNT(fragid[i]) > MAX_FILE_FRAGMENTS)
|
||||
return false;
|
||||
|
||||
if (FRAG_GETID(fragid[i]) > FRAG_GETCOUNT(fragid[i]))
|
||||
return false;
|
||||
|
||||
if (!frag_length[i])
|
||||
return false;
|
||||
|
||||
if ((size_t)frag_length[i] > FRAGMENT_MAX_SIZE || (size_t)frag_offset[i] > MAX_POSSIBLE_MSG - 1)
|
||||
return false;
|
||||
|
||||
int frag_end = frag_offset[i] + frag_length[i];
|
||||
|
||||
// end of fragment is out of the packet
|
||||
if (frag_end + buf.CurrentSize() > buf.GetMaxSize())
|
||||
return false;
|
||||
|
||||
// fragment overlaps next stream's fragment or placed after it
|
||||
for (int j = i + 1; j < MAX_STREAMS; j++)
|
||||
{
|
||||
if (frag_end > frag_offset[j] && frag_message[j]) // don't add buf.CurrentSize() for comparison
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetChannel::ProcessIncoming(unsigned char *data, int size)
|
||||
{
|
||||
BitBuffer message(data, size);
|
||||
@ -721,6 +766,11 @@ void NetChannel::ProcessIncoming(unsigned char *data, int size)
|
||||
frag_length[i] = message.ReadShort();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HLTV_FIXES
|
||||
if (!ValidateFragments(message, frag_message, fragid, frag_offset, frag_length))
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
sequence &= ~(1 << 31);
|
||||
@ -758,7 +808,12 @@ void NetChannel::ProcessIncoming(unsigned char *data, int size)
|
||||
// clear the buffer to make way for the next
|
||||
if (reliable_ack == (unsigned int)m_reliable_sequence)
|
||||
{
|
||||
// Make sure we actually could have ack'd this message
|
||||
#ifdef HLTV_FIXES
|
||||
if (sequence_ack >= (unsigned)m_last_reliable_sequence)
|
||||
#else
|
||||
if (m_incoming_acknowledged + 1 >= m_last_reliable_sequence)
|
||||
#endif
|
||||
{
|
||||
// it has been received
|
||||
m_reliableOutSize = 0;
|
||||
@ -1104,6 +1159,24 @@ void NetChannel::CopyNormalFragments()
|
||||
p = n;
|
||||
}
|
||||
|
||||
#ifdef HLTV_FIXES
|
||||
if (packet->data.IsOverflowed())
|
||||
{
|
||||
if (packet->address.IsValid())
|
||||
{
|
||||
m_System->Printf("WARNING! NetChannel::CopyNormalFragments: Incoming overflowed from %s\n", packet->address.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_System->Printf("WARNING! NetChannel::CopyNormalFragments: Incoming overflowed\n");
|
||||
}
|
||||
|
||||
packet->data.Clear();
|
||||
m_incomingbufs[FRAG_NORMAL_STREAM] = nullptr;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (*(uint32 *)packet->data.GetData() == MAKEID('B', 'Z', '2', '\0'))
|
||||
{
|
||||
char uncompressed[65536];
|
||||
|
@ -51,32 +51,41 @@ enum
|
||||
MAX_FLOWS
|
||||
};
|
||||
|
||||
#define MAX_LATENT 32
|
||||
#define FRAGMENT_MAX_SIZE 1400 // Size of fragmentation buffer internal buffers
|
||||
#define MAX_LATENT 32
|
||||
#define FRAGMENT_MAX_SIZE 1400 // Size of fragmentation buffer internal buffers
|
||||
#define CLIENT_FRAGMENT_SIZE_ONCONNECT 128
|
||||
#define CUSTOMIZATION_MAX_SIZE 20480
|
||||
|
||||
#define UDP_HEADER_SIZE 28
|
||||
#define MAX_RELIABLE_PAYLOAD 1200
|
||||
// Client sends normal fragments only while connecting
|
||||
#define MAX_NORMAL_FRAGMENTS (MAX_POSSIBLE_MSG / CLIENT_FRAGMENT_SIZE_ONCONNECT)
|
||||
|
||||
#define MAKE_FRAGID(id, count) (((id & 0xffff) << 16) | (count & 0xffff))
|
||||
#define FRAG_GETID(fragid) ((fragid >> 16) & 0xffff)
|
||||
#define FRAG_GETCOUNT(fragid) (fragid & 0xffff)
|
||||
// While client is connecting it sending fragments with minimal size, also it transfers sprays with minimal fragments...
|
||||
// But with sv_delayed_spray_upload it sends with cl_dlmax fragment size
|
||||
#define MAX_FILE_FRAGMENTS (CUSTOMIZATION_MAX_SIZE / FRAGMENT_C2S_MIN_SIZE)
|
||||
|
||||
#define UDP_HEADER_SIZE 28
|
||||
#define MAX_RELIABLE_PAYLOAD 1200
|
||||
|
||||
#define MAKE_FRAGID(id, count) (((id & 0xffff) << 16) | (count & 0xffff))
|
||||
#define FRAG_GETID(fragid) ((fragid >> 16) & 0xffff)
|
||||
#define FRAG_GETCOUNT(fragid) (fragid & 0xffff)
|
||||
|
||||
// Max length of a reliable message
|
||||
#define MAX_MSGLEN 3990 // 10 reserved for fragheader?
|
||||
#define MAX_POSSIBLE_MSG 65536
|
||||
#define MAX_MSGLEN 3990 // 10 reserved for fragheader?
|
||||
#define MAX_POSSIBLE_MSG 65536
|
||||
|
||||
#define MAX_ROUTEABLE_PACKET 1400
|
||||
#define MIN_ROUTEABLE_PACKET 16
|
||||
#define MAX_ROUTEABLE_PACKET 1400
|
||||
#define MIN_ROUTEABLE_PACKET 16
|
||||
|
||||
#define SPLIT_SIZE (MAX_ROUTEABLE_PACKET - sizeof(SPLITPACKET))
|
||||
#define SPLIT_SIZE (MAX_ROUTEABLE_PACKET - sizeof(SPLITPACKET))
|
||||
|
||||
// Pad this to next higher 16 byte boundary
|
||||
// This is the largest packet that can come in/out over the wire, before processing the header
|
||||
// bytes will be stripped by the networking channel layer
|
||||
// #define NET_MAX_MESSAGE PAD_NUMBER( ( MAX_MSGLEN + HEADER_BYTES ), 16 )
|
||||
// This is currently used value in the engine. TODO: define above gives 4016, check it why.
|
||||
#define NET_MAX_MESSAGE 4037
|
||||
#define NET_HEADER_FLAG_SPLITPACKET -2
|
||||
#define NET_MAX_MESSAGE 4037
|
||||
#define NET_HEADER_FLAG_SPLITPACKET -2
|
||||
|
||||
class IBaseSystem;
|
||||
|
||||
@ -116,7 +125,7 @@ public:
|
||||
typedef struct flowstats_s
|
||||
{
|
||||
int size; // Size of message sent/received
|
||||
double time; // Time that message was sent/received
|
||||
double time; // Time that message was sent/received
|
||||
} flowstats_t;
|
||||
|
||||
typedef struct flow_s
|
||||
@ -134,24 +143,25 @@ public:
|
||||
typedef struct fragbuf_s
|
||||
{
|
||||
struct fragbuf_s *next; // Next buffer in chain
|
||||
int bufferId; // Id of this buffer
|
||||
byte data[FRAGMENT_MAX_SIZE]; // The actual data sits here
|
||||
int bufferId; // Id of this buffer
|
||||
byte data[FRAGMENT_MAX_SIZE]; // The actual data sits here
|
||||
|
||||
int size; // Size of data to read at that offset
|
||||
bool isfile; // Is this a file buffer?
|
||||
bool isbuffer; // Is this file buffer from memory ( custom decal, etc. ).
|
||||
int size; // Size of data to read at that offset
|
||||
bool isfile; // Is this a file buffer?
|
||||
bool isbuffer; // Is this file buffer from memory ( custom decal, etc. ).
|
||||
char fileName[MAX_PATH]; // Name of the file to save out on remote host
|
||||
int fOffset; // Offset in file from which to read data
|
||||
int fOffset; // Offset in file from which to read data
|
||||
} fragbuf_t;
|
||||
|
||||
// Waiting list of fragbuf chains
|
||||
typedef struct fragbufwaiting_s
|
||||
{
|
||||
struct fragbufwaiting_s *next; // Next chain in waiting list
|
||||
int fragbufcount; // Number of buffers in this chain
|
||||
struct fragbufwaiting_s *next; // Next chain in waiting list
|
||||
int fragbufcount; // Number of buffers in this chain
|
||||
fragbuf_t *fragbufs; // The actual buffers
|
||||
} fragbufwaiting_t;
|
||||
|
||||
bool ValidateFragments(BitBuffer &buf, bool *frag_message, unsigned int *fragid, int *frag_offset, int *frag_length);
|
||||
bool CreateFragmentsFromFile(char *fileName);
|
||||
bool CopyFileFragments();
|
||||
void GetFlowStats(float *avgInKBSec, float *avgOutKBSec);
|
||||
@ -179,25 +189,25 @@ public:
|
||||
NetAddress m_remote_address; // Address this channel is talking to.
|
||||
double m_last_received;
|
||||
double m_last_send;
|
||||
double m_connect_time; // Time when channel was connected.
|
||||
double m_connect_time; // Time when channel was connected.
|
||||
float m_timeout;
|
||||
int m_max_bandwidth_rate;
|
||||
double m_send_interval;
|
||||
int m_updaterate; // Bandwidth choke, bytes per second
|
||||
double m_cleartime; // If realtime > cleartime, free to send next packet
|
||||
int m_updaterate; // Bandwidth choke, bytes per second
|
||||
double m_cleartime; // If realtime > cleartime, free to send next packet
|
||||
|
||||
bool m_keep_alive;
|
||||
bool m_crashed;
|
||||
bool m_connected;
|
||||
|
||||
// Sequencing variables
|
||||
int m_incoming_sequence; // Increasing count of sequence numbers
|
||||
int m_incoming_acknowledged; // # of last outgoing message that has been ack'd.
|
||||
int m_incoming_sequence; // Increasing count of sequence numbers
|
||||
int m_incoming_acknowledged; // # of last outgoing message that has been ack'd.
|
||||
int m_incoming_reliable_acknowledged; // Toggles T/F as reliable messages are received.
|
||||
int m_incoming_reliable_sequence; // single bit, maintained local
|
||||
int m_outgoing_sequence; // Message we are sending to remote
|
||||
int m_reliable_sequence; // Whether the message contains reliable payload, single bit
|
||||
int m_last_reliable_sequence; // Outgoing sequence number of last send that had reliable data
|
||||
int m_incoming_reliable_sequence; // single bit, maintained local
|
||||
int m_outgoing_sequence; // Message we are sending to remote
|
||||
int m_reliable_sequence; // Whether the message contains reliable payload, single bit
|
||||
int m_last_reliable_sequence; // Outgoing sequence number of last send that had reliable data
|
||||
|
||||
void *m_connection_status;
|
||||
|
||||
@ -216,11 +226,11 @@ public:
|
||||
int m_reliable_fragment[MAX_STREAMS]; // Is reliable waiting buf a fragment?
|
||||
size_t m_reliable_fragid[MAX_STREAMS]; // Buffer id for each waiting fragment
|
||||
|
||||
fragbuf_t *m_fragbufs[MAX_STREAMS]; // The current fragment being set
|
||||
int m_fragbufcount[MAX_STREAMS]; // The total number of fragments in this stream
|
||||
fragbuf_t *m_fragbufs[MAX_STREAMS]; // The current fragment being set
|
||||
int m_fragbufcount[MAX_STREAMS]; // The total number of fragments in this stream
|
||||
|
||||
int16 m_frag_startpos[MAX_STREAMS]; // Position in outgoing buffer where frag data starts
|
||||
int16 m_frag_length[MAX_STREAMS]; // Length of frag data in the buffer
|
||||
int16 m_frag_startpos[MAX_STREAMS]; // Position in outgoing buffer where frag data starts
|
||||
int16 m_frag_length[MAX_STREAMS]; // Length of frag data in the buffer
|
||||
|
||||
fragbuf_t *m_incomingbufs[MAX_STREAMS]; // Incoming fragments are stored here
|
||||
|
||||
|
@ -2365,17 +2365,56 @@ void Host_Version_f(void)
|
||||
|
||||
void Host_FullInfo_f(void)
|
||||
{
|
||||
char key[512];
|
||||
char value[512];
|
||||
char *o;
|
||||
char *s;
|
||||
|
||||
if (Cmd_Argc() != 2)
|
||||
{
|
||||
Con_Printf("fullinfo <complete info string>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef REHLDS_FIXES
|
||||
char copy[MAX_INFO_STRING];
|
||||
Q_strlcpy(copy, Cmd_Argv(1));
|
||||
|
||||
char* s = copy;
|
||||
if (*s != '\\')
|
||||
return;
|
||||
|
||||
bool eos = false;
|
||||
while (!eos) {
|
||||
const char* key = ++s;
|
||||
|
||||
// key
|
||||
while (*s != '\\')
|
||||
{
|
||||
// key should end with a '\', not a NULL
|
||||
if (*s == '\0') {
|
||||
Con_Printf("MISSING VALUE\n");
|
||||
return;
|
||||
}
|
||||
|
||||
s++;
|
||||
}
|
||||
|
||||
*s = '\0';
|
||||
const char* value = ++s;
|
||||
|
||||
// value
|
||||
while (*s != '\\') {
|
||||
if (*s == '\0') {
|
||||
eos = true;
|
||||
break;
|
||||
}
|
||||
|
||||
s++;
|
||||
}
|
||||
|
||||
*s = '\0';
|
||||
#else
|
||||
char key[512];
|
||||
char value[512];
|
||||
char *o;
|
||||
char *s;
|
||||
|
||||
s = (char *)Cmd_Argv(1);
|
||||
if (*s == '\\')
|
||||
s++;
|
||||
@ -2400,6 +2439,7 @@ void Host_FullInfo_f(void)
|
||||
*o = 0;
|
||||
if (*s)
|
||||
s++;
|
||||
#endif
|
||||
|
||||
if (cmd_source == src_command)
|
||||
{
|
||||
|
@ -31,10 +31,85 @@
|
||||
// NOTE: This file contains a lot of fixes that are not covered by REHLDS_FIXES define.
|
||||
// TODO: Most of the Info_ functions can be speedup via removing unneded copy of key and values.
|
||||
|
||||
struct info_field_t
|
||||
{
|
||||
char* name;
|
||||
bool integer;
|
||||
};
|
||||
|
||||
info_field_t g_info_important_fields[] =
|
||||
{
|
||||
// name integer
|
||||
{ "name", false },
|
||||
{ "model", false },
|
||||
|
||||
// model colors
|
||||
{ "topcolor", true },
|
||||
{ "bottomcolor", true },
|
||||
|
||||
// network
|
||||
{ "rate", true },
|
||||
{ "cl_updaterate", true },
|
||||
{ "cl_lw", true },
|
||||
{ "cl_lc", true },
|
||||
|
||||
// hltv flag
|
||||
{ "*hltv", true },
|
||||
|
||||
// avatars
|
||||
{ "*sid", false }, // transmit as string because it's int64
|
||||
|
||||
// gui/text menus
|
||||
{ "_vgui_menus", true }
|
||||
};
|
||||
|
||||
std::vector<info_field_t *> g_info_transmitted_fields;
|
||||
|
||||
// Searches the string for the given
|
||||
// key and returns the associated value, or an empty string.
|
||||
const char* EXT_FUNC Info_ValueForKey(const char *s, const char *key)
|
||||
const char* EXT_FUNC Info_ValueForKey(const char *s, const char *lookup)
|
||||
{
|
||||
#ifdef REHLDS_FIXES
|
||||
static char valueBuf[INFO_MAX_BUFFER_VALUES][MAX_KV_LEN];
|
||||
static int valueIndex;
|
||||
|
||||
size_t lookupLen = Q_strlen(lookup);
|
||||
while (*s == '\\')
|
||||
{
|
||||
// skip starting slash
|
||||
const char* key = ++s;
|
||||
|
||||
// skip key
|
||||
while (*s != '\\') {
|
||||
// Add some sanity checks because it's external function
|
||||
if (*s == '\0')
|
||||
return "";
|
||||
|
||||
s++;
|
||||
}
|
||||
|
||||
size_t keyLen = s - key;
|
||||
const char* value = ++s; // skip separating slash
|
||||
|
||||
// skip value
|
||||
while (*s != '\\' && *s != '\0')
|
||||
s++;
|
||||
|
||||
size_t valueLen = Q_min(s - value, MAX_KV_LEN - 1);
|
||||
|
||||
if (keyLen == lookupLen && !Q_strncmp(key, lookup, lookupLen))
|
||||
{
|
||||
char* dest = valueBuf[valueIndex];
|
||||
Q_memcpy(dest, value, valueLen);
|
||||
dest[valueLen] = '\0';
|
||||
|
||||
valueIndex = (valueIndex + 1) % INFO_MAX_BUFFER_VALUES;
|
||||
return dest;
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
#else
|
||||
// use few (two?) buffers so compares work without stomping on each other
|
||||
static char value[INFO_MAX_BUFFER_VALUES][MAX_KV_LEN];
|
||||
static int valueindex;
|
||||
@ -69,7 +144,7 @@ const char* EXT_FUNC Info_ValueForKey(const char *s, const char *key)
|
||||
*c = 0;
|
||||
s++; // skip the slash
|
||||
|
||||
// Copy a value
|
||||
// Copy a value
|
||||
nCount = 0;
|
||||
c = value[valueindex];
|
||||
while (*s != '\\')
|
||||
@ -88,7 +163,7 @@ const char* EXT_FUNC Info_ValueForKey(const char *s, const char *key)
|
||||
}
|
||||
*c = 0;
|
||||
|
||||
if (!Q_strcmp(key, pkey))
|
||||
if (!Q_strcmp(lookup, pkey))
|
||||
{
|
||||
c = value[valueindex];
|
||||
valueindex = (valueindex + 1) % INFO_MAX_BUFFER_VALUES;
|
||||
@ -97,10 +172,47 @@ const char* EXT_FUNC Info_ValueForKey(const char *s, const char *key)
|
||||
}
|
||||
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
|
||||
void Info_RemoveKey(char *s, const char *key)
|
||||
void Info_RemoveKey(char *s, const char *lookup)
|
||||
{
|
||||
#ifdef REHLDS_FIXES
|
||||
size_t lookupLen = Q_strlen(lookup);
|
||||
|
||||
while (*s == '\\')
|
||||
{
|
||||
char* start = s;
|
||||
|
||||
// skip starting slash
|
||||
const char* key = ++s;
|
||||
|
||||
// skip key
|
||||
while (*s != '\\') {
|
||||
if (*s == '\0')
|
||||
return;
|
||||
|
||||
s++;
|
||||
}
|
||||
|
||||
size_t keyLen = s - key;
|
||||
++s; // skip separating slash
|
||||
|
||||
// skip value
|
||||
while (*s != '\\' && *s != '\0')
|
||||
s++;
|
||||
|
||||
if (keyLen != lookupLen)
|
||||
continue;
|
||||
|
||||
if (!Q_memcmp(key, lookup, lookupLen))
|
||||
{
|
||||
// cut key and value
|
||||
Q_memmove(start, s, Q_strlen(s) + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
char pkey[MAX_KV_LEN];
|
||||
char value[MAX_KV_LEN];
|
||||
char *start;
|
||||
@ -108,13 +220,13 @@ void Info_RemoveKey(char *s, const char *key)
|
||||
int cmpsize;
|
||||
int nCount;
|
||||
|
||||
if (Q_strstr(key, "\\"))
|
||||
if (Q_strstr(lookup, "\\"))
|
||||
{
|
||||
Con_Printf("Can't use a key with a \\\n");
|
||||
return;
|
||||
}
|
||||
|
||||
cmpsize = Q_strlen(key);
|
||||
cmpsize = Q_strlen(lookup);
|
||||
if (cmpsize > MAX_KV_LEN - 1)
|
||||
cmpsize = MAX_KV_LEN - 1;
|
||||
|
||||
@ -168,16 +280,47 @@ void Info_RemoveKey(char *s, const char *key)
|
||||
*c = 0;
|
||||
|
||||
// Compare keys
|
||||
if (!Q_strncmp(key, pkey, cmpsize))
|
||||
if (!Q_strncmp(lookup, pkey, cmpsize))
|
||||
{
|
||||
Q_strcpy_s(start, s); // remove this part
|
||||
s = start; // continue searching
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Info_RemovePrefixedKeys(char *s, const char prefix)
|
||||
{
|
||||
#ifdef REHLDS_FIXES
|
||||
while (*s == '\\')
|
||||
{
|
||||
char* start = s;
|
||||
|
||||
// skip starting slash
|
||||
const char* key = ++s;
|
||||
|
||||
// skip key
|
||||
while (*s != '\\') {
|
||||
if (*s == '\0')
|
||||
return;
|
||||
|
||||
s++;
|
||||
}
|
||||
|
||||
// skip separating slash
|
||||
++s;
|
||||
|
||||
// skip value
|
||||
while (*s != '\\' && *s != '\0')
|
||||
s++;
|
||||
|
||||
if (key[0] == prefix)
|
||||
{
|
||||
Q_memmove(start, s, Q_strlen(s) + 1);
|
||||
s = start;
|
||||
}
|
||||
}
|
||||
#else
|
||||
char pkey[MAX_KV_LEN];
|
||||
char value[MAX_KV_LEN];
|
||||
char *start;
|
||||
@ -239,12 +382,37 @@ void Info_RemovePrefixedKeys(char *s, const char prefix)
|
||||
s = start; // continue searching
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef REHLDS_FIXES
|
||||
qboolean Info_IsKeyImportant(const char *key)
|
||||
{
|
||||
if (key[0] == '*')
|
||||
return true;
|
||||
|
||||
for (auto& field : g_info_important_fields) {
|
||||
if (!Q_strcmp(key, field.name))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
qboolean Info_IsKeyImportant(const char *key, size_t keyLen)
|
||||
{
|
||||
char copy[MAX_KV_LEN];
|
||||
keyLen = min(keyLen, sizeof(copy) - 1);
|
||||
Q_memcpy(copy, key, keyLen);
|
||||
copy[keyLen] = '\0';
|
||||
return Info_IsKeyImportant(copy);
|
||||
}
|
||||
#else
|
||||
qboolean Info_IsKeyImportant(const char *key)
|
||||
{
|
||||
if (key[0] == '*')
|
||||
return true;
|
||||
|
||||
if (!Q_strcmp(key, "name"))
|
||||
return true;
|
||||
if (!Q_strcmp(key, "model"))
|
||||
@ -261,19 +429,53 @@ qboolean Info_IsKeyImportant(const char *key)
|
||||
return true;
|
||||
if (!Q_strcmp(key, "cl_lc"))
|
||||
return true;
|
||||
#ifndef REHLDS_FIXES
|
||||
// keys starts from '*' already checked
|
||||
if (!Q_strcmp(key, "*hltv"))
|
||||
return true;
|
||||
if (!Q_strcmp(key, "*sid"))
|
||||
return true;
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
char *Info_FindLargestKey(char *s, int maxsize)
|
||||
const char *Info_FindLargestKey(const char *s, int maxsize)
|
||||
{
|
||||
#ifdef REHLDS_FIXES
|
||||
static char largestKey[MAX_KV_LEN];
|
||||
size_t largestLen = 0;
|
||||
|
||||
while (*s == '\\')
|
||||
{
|
||||
// skip starting slash
|
||||
const char* key = ++s;
|
||||
|
||||
// skip key
|
||||
while (*s != '\\') {
|
||||
if (*s == '\0')
|
||||
return "";
|
||||
|
||||
s++;
|
||||
}
|
||||
|
||||
size_t keyLen = s - key;
|
||||
const char* value = ++s; // skip separating slash
|
||||
|
||||
// skip value
|
||||
while (*s != '\\' && *s != '\0')
|
||||
s++;
|
||||
|
||||
size_t valueLen = s - value;
|
||||
size_t totalLen = keyLen + valueLen;
|
||||
|
||||
if (totalLen > largestLen && !Info_IsKeyImportant(key, keyLen)) {
|
||||
largestLen = totalLen;
|
||||
Q_memcpy(largestKey, key, keyLen);
|
||||
largestKey[keyLen] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
return largestLen ? largestKey : "";
|
||||
#else
|
||||
static char largest_key[MAX_KV_LEN];
|
||||
char key[MAX_KV_LEN];
|
||||
char value[MAX_KV_LEN];
|
||||
@ -347,8 +549,104 @@ char *Info_FindLargestKey(char *s, int maxsize)
|
||||
}
|
||||
|
||||
return largest_key;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef REHLDS_FIXES
|
||||
qboolean Info_SetValueForStarKey(char *s, const char *key, const char *value, size_t maxsize)
|
||||
{
|
||||
char newArray[MAX_INFO_STRING], valueBuf[MAX_KV_LEN];
|
||||
|
||||
if (!key || !value)
|
||||
{
|
||||
Con_Printf("Keys and values can't be null\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (key[0] == '\0')
|
||||
{
|
||||
Con_Printf("Keys can't be an empty string\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (Q_strchr(key, '\\') || Q_strchr(value, '\\'))
|
||||
{
|
||||
Con_Printf("Can't use keys or values with a \\\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (Q_strchr(key, '\"') || Q_strchr(value, '\"'))
|
||||
{
|
||||
Con_Printf("Can't use keys or values with a \"\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (Q_strstr(key, "..") || Q_strstr(value, ".."))
|
||||
{
|
||||
Con_Printf("Can't use keys or values with a ..\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int keyLen = Q_strlen(key);
|
||||
int valueLen = Q_strlen(value);
|
||||
|
||||
if (keyLen >= MAX_KV_LEN || valueLen >= MAX_KV_LEN)
|
||||
{
|
||||
Con_Printf("Keys and values must be < %i characters\n", MAX_KV_LEN);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!Q_UnicodeValidate(key) || !Q_UnicodeValidate(value))
|
||||
{
|
||||
Con_Printf("Keys and values must be valid utf8 text\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Remove current key/value and return if we doesn't specified to set a value
|
||||
Info_RemoveKey(s, key);
|
||||
if (value[0] == '\0')
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// auto lowercase team
|
||||
if (!Q_strcmp(key, "team")) {
|
||||
value = Q_strcpy(valueBuf, value);
|
||||
Q_strlwr(valueBuf);
|
||||
}
|
||||
|
||||
// Create key/value pair
|
||||
size_t neededLength = Q_snprintf(newArray, sizeof newArray, "\\%s\\%s", key, value);
|
||||
|
||||
if (Q_strlen(s) + neededLength >= maxsize)
|
||||
{
|
||||
// no more room in the buffer to add key/value
|
||||
if (!Info_IsKeyImportant(key))
|
||||
{
|
||||
// no room to add setting
|
||||
Con_Printf("Info string length exceeded\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// keep removing the largest key/values until we have a room
|
||||
do
|
||||
{
|
||||
const char* largekey = Info_FindLargestKey(s, maxsize);
|
||||
if (largekey[0] == '\0')
|
||||
{
|
||||
// no room to add setting
|
||||
Con_Printf("Info string length exceeded\n");
|
||||
return FALSE;
|
||||
}
|
||||
Info_RemoveKey(s, largekey);
|
||||
} while ((int)Q_strlen(s) + neededLength >= maxsize);
|
||||
}
|
||||
|
||||
Q_strcat(s, newArray);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
#else
|
||||
void Info_SetValueForStarKey(char *s, const char *key, const char *value, int maxsize)
|
||||
{
|
||||
char newArray[MAX_INFO_STRING];
|
||||
@ -424,7 +722,7 @@ void Info_SetValueForStarKey(char *s, const char *key, const char *value, int ma
|
||||
}
|
||||
|
||||
// keep removing the largest key/values until we have a room
|
||||
char *largekey;
|
||||
const char *largekey;
|
||||
do
|
||||
{
|
||||
largekey = Info_FindLargestKey(s, maxsize);
|
||||
@ -453,6 +751,7 @@ void Info_SetValueForStarKey(char *s, const char *key, const char *value, int ma
|
||||
}
|
||||
*s = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void Info_SetValueForKey(char *s, const char *key, const char *value, int maxsize)
|
||||
{
|
||||
@ -541,6 +840,89 @@ void Info_Print(const char *s)
|
||||
|
||||
qboolean Info_IsValid(const char *s)
|
||||
{
|
||||
#ifdef REHLDS_FIXES
|
||||
struct {
|
||||
const char* start;
|
||||
size_t len;
|
||||
} existingKeys[MAX_INFO_STRING * 2 / 4];
|
||||
size_t existingKeysNum = 0;
|
||||
|
||||
auto isAlreadyExists = [&](const char* key, size_t len)
|
||||
{
|
||||
for (size_t i = 0; i < existingKeysNum; i++) {
|
||||
if (len == existingKeys[i].len && !Q_memcmp(key, existingKeys[i].start, existingKeys[i].len))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
while (*s == '\\')
|
||||
{
|
||||
const char* key = ++s;
|
||||
|
||||
// keys and values are separated by another slash
|
||||
while (*s != '\\')
|
||||
{
|
||||
// key should end with a '\', not a NULL
|
||||
if (*s == '\0')
|
||||
return FALSE;
|
||||
|
||||
// quotes are deprecated
|
||||
if (*s == '"')
|
||||
return FALSE;
|
||||
|
||||
// ".." deprecated. don't know why. model path?
|
||||
if (*s == '.' && *(s + 1) == '.')
|
||||
return FALSE;
|
||||
|
||||
s++;
|
||||
}
|
||||
|
||||
size_t keyLen = s - key;
|
||||
if (keyLen == 0 || keyLen >= MAX_KV_LEN)
|
||||
return FALSE;
|
||||
|
||||
if (isAlreadyExists(key, keyLen))
|
||||
return FALSE;
|
||||
|
||||
const char* value = ++s; // skip the slash
|
||||
|
||||
// values should be ended by eos or slash
|
||||
while (*s != '\\' && *s != '\0')
|
||||
{
|
||||
// quotes are deprecated
|
||||
if (*s == '"')
|
||||
return FALSE;
|
||||
|
||||
// ".." deprecated
|
||||
if (*s == '.' && *(s + 1) == '.')
|
||||
return FALSE;
|
||||
|
||||
s++;
|
||||
}
|
||||
|
||||
size_t valueLen = s - value;
|
||||
if (valueLen == 0 || valueLen >= MAX_KV_LEN)
|
||||
return FALSE;
|
||||
|
||||
if (*s == '\0')
|
||||
return TRUE;
|
||||
|
||||
if (existingKeysNum == ARRAYSIZE(existingKeys))
|
||||
return FALSE;
|
||||
|
||||
existingKeys[existingKeysNum].start = key;
|
||||
existingKeys[existingKeysNum].len = keyLen;
|
||||
existingKeysNum++;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
#else
|
||||
char key[MAX_KV_LEN];
|
||||
char value[MAX_KV_LEN];
|
||||
char *c;
|
||||
int nCount;
|
||||
|
||||
while (*s)
|
||||
{
|
||||
if (*s == '\\')
|
||||
@ -548,48 +930,46 @@ qboolean Info_IsValid(const char *s)
|
||||
s++; // skip the slash
|
||||
}
|
||||
|
||||
// Returns character count
|
||||
// -1 - error
|
||||
// 0 - string size is zero
|
||||
enum class AllowNull {
|
||||
Yes,
|
||||
No,
|
||||
};
|
||||
auto validate = [&s](AllowNull allowNull) -> int
|
||||
// Copy a key
|
||||
nCount = 0;
|
||||
c = key;
|
||||
while (*s != '\\')
|
||||
{
|
||||
int nCount = 0;
|
||||
|
||||
for(; *s != '\\'; nCount++, s++)
|
||||
if (!*s)
|
||||
{
|
||||
if (!*s)
|
||||
{
|
||||
return (allowNull == AllowNull::Yes) ? nCount : -1;
|
||||
}
|
||||
|
||||
if (nCount >= MAX_KV_LEN)
|
||||
{
|
||||
return -1; // string length should be less then MAX_KV_LEN
|
||||
}
|
||||
|
||||
#ifdef REHLDS_FIXES
|
||||
if (*s == '\"')
|
||||
{
|
||||
return -1; // string should not contain "
|
||||
}
|
||||
#endif
|
||||
return FALSE; // key should end with a \, not a NULL
|
||||
}
|
||||
return nCount;
|
||||
};
|
||||
|
||||
if (validate(AllowNull::No) == -1)
|
||||
{
|
||||
return FALSE;
|
||||
if (nCount >= MAX_KV_LEN)
|
||||
{
|
||||
return FALSE; // key length should be less then MAX_KV_LEN
|
||||
}
|
||||
*c++ = *s++;
|
||||
nCount++;
|
||||
}
|
||||
s++; // Skip slash
|
||||
*c = 0;
|
||||
s++; // skip the slash
|
||||
|
||||
if (validate(AllowNull::Yes) <= 0)
|
||||
// Copy a value
|
||||
nCount = 0;
|
||||
c = value;
|
||||
while (*s != '\\')
|
||||
{
|
||||
return FALSE;
|
||||
if (!*s)
|
||||
{
|
||||
break; // allow value to be ended with NULL
|
||||
}
|
||||
if (nCount >= MAX_KV_LEN)
|
||||
{
|
||||
return FALSE; // value length should be less then MAX_KV_LEN
|
||||
}
|
||||
*c++ = *s++;
|
||||
nCount++;
|
||||
}
|
||||
*c = 0;
|
||||
|
||||
if (value[0] == 0)
|
||||
{
|
||||
return FALSE; // empty values are not valid
|
||||
}
|
||||
|
||||
if (!*s)
|
||||
@ -599,52 +979,89 @@ qboolean Info_IsValid(const char *s)
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef REHLDS_FIXES
|
||||
void Info_CollectFields(char *destInfo, const char *srcInfo, const char *collectedKeysOfFields)
|
||||
void Info_SetFieldsToTransmit()
|
||||
{
|
||||
char keys[MAX_INFO_STRING];
|
||||
Q_strcpy(keys, collectedKeysOfFields);
|
||||
// clean all
|
||||
for (auto field : g_info_transmitted_fields) {
|
||||
free(field->name);
|
||||
delete field;
|
||||
}
|
||||
g_info_transmitted_fields.clear();
|
||||
|
||||
size_t userInfoLength = 0;
|
||||
for (const char *key = strtok(keys, "\\"); key; key = strtok(nullptr, "\\"))
|
||||
char keys[512];
|
||||
Q_strlcpy(keys, sv_rehlds_userinfo_transmitted_fields.string);
|
||||
|
||||
auto isIntegerField = [](const char* key)
|
||||
{
|
||||
const char *value = Info_ValueForKey(srcInfo, key);
|
||||
for (auto& x : g_info_important_fields) {
|
||||
if (!Q_strcmp(key, x.name))
|
||||
return x.integer;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
for (char *key = Q_strtok(keys, "\\"); key; key = Q_strtok(nullptr, "\\"))
|
||||
{
|
||||
if (key[0] == '_') {
|
||||
Con_Printf("%s: private key '%s' couldn't be transmitted.\n", __FUNCTION__, key);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Q_strlen(key) >= MAX_KV_LEN) {
|
||||
Con_Printf("%s: key '%s' is too long (should be < %i characters)\n", __FUNCTION__, key, MAX_KV_LEN);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (std::find_if(g_info_transmitted_fields.begin(), g_info_transmitted_fields.end(), [key](info_field_t* field) { return !Q_strcmp(key, field->name); }) == g_info_transmitted_fields.end()) {
|
||||
auto field = new info_field_t;
|
||||
field->name = Q_strdup(key);
|
||||
field->integer = isIntegerField(key);
|
||||
g_info_transmitted_fields.push_back(field);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Info_CollectFields(char *destInfo, const char *srcInfo, size_t maxsize)
|
||||
{
|
||||
if (g_info_transmitted_fields.empty()) {
|
||||
Q_strlcpy(destInfo, srcInfo, maxsize);
|
||||
Info_RemovePrefixedKeys(destInfo, '_');
|
||||
return;
|
||||
}
|
||||
|
||||
char add[512], valueBuf[32];
|
||||
size_t userInfoLength = 0;
|
||||
|
||||
for (auto field : g_info_transmitted_fields)
|
||||
{
|
||||
const char *value = Info_ValueForKey(srcInfo, field->name);
|
||||
if (value[0] == '\0')
|
||||
continue;
|
||||
|
||||
// Integer fields
|
||||
if (!Q_strcmp(key, "*hltv")
|
||||
|| !Q_strcmp(key, "bottomcolor")
|
||||
|| !Q_strcmp(key, "topcolor"))
|
||||
// clean garbage from integer fields
|
||||
if (field->integer)
|
||||
{
|
||||
// don't send zero fields
|
||||
int intValue = Q_atoi(value);
|
||||
|
||||
if (!intValue)
|
||||
continue;
|
||||
|
||||
destInfo[userInfoLength++] = '\\';
|
||||
Q_strcpy(&destInfo[userInfoLength], key);
|
||||
userInfoLength += Q_strlen(key);
|
||||
|
||||
destInfo[userInfoLength++] = '\\';
|
||||
userInfoLength += Q_sprintf(&destInfo[userInfoLength], "%d", intValue);
|
||||
}
|
||||
// String fields
|
||||
else
|
||||
{
|
||||
destInfo[userInfoLength++] = '\\';
|
||||
Q_strcpy(&destInfo[userInfoLength], key);
|
||||
userInfoLength += Q_strlen(key);
|
||||
|
||||
destInfo[userInfoLength++] = '\\';
|
||||
Q_strcpy(&destInfo[userInfoLength], value);
|
||||
userInfoLength += Q_strlen(value);
|
||||
Q_sprintf(valueBuf, "%i", intValue);
|
||||
value = valueBuf;
|
||||
}
|
||||
|
||||
// don't write truncated keys/values
|
||||
size_t len = Q_sprintf(add, "\\%s\\%s", field->name, value);
|
||||
if (userInfoLength + len < maxsize) {
|
||||
Q_strcpy(destInfo + userInfoLength, add);
|
||||
userInfoLength += len;
|
||||
}
|
||||
}
|
||||
|
||||
destInfo[userInfoLength] = '\0';
|
||||
}
|
||||
#endif // REHLDS_FIXES
|
||||
|
@ -48,11 +48,16 @@ const char *Info_ValueForKey(const char *s, const char *key);
|
||||
void Info_RemoveKey(char *s, const char *key);
|
||||
void Info_RemovePrefixedKeys(char *s, const char prefix);
|
||||
qboolean Info_IsKeyImportant(const char *key);
|
||||
char *Info_FindLargestKey(char *s, int maxsize);
|
||||
const char *Info_FindLargestKey(const char *s, int maxsize);
|
||||
#ifdef REHLDS_FIXES
|
||||
qboolean Info_SetValueForStarKey(char *s, const char *key, const char *value, size_t maxsize);
|
||||
#else
|
||||
void Info_SetValueForStarKey(char *s, const char *key, const char *value, int maxsize);
|
||||
#endif
|
||||
void Info_SetValueForKey(char *s, const char *key, const char *value, int maxsize);
|
||||
void Info_Print(const char *s);
|
||||
qboolean Info_IsValid(const char *s);
|
||||
#ifdef REHLDS_FIXES
|
||||
void Info_CollectFields(char *destInfo, const char *srcInfo, const char *collectedKeysOfFields);
|
||||
void Info_SetFieldsToTransmit();
|
||||
void Info_CollectFields(char *destInfo, const char *srcInfo, size_t maxsize);
|
||||
#endif
|
||||
|
@ -356,7 +356,6 @@ void EXT_FUNC PF_traceline_DLL(const float *v1, const float *v2, int fNoMonsters
|
||||
|
||||
void EXT_FUNC TraceHull(const float *v1, const float *v2, int fNoMonsters, int hullNumber, edict_t *pentToSkip, TraceResult *ptr)
|
||||
{
|
||||
hullNumber = hullNumber;
|
||||
if (hullNumber < 0 || hullNumber > 3)
|
||||
hullNumber = 0;
|
||||
|
||||
|
@ -265,6 +265,35 @@ char *ED_ParseEdict(char *data, edict_t *ent)
|
||||
|
||||
Q_strcpy(keyname, "angles");
|
||||
}
|
||||
#ifdef REHLDS_FIXES
|
||||
else if (!Q_strcmp(keyname, "model"))
|
||||
{
|
||||
// local model?
|
||||
if (com_token[0] == '*')
|
||||
{
|
||||
// find empty slot
|
||||
int i;
|
||||
for (i = 0; i < MAX_MODELS; i++)
|
||||
{
|
||||
if (!g_psv.model_precache[i])
|
||||
break;
|
||||
}
|
||||
|
||||
int index = Q_atoi(com_token + 1);
|
||||
|
||||
g_psv.model_precache[i] = localmodels[index];
|
||||
g_psv.models[i] = Mod_ForName(localmodels[index], FALSE, FALSE);
|
||||
g_psv.model_precache_flags[i] |= RES_FATALIFMISSING;
|
||||
|
||||
#ifdef REHLDS_OPT_PEDANTIC
|
||||
{
|
||||
int __itmp = i;
|
||||
g_rehlds_sv.modelsMap.put(g_psv.model_precache[i], __itmp);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
kvd.szClassName = className;
|
||||
kvd.szKeyName = keyname;
|
||||
|
@ -1937,7 +1937,7 @@ int EXT_FUNC SV_CheckKeyInfo_internal(netadr_t *adr, char *protinfo, unsigned sh
|
||||
|
||||
s = Info_ValueForKey(protinfo, "raw");
|
||||
|
||||
if (s[0] == 0 || (nAuthProtocol == 2 && Q_strlen(s) != 32))
|
||||
if (s[0] == '\0' || (nAuthProtocol == 2 && Q_strlen(s) != 32))
|
||||
{
|
||||
SV_RejectConnection(adr, "Invalid authentication certificate length.\n");
|
||||
return 0;
|
||||
@ -2061,7 +2061,6 @@ int SV_CheckUserInfo(netadr_t *adr, char *userinfo, qboolean bIsReconnecting, in
|
||||
const char *s;
|
||||
char newname[MAX_NAME];
|
||||
int proxies;
|
||||
int i;
|
||||
|
||||
if (!NET_IsLocalAddress(*adr))
|
||||
{
|
||||
@ -2086,13 +2085,15 @@ int SV_CheckUserInfo(netadr_t *adr, char *userinfo, qboolean bIsReconnecting, in
|
||||
}
|
||||
}
|
||||
|
||||
i = Q_strlen(userinfo);
|
||||
#ifndef REHLDS_FIXES
|
||||
int i = Q_strlen(userinfo);
|
||||
if (i <= 4 || Q_strstr(userinfo, "\\\\") || userinfo[i - 1] == '\\')
|
||||
{
|
||||
SV_RejectConnection(adr, "Unknown HLTV client type.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
Info_RemoveKey(userinfo, "password");
|
||||
|
||||
@ -2132,9 +2133,9 @@ int SV_CheckUserInfo(netadr_t *adr, char *userinfo, qboolean bIsReconnecting, in
|
||||
#endif
|
||||
|
||||
#ifdef REHLDS_FIXES
|
||||
if (name[0] == 0 || !Q_stricmp(name, "console") || Q_strstr(name, "..") || Q_strstr(name, "\"") || Q_strstr(name, "\\"))
|
||||
if (name[0] == '\0' || !Q_stricmp(name, "console"))
|
||||
#else // REHLDS_FIXES
|
||||
if (name[0] == 0 || !Q_stricmp(name, "console") || Q_strstr(name, "..") != NULL)
|
||||
if (name[0] == '\0' || !Q_stricmp(name, "console") || Q_strstr(name, "..") != NULL)
|
||||
#endif // REHLDS_FIXES
|
||||
{
|
||||
Info_SetValueForKey(userinfo, "name", "unnamed", MAX_INFO_STRING);
|
||||
@ -2147,11 +2148,10 @@ int SV_CheckUserInfo(netadr_t *adr, char *userinfo, qboolean bIsReconnecting, in
|
||||
if (SV_CheckForDuplicateNames(userinfo, bIsReconnecting, nReconnectSlot))
|
||||
{
|
||||
Q_strncpy(name, Info_ValueForKey(userinfo, "name"), MAX_NAME - 1);
|
||||
name[MAX_NAME - 1] = 0;
|
||||
name[MAX_NAME - 1] = '\0';
|
||||
}
|
||||
|
||||
s = Info_ValueForKey(userinfo, "*hltv");
|
||||
|
||||
if (!s[0])
|
||||
return 1;
|
||||
|
||||
@ -3760,17 +3760,12 @@ void SV_FullClientUpdate(client_t *cl, sizebuf_t *sb)
|
||||
char info[MAX_INFO_STRING];
|
||||
|
||||
#ifdef REHLDS_FIXES
|
||||
if (sv_rehlds_userinfo_transmitted_fields.string[0] != '\0')
|
||||
{
|
||||
Info_CollectFields(info, cl->userinfo, sv_rehlds_userinfo_transmitted_fields.string);
|
||||
}
|
||||
else
|
||||
Info_CollectFields(info, cl->userinfo, MAX_INFO_STRING);
|
||||
#else // REHLDS_FIXES
|
||||
Q_strncpy(info, cl->userinfo, sizeof(info) - 1);
|
||||
info[sizeof(info) - 1] = '\0';
|
||||
Info_RemovePrefixedKeys(info, '_');
|
||||
#endif // REHLDS_FIXES
|
||||
{
|
||||
Q_strncpy(info, cl->userinfo, sizeof(info) - 1);
|
||||
info[sizeof(info) - 1] = 0;
|
||||
Info_RemovePrefixedKeys(info, '_');
|
||||
}
|
||||
|
||||
g_RehldsHookchains.m_SV_WriteFullClientUpdate.callChain(SV_WriteFullClientUpdate_internal, GetRehldsApiClient(cl), info, MAX_INFO_STRING, sb, GetRehldsApiClient((sb == &g_psv.reliable_datagram) ? nullptr : host_client));
|
||||
}
|
||||
@ -4914,12 +4909,7 @@ void SV_ExtractFromUserinfo(client_t *cl)
|
||||
Q_UnicodeRepair(newname);
|
||||
}
|
||||
|
||||
if (newname[0] == '\0' || !Q_stricmp(newname, "console")
|
||||
#ifdef REHLDS_FIXES
|
||||
|| Q_strstr(newname, "..") || Q_strstr(newname, "\"") || Q_strstr(newname, "\\"))
|
||||
#else // REHLDS_FIXES
|
||||
)
|
||||
#endif // REHLDS_FIXES
|
||||
if (newname[0] == '\0' || !Q_stricmp(newname, "console"))
|
||||
{
|
||||
Info_SetValueForKey(userinfo, "name", "unnamed", MAX_INFO_STRING);
|
||||
}
|
||||
@ -4940,26 +4930,26 @@ void SV_ExtractFromUserinfo(client_t *cl)
|
||||
ISteamGameServer_BUpdateUserData(cl->network_userid.m_SteamID, cl->name, 0);
|
||||
|
||||
val = Info_ValueForKey(userinfo, "rate");
|
||||
if (val[0] != 0)
|
||||
if (val[0] != '\0')
|
||||
{
|
||||
i = Q_atoi(val);
|
||||
cl->netchan.rate = Q_clamp(float(i), MIN_RATE, MAX_RATE);
|
||||
}
|
||||
|
||||
val = Info_ValueForKey(userinfo, "topcolor");
|
||||
if (val[0] != 0)
|
||||
if (val[0] != '\0')
|
||||
cl->topcolor = Q_atoi(val);
|
||||
else
|
||||
Con_DPrintf("topcolor unchanged for %s\n", cl->name);
|
||||
|
||||
val = Info_ValueForKey(userinfo, "bottomcolor");
|
||||
if (val[0] != 0)
|
||||
if (val[0] != '\0')
|
||||
cl->bottomcolor = Q_atoi(val);
|
||||
else
|
||||
Con_DPrintf("bottomcolor unchanged for %s\n", cl->name);
|
||||
|
||||
val = Info_ValueForKey(userinfo, "cl_updaterate");
|
||||
if (val[0] != 0)
|
||||
if (val[0] != '\0')
|
||||
{
|
||||
i = Q_atoi(val);
|
||||
if (i >= 10)
|
||||
@ -4969,13 +4959,13 @@ void SV_ExtractFromUserinfo(client_t *cl)
|
||||
}
|
||||
|
||||
val = Info_ValueForKey(userinfo, "cl_lw");
|
||||
cl->lw = val[0] != 0 ? Q_atoi(val) != 0 : 0;
|
||||
cl->lw = val[0] != '\0' ? Q_atoi(val) != 0 : 0;
|
||||
|
||||
val = Info_ValueForKey(userinfo, "cl_lc");
|
||||
cl->lc = val[0] != 0 ? Q_atoi(val) != 0 : 0;
|
||||
cl->lc = val[0] != '\0' ? Q_atoi(val) != 0 : 0;
|
||||
|
||||
val = Info_ValueForKey(userinfo, "*hltv");
|
||||
cl->proxy = val[0] != 0 ? Q_atoi(val) == TYPE_PROXY : 0;
|
||||
cl->proxy = val[0] != '\0' ? Q_atoi(val) == TYPE_PROXY : 0;
|
||||
|
||||
SV_CheckUpdateRate(&cl->next_messageinterval);
|
||||
SV_CheckRate(cl);
|
||||
@ -5813,6 +5803,10 @@ void EXT_FUNC SV_ActivateServer_internal(int runPhysics)
|
||||
Q_sprintf(szCommand, "exec %s\n", mapchangecfgfile.string);
|
||||
Cbuf_AddText(szCommand);
|
||||
}
|
||||
|
||||
#ifdef REHLDS_FIXES
|
||||
Info_SetFieldsToTransmit();
|
||||
#endif
|
||||
}
|
||||
|
||||
void SV_ServerShutdown(void)
|
||||
@ -6059,7 +6053,6 @@ int SV_SpawnServer(qboolean bIsDemo, char *server, char *startspot)
|
||||
g_psv.model_precache[0] = pr_strings;
|
||||
#ifndef REHLDS_FIXES
|
||||
g_psv.generic_precache[0] = pr_strings;
|
||||
#endif // REHLDS_FIXES
|
||||
|
||||
for (i = 1; i < g_psv.worldmodel->numsubmodels; i++)
|
||||
{
|
||||
@ -6074,6 +6067,7 @@ int SV_SpawnServer(qboolean bIsDemo, char *server, char *startspot)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif // REHLDS_FIXES
|
||||
|
||||
Q_memset(&g_psv.edicts->v, 0, sizeof(entvars_t));
|
||||
|
||||
@ -7815,7 +7809,7 @@ void SV_Init(void)
|
||||
Cvar_RegisterVariable(&sv_rehlds_local_gametime);
|
||||
Cvar_RegisterVariable(&sv_rehlds_send_mapcycle);
|
||||
Cvar_RegisterVariable(&sv_rehlds_maxclients_from_single_ip);
|
||||
|
||||
|
||||
Cvar_RegisterVariable(&sv_rollspeed);
|
||||
Cvar_RegisterVariable(&sv_rollangle);
|
||||
#endif
|
||||
|
@ -80,6 +80,7 @@ inline char *_strlwr(char *start)
|
||||
#define Q_strstr A_strstr
|
||||
#define Q_strchr strchr
|
||||
#define Q_strrchr strrchr
|
||||
#define Q_strtok strtok
|
||||
#define Q_strlwr A_strtolower
|
||||
#define Q_strupr A_strtoupper
|
||||
#define Q_sprintf sprintf
|
||||
@ -120,6 +121,7 @@ inline char *_strlwr(char *start)
|
||||
#define Q_strstr strstr
|
||||
#define Q_strchr strchr
|
||||
#define Q_strrchr strrchr
|
||||
#define Q_strtok strtok
|
||||
#define Q_strlwr _strlwr
|
||||
#define Q_strupr _strupr
|
||||
#define Q_sprintf sprintf
|
||||
@ -144,18 +146,17 @@ inline char *_strlwr(char *start)
|
||||
#define Q_fmod fmod
|
||||
#endif // #if defined(ASMLIB_H) && defined(HAVE_OPT_STRTOOLS)
|
||||
|
||||
// a safe variant of strcpy that truncates the result to fit in the destination buffer
|
||||
template <size_t size>
|
||||
char *Q_strlcpy(char (&dest)[size], const char *src) {
|
||||
// size - sizeof(buffer)
|
||||
inline char *Q_strlcpy(char *dest, const char *src, size_t size) {
|
||||
Q_strncpy(dest, src, size - 1);
|
||||
dest[size - 1] = '\0';
|
||||
return dest;
|
||||
}
|
||||
|
||||
inline char *Q_strnlcpy(char *dest, const char *src, size_t n) {
|
||||
Q_strncpy(dest, src, n - 1);
|
||||
dest[n - 1] = '\0';
|
||||
return dest;
|
||||
// a safe variant of strcpy that truncates the result to fit in the destination buffer
|
||||
template <size_t size>
|
||||
char *Q_strlcpy(char (&dest)[size], const char *src) {
|
||||
return Q_strlcpy(dest, src, size);
|
||||
}
|
||||
|
||||
// safely concatenate two strings.
|
||||
|
@ -3,8 +3,6 @@
|
||||
#include "cppunitlite/TestHarness.h"
|
||||
|
||||
TEST(PrefixedKeysRemove, Info, 1000) {
|
||||
EngineInitializer engInitGuard;
|
||||
|
||||
struct testdata_t {
|
||||
const char* inData;
|
||||
const char* outData;
|
||||
@ -12,9 +10,7 @@ TEST(PrefixedKeysRemove, Info, 1000) {
|
||||
|
||||
testdata_t testdata[] = {
|
||||
{ "", "" },
|
||||
{ "key\\value", "key\\value" },
|
||||
{ "\\key\\value", "\\key\\value" },
|
||||
{ "_key\\value", "" },
|
||||
{ "\\_key\\value", "" },
|
||||
{ "\\k\\v\\_u\\t\\y\\z", "\\k\\v\\y\\z" },
|
||||
{ "\\_k\\v\\u\\t\\y\\z", "\\u\\t\\y\\z" },
|
||||
@ -34,8 +30,6 @@ TEST(PrefixedKeysRemove, Info, 1000) {
|
||||
}
|
||||
|
||||
TEST(SetValueForStarKey, Info, 1000) {
|
||||
EngineInitializer engInitGuard;
|
||||
|
||||
struct testdata_t {
|
||||
const char* initialInfo;
|
||||
const char* key;
|
||||
@ -45,20 +39,26 @@ TEST(SetValueForStarKey, Info, 1000) {
|
||||
|
||||
testdata_t testdata[] = {
|
||||
// Behavior
|
||||
{ "", "a", "b", "\\a\\b" },
|
||||
{ "\\a\\b\\c\\d", "a", "b", "\\c\\d\\a\\b" },
|
||||
{ "a\\b\\c\\d", "a", "b", "\\c\\d\\a\\b" },
|
||||
{ "\\a\\b", "c", "d", "\\a\\b\\c\\d" },
|
||||
{ "\\a\\b\\c\\d", "b", "f", "\\a\\b\\c\\d\\b\\f" },
|
||||
{ "\\a\\b\\c\\d", "c", "", "\\a\\b" },
|
||||
{ "\\a\\b\\c\\d\\e\\f", "c", "", "\\a\\b\\e\\f" },
|
||||
{ "\\a\\b\\c\\d\\e\\f", "z", "", "\\a\\b\\c\\d\\e\\f" },
|
||||
{ "\\a\\b\\c\\d", "a", "e", "\\c\\d\\a\\e" },
|
||||
{ "\\a\\b\\c\\d", "e", "f", "\\a\\b\\c\\d\\e\\f" },
|
||||
{ "a\\b\\c\\d", "e", "f", "a\\b\\c\\d\\e\\f" },
|
||||
{ "\\a\\b\\c\\d", "b", "c", "\\a\\b\\c\\d\\b\\c" },
|
||||
{ "\\a\\b\\c\\d\\e\\f", "c", "q", "\\a\\b\\e\\f\\c\\q" },
|
||||
|
||||
{ "\\a\\b\\c\\d", "team", "aBcD", "\\a\\b\\c\\d\\team\\abcd" },
|
||||
|
||||
{ "\\a\\b\\c", "e", "f", "\\a\\b\\c\\e\\f" },
|
||||
{ "\\a\\b\\c\\", "e", "f", "\\a\\b\\c\\\\e\\f" },
|
||||
{ "\\a\\b\\\\c", "e", "f", "\\a\\b\\\\c\\e\\f" },
|
||||
// Invalid keys/values
|
||||
{ "\\a\\b", "c", nullptr, "\\a\\b" },
|
||||
{ "\\a\\b", nullptr, "c", "\\a\\b" },
|
||||
{ "\\a\\b", "c", "d..", "\\a\\b" },
|
||||
{ "\\a\\b", "..c", "d", "\\a\\b" },
|
||||
{ "\\a\\b", "c\"", "d", "\\a\\b" },
|
||||
{ "\\a\\b", "c", "d\"", "\\a\\b" },
|
||||
{ "\\a\\b", "c\\", "d", "\\a\\b" },
|
||||
{ "\\a\\b", "c", "d\\", "\\a\\b" },
|
||||
|
||||
|
||||
//limits
|
||||
{ //do nothing since 'team' is not important key
|
||||
"\\cl_updaterate\\100\\topcolor\\60\\name\\abcdefghijklmnop\\*sid\\12332432525345\\_vgui_menus\\1\\model\\urban\\somelargeuselesskey\\12312321321323123123123213123123123123123123123123123123123123123dasdsad\\_cl_autowepswitch\\1",
|
||||
@ -95,9 +95,44 @@ TEST(SetValueForStarKey, Info, 1000) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(RemoveKeyValue, Info, 1000) {
|
||||
EngineInitializer engInitGuard;
|
||||
#ifdef REHLDS_FIXES
|
||||
TEST(SetValueForStarKeyResult, Info, 1000) {
|
||||
struct testdata_t {
|
||||
const char* initialInfo;
|
||||
const char* key;
|
||||
const char* value;
|
||||
bool success;
|
||||
};
|
||||
|
||||
testdata_t testdata[] = {
|
||||
// Behavior
|
||||
{ "\\a\\b", "c", "d", true },
|
||||
{ "\\a\\b\\c\\d", "b", "f", true },
|
||||
{ "\\a\\b\\c\\d", "b", "c", true },
|
||||
|
||||
// Invalid keys/values
|
||||
{ "\\a\\b", "c", nullptr, false },
|
||||
{ "\\a\\b", nullptr, "c", false },
|
||||
{ "\\a\\b", "c", "d..", false },
|
||||
{ "\\a\\b", "..c", "d", false },
|
||||
{ "\\a\\b", "c\"", "d", false },
|
||||
{ "\\a\\b", "c", "d\"", false },
|
||||
{ "\\a\\b", "c\\", "d", false },
|
||||
{ "\\a\\b", "c", "d\\", false },
|
||||
};
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(testdata); i++) {
|
||||
testdata_t* d = &testdata[i];
|
||||
char localInfo[256];
|
||||
strcpy(localInfo, d->initialInfo);
|
||||
localInfo[255] = 0;
|
||||
bool result = Info_SetValueForStarKey(localInfo, d->key, d->value, 256);
|
||||
CHECK("Invalid info string", d->success == result);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(RemoveKeyValue, Info, 1000) {
|
||||
struct testdata_t {
|
||||
const char* initialInfo;
|
||||
const char* key;
|
||||
@ -107,18 +142,14 @@ TEST(RemoveKeyValue, Info, 1000) {
|
||||
testdata_t testdata[] = {
|
||||
{ "", "a", "" },
|
||||
{ "\\a\\b", "a", "" },
|
||||
{ "\\a\\", "a", "" },
|
||||
{ "\\a\\\\", "a", "\\" },
|
||||
{ "\\a", "a", "" },
|
||||
{ "a", "a", "" },
|
||||
{ "a\\", "a", "" },
|
||||
{ "a\\b", "a", "" },
|
||||
{ "a\\b\\", "a", "\\" },
|
||||
{ "\\a\\b\\c\\d\\e\\f", "d", "\\a\\b\\c\\d\\e\\f" },
|
||||
{ "\\a\\b\\c\\d\\e\\f", "c", "\\a\\b\\e\\f" },
|
||||
{ "a\\b\\c\\d\\e\\f", "d", "a\\b\\c\\d\\e\\f" },
|
||||
{ "a\\b\\c\\d\\e\\f", "c", "a\\b\\e\\f" },
|
||||
{ "a\\b\\c\\d\\e\\f", "a", "\\c\\d\\e\\f" },
|
||||
#ifdef REHLDS_FIXES
|
||||
{ "\\abc\\def\\x\\y\\ab\\cd", "ab", "\\abc\\def\\x\\y" },
|
||||
#else
|
||||
{ "\\abc\\def\\x\\y\\ab\\cd", "ab", "\\x\\y" },
|
||||
#endif
|
||||
{ "\\ab\\cd", "abc", "\\ab\\cd" }
|
||||
};
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(testdata); i++) {
|
||||
@ -131,8 +162,6 @@ TEST(RemoveKeyValue, Info, 1000) {
|
||||
}
|
||||
|
||||
TEST(GetKeyValue, Info, 1000) {
|
||||
EngineInitializer engInitGuard;
|
||||
|
||||
struct testdata_t {
|
||||
const char* info;
|
||||
const char* key;
|
||||
@ -145,16 +174,8 @@ TEST(GetKeyValue, Info, 1000) {
|
||||
{ "\\a\\", "a", "" },
|
||||
{ "\\a\\\\", "a", "" },
|
||||
{ "\\a", "a", "" },
|
||||
{ "a", "a", "" },
|
||||
{ "a\\", "a", "" },
|
||||
{ "a\\b", "a", "b" },
|
||||
{ "a\\b\\", "a", "b" },
|
||||
{ "\\a\\b\\c\\d\\e\\f", "d", "" },
|
||||
{ "\\a\\b\\c\\d\\e\\f", "c", "d" },
|
||||
{ "a\\b\\c\\d\\e\\f", "d", "" },
|
||||
{ "a\\b\\c\\d\\e\\f", "c", "d" },
|
||||
|
||||
{ "a\\b\\c\\d\\e\\f", "e", "f" },
|
||||
{ "\\a\\b\\c\\d\\e\\f", "e", "f" },
|
||||
|
||||
};
|
||||
@ -166,3 +187,122 @@ TEST(GetKeyValue, Info, 1000) {
|
||||
ZSTR_EQUAL("Invalid info value", d->result, res);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(FindLargestKey, Info, 1000) {
|
||||
struct testdata_t {
|
||||
const char* info;
|
||||
const char* result;
|
||||
};
|
||||
|
||||
testdata_t testdata[] = {
|
||||
{ "", "" },
|
||||
{ "\\name\\a\\model\\b", "" },
|
||||
{ "\\name\\a\\model\\b\\c\\d", "c" },
|
||||
{ "\\name\\a\\1234567890abcdef\\b\\model\\c\\1234567890abcdefghi\\d\\rate\\1000", "1234567890abcdefghi" },
|
||||
{ "\\name\\a\\1234567890abcdefghi\\b\\model\\c\\1234567890abcdef\\d\\rate\\1000", "1234567890abcdefghi" }
|
||||
};
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(testdata); i++) {
|
||||
testdata_t* d = &testdata[i];
|
||||
|
||||
const char* res = Info_FindLargestKey(d->info, MAX_INFO_STRING);
|
||||
ZSTR_EQUAL("Invalid info value", d->result, res);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(InfoIsValid, Info, 1000) {
|
||||
struct testdata_t {
|
||||
const char* info;
|
||||
qboolean result;
|
||||
};
|
||||
|
||||
testdata_t testdata[] = {
|
||||
{ "", false }, // by original design
|
||||
#ifdef REHLDS_FIXES
|
||||
{ "a\\b", false },
|
||||
#endif
|
||||
{ "\\a\\b", true },
|
||||
{ "\\a\\b\\c", false },
|
||||
{ "\\a\\b\\c\\", false },
|
||||
{ "\\a\\b\\c\\\\", false },
|
||||
#ifdef REHLDS_FIXES
|
||||
{ "\\a\\b\\\\d", false },
|
||||
{ "\\a\\b\\\\d\\", false },
|
||||
{ "\\a\\b..c", false },
|
||||
{ "\\a\\b\"c", false },
|
||||
{ "\\a..b\\c", false },
|
||||
{ "\\a\"b\\c", false },
|
||||
#endif
|
||||
{ "\\a\\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", false },
|
||||
{ "\\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\\c", false },
|
||||
#ifdef REHLDS_FIXES
|
||||
{ "\\a\\b\\c\\d\\a\\e", false },
|
||||
#endif
|
||||
{ "\\aaab\\b\\c\\d\\aaa\\e", true },
|
||||
{ "\\aaa\\b\\c\\d\\aaab\\e", true }
|
||||
};
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(testdata); i++) {
|
||||
testdata_t* d = &testdata[i];
|
||||
|
||||
char error[256];
|
||||
snprintf(error, sizeof error, "Invalid result for string '%s'", d->info);
|
||||
|
||||
qboolean res = Info_IsValid(d->info);
|
||||
CHECK(error, d->result == res);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef REHLDS_FIXES
|
||||
TEST(InfoCollectFields, Info, 1000)
|
||||
{
|
||||
struct testdata_t {
|
||||
const char* info;
|
||||
const char* cvar;
|
||||
const char* result;
|
||||
};
|
||||
|
||||
testdata_t testdata[] = {
|
||||
{ "\\cl_updaterate\\100\\topcolor\\60\\name\\abcdefghijklmnop\\*sid\\12332432525345\\_vgui_menus\\1\\model\\urban\\anykey\\1", "", "\\cl_updaterate\\100\\topcolor\\60\\name\\abcdefghijklmnop\\*sid\\12332432525345\\model\\urban\\anykey\\1" },
|
||||
{ "\\cl_updaterate\\100\\topcolor\\60\\name\\abcdefghijklmnop\\*sid\\12332432525345\\_vgui_menus\\1\\model\\urban", "rate", "" },
|
||||
{ "\\cl_updaterate\\100\\topcolor\\60\\name\\abcdefghijklmnop\\*sid\\12332432525345\\_vgui_menus\\1\\model\\urban", "topcolor\\*sid\\_vgui_menus", "\\topcolor\\60\\*sid\\12332432525345" },
|
||||
{ "\\*hltv\\1dsgs", "*hltv", "\\*hltv\\1" },
|
||||
{ "\\name\\player", "bottomcolor\\name", "\\name\\player" },
|
||||
};
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(testdata); i++) {
|
||||
testdata_t* d = &testdata[i];
|
||||
|
||||
char destinfo[MAX_INFO_STRING];
|
||||
sv_rehlds_userinfo_transmitted_fields.string = (char *)d->cvar;
|
||||
Info_SetFieldsToTransmit();
|
||||
Info_CollectFields(destinfo, d->info, MAX_INFO_STRING);
|
||||
|
||||
ZSTR_EQUAL("Invalid info string", d->result, destinfo);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(Info_IsKeyImportant, Info, 1000)
|
||||
{
|
||||
struct testdata_t {
|
||||
const char* key;
|
||||
bool result;
|
||||
};
|
||||
|
||||
testdata_t testdata[] = {
|
||||
{ "bottomcolor", true },
|
||||
{ "bot", false },
|
||||
{ "*any", true },
|
||||
{ "_any", false },
|
||||
{ "model2", false }
|
||||
};
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(testdata); i++) {
|
||||
testdata_t* d = &testdata[i];
|
||||
|
||||
bool result = Info_IsKeyImportant(d->key);
|
||||
|
||||
CHECK("wrong result", d->result == result);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user