Add FileTransfer Hooks to SDKTools (r=Drifter).

This commit is contained in:
Kyle Sanderson 2015-09-12 13:01:33 -07:00
parent 8777d0d0da
commit 274e7bd329
5 changed files with 261 additions and 33 deletions

View File

@ -44,6 +44,7 @@
#include <ISDKTools.h> #include <ISDKTools.h>
#include "clientnatives.h" #include "clientnatives.h"
#include "teamnatives.h" #include "teamnatives.h"
#include "filesystem.h"
/** /**
* @file extension.cpp * @file extension.cpp
* @brief Implements SDK Tools extension code. * @brief Implements SDK Tools extension code.
@ -68,6 +69,7 @@ IVoiceServer *voiceserver = NULL;
IPlayerInfoManager *playerinfomngr = NULL; IPlayerInfoManager *playerinfomngr = NULL;
ICvar *icvar = NULL; ICvar *icvar = NULL;
IServer *iserver = NULL; IServer *iserver = NULL;
IBaseFileSystem *basefilesystem = NULL;
CGlobalVars *gpGlobals; CGlobalVars *gpGlobals;
ISoundEmitterSystemBase *soundemitterbase = NULL; ISoundEmitterSystemBase *soundemitterbase = NULL;
@ -258,6 +260,7 @@ bool SDKTools::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool
GET_V_IFACE_ANY(GetEngineFactory, voiceserver, IVoiceServer, INTERFACEVERSION_VOICESERVER); GET_V_IFACE_ANY(GetEngineFactory, voiceserver, IVoiceServer, INTERFACEVERSION_VOICESERVER);
GET_V_IFACE_ANY(GetServerFactory, playerinfomngr, IPlayerInfoManager, INTERFACEVERSION_PLAYERINFOMANAGER); GET_V_IFACE_ANY(GetServerFactory, playerinfomngr, IPlayerInfoManager, INTERFACEVERSION_PLAYERINFOMANAGER);
GET_V_IFACE_CURRENT(GetEngineFactory, icvar, ICvar, CVAR_INTERFACE_VERSION); GET_V_IFACE_CURRENT(GetEngineFactory, icvar, ICvar, CVAR_INTERFACE_VERSION);
GET_V_IFACE_CURRENT(GetFileSystemFactory, basefilesystem, IBaseFileSystem, BASEFILESYSTEM_INTERFACE_VERSION);
#if SOURCE_ENGINE >= SE_ORANGEBOX #if SOURCE_ENGINE >= SE_ORANGEBOX
GET_V_IFACE_ANY(GetServerFactory, servertools, IServerTools, VSERVERTOOLS_INTERFACE_VERSION); GET_V_IFACE_ANY(GetServerFactory, servertools, IServerTools, VSERVERTOOLS_INTERFACE_VERSION);
@ -466,9 +469,10 @@ const char *SDKTools::GetExtensionDateString()
return SOURCEMOD_BUILD_TIME; return SOURCEMOD_BUILD_TIME;
} }
void SDKTools::OnClientPutInServer(int client) bool SDKTools::InterceptClientConnect(int client, char *error, size_t maxlength)
{ {
g_Hooks.OnClientPutInServer(client); g_Hooks.OnClientConnect(client);
return true;
} }
#if SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_CSGO #if SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_CSGO
@ -487,6 +491,11 @@ void SDKTools::OnSendClientCommand(edict_t *pPlayer, const char *szFormat)
} }
#endif #endif
void SDKTools::OnClientPutInServer(int client)
{
g_Hooks.OnClientPutInServer(client);
}
class SDKTools_API : public ISDKTools class SDKTools_API : public ISDKTools
{ {
public: public:

View File

@ -89,6 +89,7 @@ public:
public: //IConCommandBaseAccessor public: //IConCommandBaseAccessor
bool RegisterConCommandBase(ConCommandBase *pVar); bool RegisterConCommandBase(ConCommandBase *pVar);
public: //IClientListner public: //IClientListner
bool InterceptClientConnect(int client, char *error, size_t maxlength);
void OnClientPutInServer(int client); void OnClientPutInServer(int client);
void OnClientDisconnecting(int client); void OnClientDisconnecting(int client);
public: // IVoiceServer public: // IVoiceServer
@ -129,6 +130,7 @@ extern IVoiceServer *voiceserver;
extern IPlayerInfoManager *playerinfomngr; extern IPlayerInfoManager *playerinfomngr;
extern ICvar *icvar; extern ICvar *icvar;
extern IServer *iserver; extern IServer *iserver;
extern IBaseFileSystem *basefilesystem;
extern CGlobalVars *gpGlobals; extern CGlobalVars *gpGlobals;
#if SOURCE_ENGINE >= SE_ORANGEBOX #if SOURCE_ENGINE >= SE_ORANGEBOX
extern IServerTools *servertools; extern IServerTools *servertools;

View File

@ -37,18 +37,32 @@
#include "utlvector.h" #include "utlvector.h"
#include <shareddefs.h> #include <shareddefs.h>
#include "usercmd.h" #include "usercmd.h"
#include "filesystem.h"
#define FEATURECAP_PLAYERRUNCMD_11PARAMS "SDKTools PlayerRunCmd 11Params" #define FEATURECAP_PLAYERRUNCMD_11PARAMS "SDKTools PlayerRunCmd 11Params"
CHookManager g_Hooks; CHookManager g_Hooks;
static bool PRCH_enabled = false; static bool PRCH_enabled = false;
static bool PRCH_used = false; static bool PRCH_used = false;
static bool FILE_used = false;
SH_DECL_MANUALHOOK2_void(PlayerRunCmdHook, 0, 0, 0, CUserCmd *, IMoveHelper *); SH_DECL_MANUALHOOK2_void(PlayerRunCmdHook, 0, 0, 0, CUserCmd *, IMoveHelper *);
SH_DECL_HOOK2(IBaseFileSystem, FileExists, SH_NOATTRIB, 0, bool, const char*, const char *);
#if SOURCE_ENGINE >= SE_ALIENSWARM || SOURCE_ENGINE == SE_LEFT4DEAD || SOURCE_ENGINE == SE_LEFT4DEAD2
SH_DECL_HOOK3(INetChannel, SendFile, SH_NOATTRIB, 0, bool, const char *, unsigned int, bool);
#else
SH_DECL_HOOK2(INetChannel, SendFile, SH_NOATTRIB, 0, bool, const char *, unsigned int);
#endif
SH_DECL_HOOK2_void(INetChannel, ProcessPacket, SH_NOATTRIB, 0, struct netpacket_s *, bool);
SourceHook::CallClass<IBaseFileSystem> *basefilesystemPatch = NULL;
CHookManager::CHookManager() CHookManager::CHookManager()
{ {
m_usercmdsFwd = NULL; m_usercmdsFwd = NULL;
m_netFileSendFwd = NULL;
m_netFileReceiveFwd = NULL;
m_pActiveNetChannel = NULL;
} }
void CHookManager::Initialize() void CHookManager::Initialize()
@ -65,6 +79,13 @@ void CHookManager::Initialize()
PRCH_enabled = false; PRCH_enabled = false;
} }
SH_ADD_HOOK(IBaseFileSystem, FileExists, basefilesystem, SH_MEMBER(this, &CHookManager::FileExists), false);
basefilesystemPatch = SH_GET_CALLCLASS(basefilesystem);
m_netFileSendFwd = forwards->CreateForward("OnFileSend", ET_Event, 2, NULL, Param_Cell, Param_String);
m_netFileReceiveFwd = forwards->CreateForward("OnFileReceive", ET_Event, 2, NULL, Param_Cell, Param_String);
plsys->AddPluginsListener(this); plsys->AddPluginsListener(this);
sharesys->AddCapabilityProvider(myself, this, FEATURECAP_PLAYERRUNCMD_11PARAMS); sharesys->AddCapabilityProvider(myself, this, FEATURECAP_PLAYERRUNCMD_11PARAMS);
@ -85,16 +106,25 @@ void CHookManager::Initialize()
void CHookManager::Shutdown() void CHookManager::Shutdown()
{ {
forwards->ReleaseForward(m_usercmdsFwd); forwards->ReleaseForward(m_usercmdsFwd);
forwards->ReleaseForward(m_netFileSendFwd);
forwards->ReleaseForward(m_netFileReceiveFwd);
plsys->RemovePluginsListener(this); plsys->RemovePluginsListener(this);
sharesys->DropCapabilityProvider(myself, this, FEATURECAP_PLAYERRUNCMD_11PARAMS); sharesys->DropCapabilityProvider(myself, this, FEATURECAP_PLAYERRUNCMD_11PARAMS);
} }
void CHookManager::OnClientConnect(int client)
{
NetChannelHook(client);
}
void CHookManager::OnClientPutInServer(int client) void CHookManager::OnClientPutInServer(int client)
{ {
if (!PRCH_enabled) PlayerRunCmdHook(client);
return; }
void CHookManager::PlayerRunCmdHook(int client)
{
if (!PRCH_used) if (!PRCH_used)
return; return;
@ -193,17 +223,144 @@ void CHookManager::PlayerRunCmd(CUserCmd *ucmd, IMoveHelper *moveHelper)
RETURN_META(MRES_IGNORED); RETURN_META(MRES_IGNORED);
} }
void CHookManager::NetChannelHook(int client)
{
if (!FILE_used)
return;
INetChannel *pNetChannel = static_cast<INetChannel *>(engine->GetPlayerNetInfo(client));
if (pNetChannel == NULL)
{
return;
}
/* Normal NetChannel Hooks. */
{
CVTableHook hook(pNetChannel);
size_t iter;
for (iter = 0; iter < m_netChannelHooks.length(); ++iter)
{
/* We can technically skip 2; even technical-ier, this could be a bool; but Valve. */
if (hook == m_netChannelHooks[iter])
{
break;
}
}
if (iter == m_netChannelHooks.length())
{
int hookid = SH_ADD_VPHOOK(INetChannel, SendFile, pNetChannel, SH_MEMBER(this, &CHookManager::SendFile), false);
hook.SetHookID(hookid);
m_netChannelHooks.append(new CVTableHook(hook));
hookid = SH_ADD_VPHOOK(INetChannel, ProcessPacket, pNetChannel, SH_MEMBER(this, &CHookManager::ProcessPacket), false);
hook.SetHookID(hookid);
m_netChannelHooks.append(new CVTableHook(hook));
hookid = SH_ADD_VPHOOK(INetChannel, ProcessPacket, pNetChannel, SH_MEMBER(this, &CHookManager::ProcessPacket_Post), true);
hook.SetHookID(hookid);
m_netChannelHooks.append(new CVTableHook(hook));
}
}
}
void CHookManager::ProcessPacket(struct netpacket_s *packet, bool bHasHeader)
{
if (m_netFileReceiveFwd->GetFunctionCount() == 0)
{
RETURN_META(MRES_IGNORED);
}
m_pActiveNetChannel = META_IFACEPTR(INetChannel);
RETURN_META(MRES_IGNORED);
}
bool CHookManager::FileExists(const char *filename, const char *pathID)
{
if (m_pActiveNetChannel == NULL || m_netFileReceiveFwd->GetFunctionCount() == 0)
{
RETURN_META_VALUE(MRES_IGNORED, false);
}
bool ret = SH_CALL(basefilesystemPatch, &IBaseFileSystem::FileExists)(filename, pathID);
if (ret == true) /* If the File Exists, the engine historically bails out. */
{
RETURN_META_VALUE(MRES_IGNORED, false);
}
int userid = 0;
IClient *pClient = (IClient *)m_pActiveNetChannel->GetMsgHandler();
if (pClient != NULL)
{
userid = pClient->GetUserID();
}
cell_t res = Pl_Continue;
m_netFileReceiveFwd->PushCell(playerhelpers->GetClientOfUserId(userid));
m_netFileReceiveFwd->PushString(filename);
m_netFileReceiveFwd->Execute(&res);
if (res != Pl_Continue)
{
RETURN_META_VALUE(MRES_SUPERCEDE, true);
}
RETURN_META_VALUE(MRES_IGNORED, false);
}
void CHookManager::ProcessPacket_Post(struct netpacket_s* packet, bool bHasHeader)
{
m_pActiveNetChannel = NULL;
RETURN_META(MRES_IGNORED);
}
#if SOURCE_ENGINE >= SE_ALIENSWARM || SOURCE_ENGINE == SE_LEFT4DEAD || SOURCE_ENGINE == SE_LEFT4DEAD2
bool CHookManager::SendFile(const char *filename, unsigned int transferID, bool isReplayDemo)
#else
bool CHookManager::SendFile(const char *filename, unsigned int transferID)
#endif
{
if (m_netFileSendFwd->GetFunctionCount() == 0)
{
RETURN_META_VALUE(MRES_IGNORED, false);
}
INetChannel *pNetChannel = META_IFACEPTR(INetChannel);
if (pNetChannel == NULL)
{
RETURN_META_VALUE(MRES_IGNORED, false);
}
int userid = 0;
IClient *pClient = (IClient *)m_pActiveNetChannel->GetMsgHandler();
if (pClient != NULL)
{
userid = pClient->GetUserID();
}
cell_t res = Pl_Continue;
m_netFileSendFwd->PushCell(playerhelpers->GetClientOfUserId(userid));
m_netFileSendFwd->PushString(filename);
m_netFileSendFwd->Execute(&res);
if (res != Pl_Continue)
{
/* Mimic the Engine. */
#if SOURCE_ENGINE >= SE_ALIENSWARM || SOURCE_ENGINE == SE_LEFT4DEAD || SOURCE_ENGINE == SE_LEFT4DEAD2
pNetChannel->DenyFile(filename, transferID, isReplayDemo);
#else
pNetChannel->DenyFile(filename, transferID);
#endif
RETURN_META_VALUE(MRES_SUPERCEDE, false);
}
RETURN_META_VALUE(MRES_IGNORED, false);
}
void CHookManager::OnPluginLoaded(IPlugin *plugin) void CHookManager::OnPluginLoaded(IPlugin *plugin)
{ {
if (!PRCH_enabled) if (PRCH_enabled && !PRCH_used && m_usercmdsFwd->GetFunctionCount())
return; {
if (PRCH_used)
return;
if (!m_usercmdsFwd->GetFunctionCount())
return;
PRCH_used = true; PRCH_used = true;
int MaxClients = playerhelpers->GetMaxClients(); int MaxClients = playerhelpers->GetMaxClients();
@ -214,19 +371,27 @@ void CHookManager::OnPluginLoaded(IPlugin *plugin)
OnClientPutInServer(i); OnClientPutInServer(i);
} }
} }
}
if (!FILE_used && (m_netFileSendFwd->GetFunctionCount() || m_netFileReceiveFwd->GetFunctionCount()))
{
FILE_used = true;
int MaxClients = playerhelpers->GetMaxClients();
for (int i = 1; i <= MaxClients; i++)
{
if (playerhelpers->GetGamePlayer(i)->IsConnected())
{
OnClientConnect(i);
}
}
}
} }
void CHookManager::OnPluginUnloaded(IPlugin *plugin) void CHookManager::OnPluginUnloaded(IPlugin *plugin)
{ {
if (!PRCH_enabled) if (PRCH_used && !m_usercmdsFwd->GetFunctionCount())
return; {
if (!PRCH_used)
return;
if (m_usercmdsFwd->GetFunctionCount())
return;
for (size_t i = 0; i < m_runUserCmdHooks.length(); ++i) for (size_t i = 0; i < m_runUserCmdHooks.length(); ++i)
{ {
delete m_runUserCmdHooks[i]; delete m_runUserCmdHooks[i];
@ -234,6 +399,18 @@ void CHookManager::OnPluginUnloaded(IPlugin *plugin)
m_runUserCmdHooks.clear(); m_runUserCmdHooks.clear();
PRCH_used = false; PRCH_used = false;
}
if (FILE_used && !m_netFileSendFwd->GetFunctionCount() && !m_netFileReceiveFwd->GetFunctionCount())
{
for (size_t i = 0; i < m_netChannelHooks.length(); ++i)
{
delete m_netChannelHooks[i];
}
m_netChannelHooks.clear();
FILE_used = false;
}
} }
FeatureStatus CHookManager::GetFeatureStatus(FeatureType type, const char *name) FeatureStatus CHookManager::GetFeatureStatus(FeatureType type, const char *name)

View File

@ -36,6 +36,8 @@ class CUserCmd;
#include "extension.h" #include "extension.h"
#include <am-vector.h> #include <am-vector.h>
#include "inetchannel.h"
#include "iclient.h"
#include "vtable_hook_helper.h" #include "vtable_hook_helper.h"
class CHookManager : IPluginsListener, IFeatureProvider class CHookManager : IPluginsListener, IFeatureProvider
@ -44,17 +46,35 @@ public:
CHookManager(); CHookManager();
void Initialize(); void Initialize();
void Shutdown(); void Shutdown();
void OnClientConnect(int client);
void OnClientPutInServer(int client); void OnClientPutInServer(int client);
void PlayerRunCmd(CUserCmd *ucmd, IMoveHelper *moveHelper); void PlayerRunCmd(CUserCmd *ucmd, IMoveHelper *moveHelper);
public: /* NetChannel/Related Hooks */
bool FileExists(const char *filename, const char *pathID);
#if SOURCE_ENGINE >= SE_ALIENSWARM || SOURCE_ENGINE == SE_LEFT4DEAD || SOURCE_ENGINE == SE_LEFT4DEAD2
bool SendFile(const char *filename, unsigned int transferID, bool isReplayDemo);
#else
bool SendFile(const char *filename, unsigned int transferID);
#endif
void ProcessPacket(struct netpacket_s *packet, bool bHasHeader);
void ProcessPacket_Post(struct netpacket_s *packet, bool bHasHeader);
public: //IPluginsListener public: //IPluginsListener
void OnPluginLoaded(IPlugin *plugin); void OnPluginLoaded(IPlugin *plugin);
void OnPluginUnloaded(IPlugin *plugin); void OnPluginUnloaded(IPlugin *plugin);
public: //IFeatureProvider public: //IFeatureProvider
virtual FeatureStatus GetFeatureStatus(FeatureType type, const char *name); virtual FeatureStatus GetFeatureStatus(FeatureType type, const char *name);
private:
void PlayerRunCmdHook(int client);
void NetChannelHook(int client);
private: private:
IForward *m_usercmdsFwd; IForward *m_usercmdsFwd;
IForward *m_netFileSendFwd;
IForward *m_netFileReceiveFwd;
ke::Vector<CVTableHook *> m_runUserCmdHooks; ke::Vector<CVTableHook *> m_runUserCmdHooks;
ke::Vector<CVTableHook *> m_netChannelHooks;
INetChannel *m_pActiveNetChannel;
}; };
extern CHookManager g_Hooks; extern CHookManager g_Hooks;

View File

@ -57,3 +57,23 @@
* FEATURECAP_PLAYERRUNCMD_11PARAMS. * FEATURECAP_PLAYERRUNCMD_11PARAMS.
*/ */
forward Action:OnPlayerRunCmd(client, &buttons, &impulse, Float:vel[3], Float:angles[3], &weapon, &subtype, &cmdnum, &tickcount, &seed, mouse[2]); forward Action:OnPlayerRunCmd(client, &buttons, &impulse, Float:vel[3], Float:angles[3], &weapon, &subtype, &cmdnum, &tickcount, &seed, mouse[2]);
/**
* @brief Called when a client requests a file from the server.
*
* @param client Client index.
* @param sFile Requested file path.
*
* @return Plugin_Handled to block the transfer, Plugin_Continue to let it proceed.
*/
forward Action:OnFileSend(client, const String:sFile[]);
/**
* @brief Called when a client sends a file to the server.
*
* @param client Client index.
* @param sFile Requested file path.
*
* @return Plugin_Handled to block the transfer, Plugin_Continue to let it proceed.
*/
forward Action:OnFileReceive(client, const String:sFile[]);