mirror of
https://github.com/rehlds/metamod-r.git
synced 2024-12-27 07:05:34 +03:00
Rewritten most of osdep code
This commit is contained in:
parent
2ecf18165b
commit
d206ad4a13
@ -77,7 +77,7 @@
|
||||
<ImportLibrary>$(OutDir)$(TargetName).lib</ImportLibrary>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>psapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
<Midl>
|
||||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
@ -140,7 +140,7 @@
|
||||
<ImportLibrary>$(OutDir)$(TargetName).lib</ImportLibrary>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>psapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
<Midl>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
|
@ -216,7 +216,7 @@ void compile_dllfunc_callbacks()
|
||||
{
|
||||
jitdata_t jitdata;
|
||||
jitdata.plugins = g_plugins ? g_plugins->plist : nullptr;
|
||||
jitdata.plugins_count = g_plugins ? g_plugins->endlist : 0;
|
||||
jitdata.plugins_count = g_plugins ? g_plugins->max_loaded_count : 0;
|
||||
jitdata.table_offset = offsetof(MPlugin, dllapi_table);
|
||||
jitdata.post_table_offset = offsetof(MPlugin, dllapi_post_table);
|
||||
|
||||
@ -237,7 +237,7 @@ void compile_newdllfunc_callbacks()
|
||||
{
|
||||
jitdata_t jitdata;
|
||||
jitdata.plugins = g_plugins ? g_plugins->plist : nullptr;
|
||||
jitdata.plugins_count = g_plugins ? g_plugins->endlist : 0;
|
||||
jitdata.plugins_count = g_plugins ? g_plugins->max_loaded_count : 0;
|
||||
jitdata.table_offset = offsetof(MPlugin, newapi_table);
|
||||
jitdata.post_table_offset = offsetof(MPlugin, newapi_post_table);
|
||||
|
||||
|
@ -240,7 +240,7 @@ void compile_engfuncs_callbacks()
|
||||
{
|
||||
jitdata_t jitdata;
|
||||
jitdata.plugins = g_plugins ? g_plugins->plist : nullptr;
|
||||
jitdata.plugins_count = g_plugins ? g_plugins->endlist : 0;
|
||||
jitdata.plugins_count = g_plugins ? g_plugins->max_loaded_count : 0;
|
||||
jitdata.table_offset = offsetof(MPlugin, engine_table);
|
||||
jitdata.post_table_offset = offsetof(MPlugin, engine_post_table);
|
||||
|
||||
|
@ -14,12 +14,12 @@ void do_link_ent(ENTITY_FN *pfnEntity, int *missing, const char *entStr, entvars
|
||||
if (!*pfnEntity)
|
||||
{
|
||||
META_DEBUG(9, ("Looking up game entity '%s'", entStr));
|
||||
*pfnEntity = (ENTITY_FN)DLSYM(GameDLL.handle, entStr);
|
||||
*pfnEntity = (ENTITY_FN)GameDLL.sys_module.getsym(entStr);
|
||||
}
|
||||
|
||||
if (!*pfnEntity)
|
||||
{
|
||||
META_ERROR("Couldn't find game entity '%s' in game DLL '%s': %s", entStr, GameDLL.name, DLERROR());
|
||||
META_ERROR("Couldn't find game entity '%s' in game DLL '%s': %s", entStr, GameDLL.name, CSysModule::getloaderror());
|
||||
*missing = 1;
|
||||
return;
|
||||
}
|
||||
|
@ -292,9 +292,9 @@ bool meta_load_gamedll(void)
|
||||
}
|
||||
|
||||
// open the game DLL
|
||||
if (!(GameDLL.handle = DLOPEN(GameDLL.pathname)))
|
||||
if (!GameDLL.sys_module.load(GameDLL.pathname))
|
||||
{
|
||||
META_ERROR("dll: Couldn't load game DLL %s: %s", GameDLL.pathname, DLERROR());
|
||||
META_ERROR("dll: Couldn't load game DLL %s: %s", GameDLL.pathname, CSysModule::getloaderror());
|
||||
RETURN_ERRNO(false, ME_DLOPEN);
|
||||
}
|
||||
|
||||
@ -305,20 +305,21 @@ bool meta_load_gamedll(void)
|
||||
// wanted to catch one of the functions, but now that plugins are
|
||||
// dynamically loadable at any time, we have to always pass our table,
|
||||
// so that any plugin loaded later can catch what they need to.
|
||||
if ((pfn_give_engfuncs = (GIVE_ENGINE_FUNCTIONS_FN) DLSYM(GameDLL.handle, "GiveFnptrsToDll")))
|
||||
if ((pfn_give_engfuncs = (GIVE_ENGINE_FUNCTIONS_FN)GameDLL.sys_module.getsym("GiveFnptrsToDll")))
|
||||
{
|
||||
pfn_give_engfuncs(&meta_engfuncs, gpGlobals);
|
||||
META_DEBUG(3, ("dll: Game '%s': Called GiveFnptrsToDll", GameDLL.name));
|
||||
}
|
||||
else
|
||||
{
|
||||
META_ERROR("dll: Couldn't find GiveFnptrsToDll() in game DLL '%s': %s", GameDLL.name, DLERROR());
|
||||
META_ERROR("dll: Couldn't find GiveFnptrsToDll() in game DLL '%s'", GameDLL.name);
|
||||
RETURN_ERRNO(false, ME_DLMISSING);
|
||||
}
|
||||
|
||||
// TODO
|
||||
// Yes...another macro.
|
||||
#define GET_FUNC_TABLE_FROM_GAME(gamedll, pfnGetFuncs, STR_GetFuncs, struct_field, API_TYPE, TABLE_TYPE, vers_pass, vers_int, vers_want, gotit) \
|
||||
if ((pfnGetFuncs = (API_TYPE) DLSYM(gamedll.handle, STR_GetFuncs))) { \
|
||||
if ((pfnGetFuncs = (API_TYPE)gamedll.sys_module.getsym(STR_GetFuncs))) { \
|
||||
gamedll.funcs.struct_field = (TABLE_TYPE *)Q_calloc(1, sizeof(TABLE_TYPE)); \
|
||||
if (!gamedll.funcs.struct_field) {\
|
||||
META_ERROR("malloc failed for gamedll struct_field: %s", STR_GetFuncs); \
|
||||
|
@ -36,7 +36,7 @@ struct gamedll_t
|
||||
char pathname[PATH_MAX]; // ie "/home/willday/half-life/cstrike/dlls/cs_i386.so"
|
||||
char const *file; // ie "cs_i386.so"
|
||||
char real_pathname[PATH_MAX]; // in case pathname overridden by bot, etc
|
||||
DLHANDLE handle;
|
||||
CSysModule sys_module;
|
||||
gamedll_funcs_t funcs; // dllapi_table, newapi_table
|
||||
};
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "precompiled.h"
|
||||
|
||||
// Constructor
|
||||
MPluginList::MPluginList(const char* ifile) : size(MAX_PLUGINS), endlist(0)
|
||||
MPluginList::MPluginList(const char* ifile) : max_loaded_count(0)
|
||||
{
|
||||
// store filename of ini file
|
||||
Q_strncpy(inifile, ifile, sizeof inifile - 1);
|
||||
@ -9,28 +9,28 @@ MPluginList::MPluginList(const char* ifile) : size(MAX_PLUGINS), endlist(0)
|
||||
|
||||
// initialize array
|
||||
Q_memset(plist, 0, sizeof(plist));
|
||||
for (int i = 0; i < size; i++)
|
||||
for (int i = 0; i < MAX_PLUGINS; i++)
|
||||
{
|
||||
plist[i].index = i + 1; // 1-based
|
||||
}
|
||||
|
||||
endlist = 0;
|
||||
max_loaded_count = 0;
|
||||
}
|
||||
|
||||
// Find a plugin based on the plugin handle.
|
||||
// meta_errno values:
|
||||
// - ME_ARGUMENT invalid pindex
|
||||
// - ME_NOTFOUND couldn't find a matching plugin
|
||||
MPlugin *MPluginList::find(DLHANDLE handle)
|
||||
MPlugin *MPluginList::find(module_handle_t handle)
|
||||
{
|
||||
if (!handle)
|
||||
RETURN_ERRNO(NULL, ME_ARGUMENT);
|
||||
|
||||
for (int i = 0; i < endlist; i++)
|
||||
for (int i = 0; i < max_loaded_count; i++)
|
||||
{
|
||||
if (plist[i].status < PL_VALID)
|
||||
continue;
|
||||
if (plist[i].handle == handle)
|
||||
if (handle == plist[i].sys_module.gethandle())
|
||||
return &plist[i];
|
||||
}
|
||||
|
||||
@ -62,7 +62,7 @@ MPlugin *MPluginList::find(plid_t id)
|
||||
if (!id)
|
||||
RETURN_ERRNO(NULL, ME_ARGUMENT);
|
||||
|
||||
for (int i = 0; i < endlist; i++)
|
||||
for (int i = 0; i < max_loaded_count; i++)
|
||||
{
|
||||
if (plist[i].status < PL_VALID)
|
||||
continue;
|
||||
@ -85,7 +85,7 @@ MPlugin *MPluginList::find(const char* findpath)
|
||||
|
||||
META_DEBUG(8, ("Looking for loaded plugin with dlfnamepath: %s", findpath));
|
||||
|
||||
for (int i = 0; i < endlist; i++)
|
||||
for (int i = 0; i < max_loaded_count; i++)
|
||||
{
|
||||
META_DEBUG(9, ("Looking at: plugin %s loadedpath: %s", plist[i].file, plist[i].pathname));
|
||||
|
||||
@ -104,25 +104,16 @@ MPlugin *MPluginList::find(const char* findpath)
|
||||
}
|
||||
|
||||
// Find a plugin that uses the given memory location.
|
||||
// meta_errno values:
|
||||
// - ME_ARGUMENT null memptr
|
||||
// - ME_NOTFOUND couldn't find a matching plugin
|
||||
// - errno's from DLFNAME()
|
||||
MPlugin *MPluginList::find_memloc(void *memptr)
|
||||
{
|
||||
const char* dlfile;
|
||||
for (int i = 0; i < max_loaded_count; i++) {
|
||||
auto iplug = &plist[i];
|
||||
|
||||
if (!memptr)
|
||||
RETURN_ERRNO(NULL, ME_ARGUMENT);
|
||||
|
||||
if (!(dlfile = DLFNAME(memptr)))
|
||||
{
|
||||
META_DEBUG(8, ("DLFNAME failed to find memloc %d", memptr));
|
||||
// meta_errno should be already set in DLFNAME
|
||||
return NULL;
|
||||
if (iplug->sys_module.contain(memptr))
|
||||
return iplug;
|
||||
}
|
||||
|
||||
return find(dlfile);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Find a plugin with non-ambiguous prefix string matching desc, file,
|
||||
@ -145,7 +136,7 @@ MPlugin *MPluginList::find_match(const char *prefix)
|
||||
pfound = NULL;
|
||||
len = Q_strlen(prefix);
|
||||
Q_snprintf(buf, sizeof(buf), "mm_%s", prefix);
|
||||
for (i = 0; i < endlist; i++)
|
||||
for (i = 0; i < max_loaded_count; i++)
|
||||
{
|
||||
iplug = &plist[i];
|
||||
if (iplug->status < PL_VALID)
|
||||
@ -214,7 +205,7 @@ MPlugin *MPluginList::find_match(MPlugin* pmatch)
|
||||
}
|
||||
|
||||
pfound = NULL;
|
||||
for (i = 0; i < endlist; i++)
|
||||
for (i = 0; i < max_loaded_count; i++)
|
||||
{
|
||||
iplug = &plist[i];
|
||||
if (pmatch->platform_match(iplug))
|
||||
@ -292,33 +283,34 @@ MPlugin* MPluginList::plugin_addload(plid_t plid, const char* fname, PLUG_LOADTI
|
||||
return pl_added;
|
||||
}
|
||||
|
||||
MPlugin* MPluginList::find_empty_slot()
|
||||
{
|
||||
for (int i = 0; i < MAX_PLUGINS; i++) {
|
||||
if (plist[i].status == PL_EMPTY) {
|
||||
if (i > max_loaded_count)
|
||||
max_loaded_count = i + 1;
|
||||
|
||||
return &plist[i];
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Add a plugin to the list.
|
||||
// meta_errno values:
|
||||
// - ME_MAXREACHED reached max plugins
|
||||
MPlugin* MPluginList::add(MPlugin* padd)
|
||||
{
|
||||
int i;
|
||||
MPlugin* iplug;
|
||||
|
||||
// Find either:
|
||||
// - a slot in the list that's not being used
|
||||
// - the end of the list
|
||||
for (i = 0; i < endlist && plist[i].status != PL_EMPTY; i++)
|
||||
;
|
||||
auto iplug = find_empty_slot();
|
||||
|
||||
// couldn't find a slot to use
|
||||
if (i == size)
|
||||
if (!iplug)
|
||||
{
|
||||
META_ERROR("Couldn't add plugin '%s' to list; reached max plugins (%d)", padd->file, i);
|
||||
META_ERROR("Couldn't add plugin '%s' to list; reached max plugins (%d)", padd->file, MAX_PLUGINS);
|
||||
RETURN_ERRNO(NULL, ME_MAXREACHED);
|
||||
}
|
||||
|
||||
// if we found the end of the list, advance end marker
|
||||
if (i == endlist)
|
||||
endlist++;
|
||||
|
||||
iplug = &plist[i];
|
||||
|
||||
// copy filename into this free slot
|
||||
Q_strncpy(iplug->filename, padd->filename, sizeof iplug->filename - 1);
|
||||
iplug->filename[sizeof iplug->filename - 1] = '\0';
|
||||
@ -337,13 +329,8 @@ MPlugin* MPluginList::add(MPlugin* padd)
|
||||
iplug->pathname[sizeof iplug->pathname - 1] = '\0';
|
||||
normalize_pathname(iplug->pathname);
|
||||
|
||||
// copy source
|
||||
iplug->source = padd->source;
|
||||
|
||||
// copy status
|
||||
iplug->status = padd->status;
|
||||
|
||||
//copy other things
|
||||
iplug->source_plugin_index = padd->source_plugin_index;
|
||||
|
||||
return iplug;
|
||||
@ -375,7 +362,7 @@ bool MPluginList::ini_startup()
|
||||
}
|
||||
|
||||
META_LOG("ini: Begin reading plugins list: %s", inifile);
|
||||
for (n = 0 , ln = 1; !feof(fp) && fgets(line, sizeof(line), fp) && n < size; ln++)
|
||||
for (n = 0 , ln = 1; !feof(fp) && fgets(line, sizeof(line), fp) && n < MAX_PLUGINS; ln++)
|
||||
{
|
||||
// Remove line terminations.
|
||||
char* cp;
|
||||
@ -420,7 +407,7 @@ bool MPluginList::ini_startup()
|
||||
plist[n].action = PA_LOAD;
|
||||
META_LOG("ini: Read plugin config for: %s", plist[n].desc);
|
||||
n++;
|
||||
endlist = n; // mark end of list
|
||||
max_loaded_count = n; // mark end of list
|
||||
}
|
||||
META_LOG("ini: Finished reading plugins list: %s; Found %d plugins to load", inifile, n);
|
||||
|
||||
@ -452,7 +439,7 @@ bool MPluginList::ini_refresh()
|
||||
}
|
||||
|
||||
META_LOG("ini: Begin re-reading plugins list: %s", inifile);
|
||||
for (n = 0 , ln = 1; !feof(fp) && fgets(line, sizeof(line), fp) && n < size; ln++)
|
||||
for (n = 0 , ln = 1; !feof(fp) && fgets(line, sizeof(line), fp) && n < MAX_PLUGINS; ln++)
|
||||
{
|
||||
// Remove line terminations.
|
||||
char *cp;
|
||||
@ -655,7 +642,7 @@ bool MPluginList::load()
|
||||
}
|
||||
|
||||
META_LOG("dll: Loading plugins...");
|
||||
for (int i = 0; i < endlist; i++)
|
||||
for (int i = 0; i < max_loaded_count; i++)
|
||||
{
|
||||
if (plist[i].status < PL_VALID)
|
||||
continue;
|
||||
@ -690,7 +677,7 @@ bool MPluginList::refresh(PLUG_LOADTIME now)
|
||||
}
|
||||
|
||||
META_LOG("dll: Updating plugins...");
|
||||
for (i = 0; i < endlist; i++)
|
||||
for (i = 0; i < max_loaded_count; i++)
|
||||
{
|
||||
iplug = &plist[i];
|
||||
if (iplug->status < PL_VALID)
|
||||
@ -767,7 +754,7 @@ bool MPluginList::refresh(PLUG_LOADTIME now)
|
||||
// - none
|
||||
void MPluginList::unpause_all(void)
|
||||
{
|
||||
for (int i = 0; i < endlist; i++)
|
||||
for (int i = 0; i < max_loaded_count; i++)
|
||||
{
|
||||
auto iplug = &plist[i];
|
||||
if (iplug->status == PL_PAUSED)
|
||||
@ -781,7 +768,7 @@ void MPluginList::unpause_all(void)
|
||||
// - none
|
||||
void MPluginList::retry_all(PLUG_LOADTIME now)
|
||||
{
|
||||
for (int i = 0; i < endlist; i++)
|
||||
for (int i = 0; i < max_loaded_count; i++)
|
||||
{
|
||||
auto iplug = &plist[i];
|
||||
if (iplug->action != PA_NONE)
|
||||
@ -806,7 +793,7 @@ void MPluginList::show(int source_index)
|
||||
META_CONS(" %*s %-*s %-4s %-4s %-*s v%-*s %-*s %-5s %-5s", WIDTH_MAX_PLUGINS, "", sizeof(desc) - 1, "description", "stat", "pend",
|
||||
sizeof(file) - 1, "file", sizeof(vers) - 1, "ers", 2 + WIDTH_MAX_PLUGINS, "src", "load ", "unlod");
|
||||
|
||||
for (int i = 0; i < endlist; i++)
|
||||
for (int i = 0; i < max_loaded_count; i++)
|
||||
{
|
||||
pl = &plist[i];
|
||||
if (pl->status < PL_VALID)
|
||||
@ -857,7 +844,7 @@ void MPluginList::show_client(edict_t *pEntity)
|
||||
MPlugin *pl;
|
||||
META_CLIENT(pEntity, "Currently running plugins:");
|
||||
|
||||
for (int i = 0; i < endlist; i++)
|
||||
for (int i = 0; i < max_loaded_count; i++)
|
||||
{
|
||||
pl = &plist[i];
|
||||
if (pl->status != PL_RUNNING || !pl->info)
|
||||
@ -880,7 +867,7 @@ bool MPluginList::found_child_plugins(int source_index) const
|
||||
if (source_index <= 0)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < endlist; i++)
|
||||
for (int i = 0; i < max_loaded_count; i++)
|
||||
{
|
||||
if (plist[i].status < PL_VALID)
|
||||
continue;
|
||||
@ -897,7 +884,7 @@ void MPluginList::clear_source_plugin_index(int source_index)
|
||||
if (source_index <= 0)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < endlist; i++)
|
||||
for (int i = 0; i < max_loaded_count; i++)
|
||||
{
|
||||
if (plist[i].status < PL_VALID)
|
||||
continue;
|
||||
|
@ -23,7 +23,8 @@ public:
|
||||
MPlugin *find_memloc(void *memptr); // find by memory location
|
||||
MPlugin *find_match(const char *prefix); // find by partial prefix match
|
||||
MPlugin *find_match(MPlugin *pmatch); // find by platform_match()
|
||||
MPlugin *find(DLHANDLE handle); // find by handle
|
||||
MPlugin *find(module_handle_t handle); // find by handle
|
||||
MPlugin *find_empty_slot();
|
||||
MPlugin *add(MPlugin *padd);
|
||||
|
||||
bool found_child_plugins(int source_index) const;
|
||||
@ -42,8 +43,7 @@ public:
|
||||
void clear_source_plugin_index(int source_index);
|
||||
|
||||
public:
|
||||
int loaded_count; // index of last used entry
|
||||
int size; // size of list, ie MAX_PLUGINS
|
||||
int max_loaded_count; // index of last used entry
|
||||
char inifile[PATH_MAX]; // full pathname
|
||||
MPlugin plist[MAX_PLUGINS]; // array of plugins
|
||||
};
|
||||
|
@ -382,7 +382,7 @@ char *MPlugin::resolve_dirs(char *path)
|
||||
// dir/file
|
||||
// meta_errno values:
|
||||
// - none
|
||||
char *MPlugin::resolve_prefix(char *path)
|
||||
char *MPlugin::resolve_prefix(char *path) const
|
||||
{
|
||||
struct stat st;
|
||||
char *cp, *fname;
|
||||
@ -432,7 +432,7 @@ char *MPlugin::resolve_prefix(char *path)
|
||||
// path_i386.so, path_i486.so, etc (if linux)
|
||||
// meta_errno values:
|
||||
// - none
|
||||
char *MPlugin::resolve_suffix(char *path)
|
||||
char *MPlugin::resolve_suffix(char *path) const
|
||||
{
|
||||
struct stat st;
|
||||
static char buf[PATH_MAX ];
|
||||
@ -595,12 +595,10 @@ bool MPlugin::load(PLUG_LOADTIME now)
|
||||
META_ERROR("dll: Skipping plugin '%s'; couldn't query", desc);
|
||||
if (meta_errno != ME_DLOPEN)
|
||||
{
|
||||
if (DLCLOSE(handle) != 0)
|
||||
if (!sys_module.unload())
|
||||
{
|
||||
META_ERROR("dll: Couldn't close plugin file '%s': %s", file, DLERROR());
|
||||
META_ERROR("dll: Couldn't close plugin file '%s': %s", file, "invalid handle");
|
||||
}
|
||||
else
|
||||
handle = NULL;
|
||||
}
|
||||
status = PL_BADFILE;
|
||||
info = NULL; //prevent crash
|
||||
@ -682,10 +680,9 @@ bool MPlugin::query(void)
|
||||
META_QUERY_FN pfn_query;
|
||||
|
||||
// open the plugin DLL
|
||||
if (!(handle = DLOPEN(pathname)))
|
||||
if (!sys_module.load(pathname))
|
||||
{
|
||||
META_ERROR("dll: Failed query plugin '%s'; Couldn't open file '%s': %s",
|
||||
desc, pathname, DLERROR());
|
||||
META_ERROR("dll: Failed query plugin '%s'; Couldn't open file '%s': %s", desc, pathname, sys_module.getloaderror());
|
||||
RETURN_ERRNO(false, ME_DLOPEN);
|
||||
}
|
||||
|
||||
@ -699,10 +696,10 @@ bool MPlugin::query(void)
|
||||
// GiveFnptrsToDll before Meta_Query, because the latter typically uses
|
||||
// engine functions like AlertMessage, which have to be passed along via
|
||||
// GiveFnptrsToDll.
|
||||
pfn_query = (META_QUERY_FN) DLSYM(handle, "Meta_Query");
|
||||
pfn_query = (META_QUERY_FN)sys_module.getsym("Meta_Query");
|
||||
if (!pfn_query)
|
||||
{
|
||||
META_ERROR("dll: Failed query plugin '%s'; Couldn't find Meta_Query(): %s", desc, DLERROR());
|
||||
META_ERROR("dll: Failed query plugin '%s'; Couldn't find Meta_Query(): %s", desc, "function not found");
|
||||
// caller will dlclose()
|
||||
RETURN_ERRNO(false, ME_DLMISSING);
|
||||
}
|
||||
@ -721,7 +718,7 @@ bool MPlugin::query(void)
|
||||
// This passes nothing and returns nothing, and the routine in the
|
||||
// plugin can NOT use any g_engine functions, as they haven't been
|
||||
// provided yet (done next, in GiveFnptrsToDll).
|
||||
pfn_init = (META_INIT_FN) DLSYM(handle, "Meta_Init");
|
||||
pfn_init = (META_INIT_FN)sys_module.getsym("Meta_Init");
|
||||
if (pfn_init)
|
||||
{
|
||||
pfn_init();
|
||||
@ -734,10 +731,10 @@ bool MPlugin::query(void)
|
||||
}
|
||||
|
||||
// pass on engine function table and globals to plugin
|
||||
if (!(pfn_give_engfuncs = (GIVE_ENGINE_FUNCTIONS_FN) DLSYM(handle, "GiveFnptrsToDll")))
|
||||
if (!(pfn_give_engfuncs = (GIVE_ENGINE_FUNCTIONS_FN)sys_module.getsym("GiveFnptrsToDll")))
|
||||
{
|
||||
// META_ERROR("dll: Couldn't find GiveFnptrsToDll() in plugin '%s': %s", desc, DLERROR());
|
||||
META_ERROR("dll: Failed query plugin '%s'; Couldn't find GiveFnptrsToDll(): %s", desc, DLERROR());
|
||||
META_ERROR("dll: Failed query plugin '%s'; Couldn't find GiveFnptrsToDll(): %s", desc, "function not found");
|
||||
// caller will dlclose()
|
||||
RETURN_ERRNO(false, ME_DLMISSING);
|
||||
}
|
||||
@ -880,9 +877,9 @@ bool MPlugin::attach(PLUG_LOADTIME now)
|
||||
}
|
||||
static_cast<meta_new_dll_functions_t *>(gamedll_funcs.newapi_table)->set_from(GameDLL.funcs.newapi_table);
|
||||
}
|
||||
if (!(pfn_attach = (META_ATTACH_FN) DLSYM(handle, "Meta_Attach")))
|
||||
if (!(pfn_attach = (META_ATTACH_FN)sys_module.getsym("Meta_Attach")))
|
||||
{
|
||||
META_ERROR("dll: Failed attach plugin '%s': Couldn't find Meta_Attach(): %s", desc, DLERROR());
|
||||
META_ERROR("dll: Failed attach plugin '%s': Couldn't find Meta_Attach(): %s", desc, "function not found");
|
||||
// caller will dlclose()
|
||||
RETURN_ERRNO(false, ME_DLMISSING);
|
||||
}
|
||||
@ -1082,13 +1079,12 @@ bool MPlugin::unload(PLUG_LOADTIME now, PL_UNLOAD_REASON reason, PL_UNLOAD_REASO
|
||||
|
||||
// Close the file. Note: after this, attempts to reference any memory
|
||||
// locations in the file will produce a segfault.
|
||||
if (DLCLOSE(handle) != 0)
|
||||
if (!sys_module.unload())
|
||||
{
|
||||
// If DLL cannot be closed, OS is badly broken or we are giving invalid handle.
|
||||
// So we don't return here but instead remove plugin from our listings.
|
||||
META_WARNING("dll: Couldn't close plugin file '%s': %s", file, DLERROR());
|
||||
META_WARNING("dll: Couldn't close plugin file '%s': %s", file, "invalid handle");
|
||||
}
|
||||
handle = NULL;
|
||||
|
||||
if (action == PA_UNLOAD)
|
||||
{
|
||||
@ -1118,12 +1114,12 @@ bool MPlugin::detach(PLUG_LOADTIME now, PL_UNLOAD_REASON reason)
|
||||
// If we have no handle, i.e. no dll loaded, we return true because the
|
||||
// dll is obviously detached. We shouldn't call DLSYM() with a NULL
|
||||
// handle since this will DLSYM() ourself.
|
||||
if (!handle)
|
||||
if (!sys_module.gethandle())
|
||||
return true;
|
||||
|
||||
if (!(pfn_detach = (META_DETACH_FN) DLSYM(handle, "Meta_Detach")))
|
||||
if (!(pfn_detach = (META_DETACH_FN)sys_module.getsym("Meta_Detach")))
|
||||
{
|
||||
META_ERROR("dll: Error detach plugin '%s': Couldn't find Meta_Detach(): %s", desc, DLERROR());
|
||||
META_ERROR("dll: Error detach plugin '%s': Couldn't find Meta_Detach(): %s", desc, "function not found");
|
||||
// caller will dlclose()
|
||||
RETURN_ERRNO(false, ME_DLMISSING);
|
||||
}
|
||||
@ -1279,13 +1275,12 @@ bool MPlugin::clear(void)
|
||||
}
|
||||
// If file is open, close the file. Note: after this, attempts to
|
||||
// reference any memory locations in the file will produce a segfault.
|
||||
if (handle && DLCLOSE(handle) != 0)
|
||||
if (!sys_module.unload())
|
||||
{
|
||||
META_ERROR("dll: Couldn't close plugin file '%s': %s", file, DLERROR());
|
||||
META_ERROR("dll: Couldn't close plugin file '%s': %s", file, "invalid handle");
|
||||
status = PL_FAILED;
|
||||
RETURN_ERRNO(false, ME_DLERROR);
|
||||
}
|
||||
handle = NULL;
|
||||
|
||||
if (gamedll_funcs.dllapi_table) Q_free(gamedll_funcs.dllapi_table);
|
||||
if (gamedll_funcs.newapi_table) Q_free(gamedll_funcs.newapi_table);
|
||||
@ -1298,7 +1293,6 @@ bool MPlugin::clear(void)
|
||||
|
||||
status = PL_EMPTY;
|
||||
action = PA_NULL;
|
||||
handle = NULL;
|
||||
info = NULL;
|
||||
time_loaded = 0;
|
||||
dllapi_table = NULL;
|
||||
|
@ -5,9 +5,9 @@
|
||||
|
||||
// Flags to indicate current "load" state of plugin.
|
||||
// NOTE: order is important, as greater/less comparisons are made.
|
||||
enum PLUG_STATUS
|
||||
enum PLUG_STATUS : uint8
|
||||
{
|
||||
PL_EMPTY = 0, // empty slot
|
||||
PL_EMPTY = 0, // empty slot
|
||||
PL_VALID, // has valid info in it
|
||||
PL_BADFILE, // nonexistent file (open failed), or not a valid plugin file (query failed)
|
||||
PL_OPENED, // dlopened and queried
|
||||
@ -17,7 +17,7 @@ enum PLUG_STATUS
|
||||
};
|
||||
|
||||
// Action to take for plugin at next opportunity.
|
||||
enum PLUG_ACTION
|
||||
enum PLUG_ACTION : uint8
|
||||
{
|
||||
PA_NULL = 0,
|
||||
PA_NONE, // no action needed right now
|
||||
@ -29,7 +29,7 @@ enum PLUG_ACTION
|
||||
};
|
||||
|
||||
// Flags to indicate from where the plugin was loaded.
|
||||
enum PLOAD_SOURCE
|
||||
enum PLOAD_SOURCE : uint8
|
||||
{
|
||||
PS_INI = 0, // was loaded from the plugins.ini
|
||||
PS_CMD, // was loaded via a server command
|
||||
@ -37,7 +37,7 @@ enum PLOAD_SOURCE
|
||||
};
|
||||
|
||||
// Flags for how to word description of plugin loadtime.
|
||||
enum STR_LOADTIME
|
||||
enum STR_LOADTIME : uint8
|
||||
{
|
||||
SL_SIMPLE = 0, // single word
|
||||
SL_SHOW, // for "show" output, 5 chars
|
||||
@ -46,21 +46,21 @@ enum STR_LOADTIME
|
||||
};
|
||||
|
||||
// Flags for how to format description of status.
|
||||
enum STR_STATUS
|
||||
enum STR_STATUS : uint8
|
||||
{
|
||||
ST_SIMPLE = 0, // single word
|
||||
ST_SHOW, // for "show" output, 4 chars
|
||||
};
|
||||
|
||||
// Flags for how to format description of action.
|
||||
enum STR_ACTION
|
||||
enum STR_ACTION : uint8
|
||||
{
|
||||
SA_SIMPLE = 0, // single word
|
||||
SA_SHOW, // for "show" output, 4 chars
|
||||
};
|
||||
|
||||
// Flags for how to format description of source.
|
||||
enum STR_SOURCE
|
||||
enum STR_SOURCE : uint8
|
||||
{
|
||||
SO_SIMPLE = 0, // two words
|
||||
SO_SHOW, // for "list" output, 3 chars
|
||||
@ -68,26 +68,13 @@ enum STR_SOURCE
|
||||
|
||||
// An individual plugin.
|
||||
class MPlugin {
|
||||
private:
|
||||
bool query();
|
||||
bool attach(PLUG_LOADTIME now);
|
||||
bool detach(PLUG_LOADTIME now, PL_UNLOAD_REASON reason);
|
||||
gamedll_funcs_t gamedll_funcs;
|
||||
mutil_funcs_t mutil_funcs;
|
||||
|
||||
public:
|
||||
int index; // 1-based
|
||||
char filename[PATH_MAX]; // ie "dlls/mm_test_i386.so", from inifile
|
||||
char *file; // ie "mm_test_i386.so", ptr from filename
|
||||
char desc[MAX_DESC_LEN]; // ie "Test metamod plugin", from inifile
|
||||
char pathname[PATH_MAX]; // UNIQUE, ie "/home/willday/half-life/cstrike/dlls/mm_test_i386.so", built with GameDLL.gamedir
|
||||
int pfspecific; // level of specific platform affinity, used during load time
|
||||
PLUG_STATUS status; // current status of plugin (loaded, etc)
|
||||
PLUG_ACTION action; // what to do with plugin (load, unload, etc)
|
||||
PLOAD_SOURCE source; // source of the request to load the plugin
|
||||
|
||||
DLHANDLE handle; // handle for dlopen, dlsym, etc
|
||||
int index; // 1-based
|
||||
plugin_info_t *info; // information plugin provides about itself
|
||||
CSysModule sys_module;
|
||||
time_t time_loaded; // when plugin was loaded
|
||||
int source_plugin_index; // who loaded this plugin
|
||||
int unloader_index;
|
||||
@ -100,6 +87,15 @@ public:
|
||||
enginefuncs_t *engine_table;
|
||||
enginefuncs_t *engine_post_table;
|
||||
|
||||
gamedll_funcs_t gamedll_funcs;
|
||||
mutil_funcs_t mutil_funcs;
|
||||
|
||||
char filename[PATH_MAX]; // ie "dlls/mm_test_i386.so", from inifile
|
||||
char *file; // ie "mm_test_i386.so", ptr from filename
|
||||
char desc[MAX_DESC_LEN]; // ie "Test metamod plugin", from inifile
|
||||
char pathname[PATH_MAX]; // UNIQUE, ie "/home/willday/half-life/cstrike/dlls/mm_test_i386.so", built with GameDLL.gamedir
|
||||
int pfspecific; // level of specific platform affinity, used during load time
|
||||
|
||||
bool ini_parseline(char *line); // parse line from inifile
|
||||
bool cmd_parseline(const char *line); // parse from console command
|
||||
bool plugin_parseline(const char *fname, int loader_index); // parse from plugin
|
||||
@ -107,8 +103,8 @@ public:
|
||||
|
||||
bool resolve(); // find a matching file on disk
|
||||
char *resolve_dirs(char *path);
|
||||
char *resolve_prefix(char *path);
|
||||
char *resolve_suffix(char *path);
|
||||
char *resolve_prefix(char *path) const;
|
||||
char *resolve_suffix(char *path) const;
|
||||
|
||||
bool platform_match(MPlugin* plugin);
|
||||
|
||||
@ -151,6 +147,11 @@ public:
|
||||
if (info) return str_loadtime(info->unloadable, fmt);
|
||||
else return " -";
|
||||
};
|
||||
|
||||
private:
|
||||
bool query();
|
||||
bool attach(PLUG_LOADTIME now);
|
||||
bool detach(PLUG_LOADTIME now, PL_UNLOAD_REASON reason);
|
||||
};
|
||||
|
||||
// Macros used by MPlugin::show(), to list the functions that the plugin
|
||||
|
@ -172,14 +172,6 @@ void MRegCmdList::show(int plugin_id) const
|
||||
int n = 0;
|
||||
MRegCmd *icmd;
|
||||
|
||||
// If OS doesn't support DLFNAME, then we can't know what the plugin's
|
||||
// registered cvars are.
|
||||
DLFNAME(NULL);
|
||||
if (meta_errno == ME_OSNOTSUP)
|
||||
{
|
||||
META_CONS("Registered commands: unknown (can't get info under this OS)");
|
||||
return;
|
||||
}
|
||||
META_CONS("Registered commands:");
|
||||
for (int i = 0; i < endlist; i++)
|
||||
{
|
||||
@ -375,15 +367,6 @@ void MRegCvarList::show(int plugin_id) const
|
||||
MRegCvar *icvar;
|
||||
char bname[30 + 1], bval[15 + 1]; // +1 for term null
|
||||
|
||||
// If OS doesn't support DLFNAME, then we can't know what the plugin's
|
||||
// registered cvars are.
|
||||
DLFNAME(NULL);
|
||||
if (meta_errno == ME_OSNOTSUP)
|
||||
{
|
||||
META_CONS("Registered cvars: unknown (can't get info under this OS)");
|
||||
return;
|
||||
}
|
||||
|
||||
META_CONS("%-*s %*s %s", sizeof(bname) - 1, "Registered cvars:", sizeof(bval) - 1, "float value", "string value");
|
||||
for (int i = 0; i < endlist; i++)
|
||||
{
|
||||
|
@ -128,4 +128,4 @@ private:
|
||||
MRegMsg mlist[MAX_REG_MSGS]; // array of registered msgs
|
||||
int size; // size of list, ie MAX_REG_MSGS
|
||||
int endlist; // index of last used entry
|
||||
};
|
||||
};
|
||||
|
@ -119,7 +119,7 @@ qboolean EXT_FUNC mutil_CallGameEntity(plid_t plid, const char *entStr, entvars_
|
||||
{
|
||||
plugin_info_t *plinfo = (plugin_info_t *)plid;
|
||||
META_DEBUG(8, ("Looking up game entity '%s' for plugin '%s'", entStr, plinfo->name));
|
||||
ENTITY_FN pfnEntity = (ENTITY_FN) DLSYM(GameDLL.handle, entStr);
|
||||
ENTITY_FN pfnEntity = (ENTITY_FN)GameDLL.sys_module.getsym(entStr);
|
||||
if (!pfnEntity)
|
||||
{
|
||||
META_ERROR("Couldn't find game entity '%s' in game DLL '%s' for plugin '%s'", entStr, GameDLL.name, plinfo->name);
|
||||
@ -268,7 +268,7 @@ int EXT_FUNC mutil_LoadMetaPlugin(plid_t plid, const char* fname, PLUG_LOADTIME
|
||||
else
|
||||
{
|
||||
if (plugin_handle)
|
||||
*plugin_handle = (void *)pl_loaded->handle;
|
||||
*plugin_handle = (void *)pl_loaded->sys_module.gethandle();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -310,7 +310,7 @@ int EXT_FUNC mutil_UnloadMetaPluginByHandle(plid_t plid, void *plugin_handle, PL
|
||||
return ME_ARGUMENT;
|
||||
}
|
||||
|
||||
if (!(findp = g_plugins->find((DLHANDLE)plugin_handle)))
|
||||
if (!(findp = g_plugins->find((module_handle_t)plugin_handle)))
|
||||
return ME_NOTFOUND;
|
||||
|
||||
meta_errno = ME_NOERROR;
|
||||
|
@ -1,36 +1,128 @@
|
||||
#include "precompiled.h"
|
||||
|
||||
bool dlclose_handle_invalid;
|
||||
CSysModule::CSysModule() : m_handle(0), m_base(0), m_size(0)
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
// Since windows doesn't provide a verison of strtok_r(), we include one
|
||||
// here. This may or may not operate exactly like strtok_r(), but does
|
||||
// what we need it it do.
|
||||
char *my_strtok_r(char *s, const char *delim, char **ptrptr)
|
||||
module_handle_t CSysModule::load(const char* filepath)
|
||||
{
|
||||
char *begin = nullptr;
|
||||
char *end = nullptr;
|
||||
char *rest = nullptr;
|
||||
if (s)
|
||||
begin = s;
|
||||
else
|
||||
begin = *ptrptr;
|
||||
if (!begin)
|
||||
return nullptr;
|
||||
m_handle = LoadLibrary(filepath);
|
||||
|
||||
end = strpbrk(begin, delim);
|
||||
if (end)
|
||||
{
|
||||
*end = '\0';
|
||||
rest = end + 1;
|
||||
*ptrptr = rest + strspn(rest, delim);
|
||||
MODULEINFO module_info;
|
||||
if (GetModuleInformation(GetCurrentProcess(), m_handle, &module_info, sizeof(module_info))) {
|
||||
m_base = (uintptr_t)module_info.lpBaseOfDll;
|
||||
m_size = module_info.SizeOfImage;
|
||||
}
|
||||
else
|
||||
*ptrptr = nullptr;
|
||||
|
||||
return begin;
|
||||
return m_handle;
|
||||
}
|
||||
|
||||
bool CSysModule::unload()
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
if (m_handle) {
|
||||
ret = FreeLibrary(m_handle) != ERROR;
|
||||
m_handle = 0;
|
||||
m_base = 0;
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void* CSysModule::getsym(const char* name) const
|
||||
{
|
||||
return GetProcAddress(m_handle, name);
|
||||
}
|
||||
#else
|
||||
static ElfW(Addr) dlsize(void* base)
|
||||
{
|
||||
ElfW(Ehdr) *ehdr;
|
||||
ElfW(Phdr) *phdr;
|
||||
ElfW(Addr) end;
|
||||
|
||||
ehdr = (ElfW(Ehdr) *)base;
|
||||
|
||||
/* Find the first program header */
|
||||
phdr = (ElfW(Phdr)*)((ElfW(Addr))ehdr + ehdr->e_phoff);
|
||||
|
||||
/* Find the final PT_LOAD segment's extent */
|
||||
for (int i = 0; i < ehdr->e_phnum; ++i)
|
||||
if (phdr[i].p_type == PT_LOAD)
|
||||
end = phdr[i].p_vaddr + phdr[i].p_memsz;
|
||||
|
||||
/* The start (virtual) address is always zero, so just return end.*/
|
||||
return end;
|
||||
}
|
||||
|
||||
module_handle_t CSysModule::load(const char* filepath)
|
||||
{
|
||||
m_handle = dlopen(filepath, RTLD_NOW);
|
||||
|
||||
char buf[1024], dummy[1024], path[260];
|
||||
sprintf(buf, "/proc/%i/maps", getpid());
|
||||
|
||||
FILE* fp = fopen(buf, "r");
|
||||
|
||||
while (fgets(buf, sizeof(buf), fp)) {
|
||||
uintptr_t start, end;
|
||||
|
||||
int args = sscanf(buf, "%x-%x %128s %128s %128s %128s %255s", &start, &end, dummy, dummy, dummy, dummy, path);
|
||||
if (args != 7) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!Q_stricmp(path, filepath)) {
|
||||
m_base = start;
|
||||
m_size = end - start;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return m_handle;
|
||||
}
|
||||
|
||||
bool CSysModule::unload()
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
if (m_handle) {
|
||||
ret = dlclose(m_handle) != 0;
|
||||
m_handle = 0;
|
||||
m_base = 0;
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void* CSysModule::getsym(const char* name) const
|
||||
{
|
||||
return dlsym(m_handle, name);
|
||||
}
|
||||
#endif
|
||||
|
||||
module_handle_t CSysModule::gethandle() const
|
||||
{
|
||||
return m_handle;
|
||||
}
|
||||
|
||||
bool CSysModule::contain(void* addr) const
|
||||
{
|
||||
return addr && uintptr_t(addr) > m_base && uintptr_t(addr) < m_base + m_size;
|
||||
}
|
||||
|
||||
const char* CSysModule::getloaderror()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return str_GetLastError();
|
||||
#else
|
||||
return dlerror;
|
||||
#endif
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
#ifdef _WIN32
|
||||
// Windows doesn't provide a functon analagous to dlerr() that returns a
|
||||
@ -44,70 +136,16 @@ const char *str_GetLastError()
|
||||
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&buf, MAX_STRBUF_LEN - 1, NULL);
|
||||
return buf;
|
||||
}
|
||||
|
||||
const char* str_os_error()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return str_GetLastError();
|
||||
#else
|
||||
return strerror(errno);
|
||||
#endif
|
||||
|
||||
// Find the filename of the DLL/shared-lib where the given memory location
|
||||
// exists.
|
||||
#if defined(linux) || defined(__APPLE__)
|
||||
// Errno values:
|
||||
// - ME_NOTFOUND couldn't find a sharedlib that contains memory location
|
||||
const char *DLFNAME(void *memptr)
|
||||
{
|
||||
Dl_info dli;
|
||||
Q_memset(&dli, 0, sizeof(dli));
|
||||
if (dladdr(memptr, &dli))
|
||||
return dli.dli_fname;
|
||||
else
|
||||
RETURN_ERRNO(NULL, ME_NOTFOUND);
|
||||
}
|
||||
#elif defined(_WIN32)
|
||||
// Implementation for win32 provided by Jussi Kivilinna <kijuhe00@rhea.otol.fi>:
|
||||
//
|
||||
// 1. Get memory location info on memptr with VirtualQuery.
|
||||
// 2. Check if memory location info is valid and use MBI.AllocationBase
|
||||
// as module start point.
|
||||
// 3. Get module file name with GetModuleFileName.
|
||||
//
|
||||
// Simple and should work pretty much same way as 'dladdr' in linux.
|
||||
// VirtualQuery and GetModuleFileName work even with win32s.
|
||||
//
|
||||
// Note that GetModuleFileName returns longfilenames rather than 8.3.
|
||||
//
|
||||
// Note also, the returned filename is local static storage, and should be
|
||||
// copied by caller if it needs to keep it around.
|
||||
//
|
||||
// Also note, normalize_pathname() should really be done by the caller, but
|
||||
// is done here to preserve "const char *" return consistent with linux
|
||||
// version.
|
||||
//
|
||||
// Errno values:
|
||||
// - ME_NOTFOUND couldn't find a DLL that contains memory location
|
||||
const char *DLFNAME(void *memptr)
|
||||
{
|
||||
MEMORY_BASIC_INFORMATION MBI;
|
||||
static char fname[PATH_MAX];
|
||||
|
||||
if (!VirtualQuery(memptr, &MBI, sizeof(MBI)))
|
||||
RETURN_ERRNO(NULL, ME_NOTFOUND);
|
||||
|
||||
if (MBI.State != MEM_COMMIT)
|
||||
RETURN_ERRNO(NULL, ME_NOTFOUND);
|
||||
|
||||
if (!MBI.AllocationBase)
|
||||
RETURN_ERRNO(NULL, ME_NOTFOUND);
|
||||
|
||||
// MSDN indicates that GetModuleFileName will leave string
|
||||
// null-terminated, even if it's truncated because buffer is too small.
|
||||
if (!GetModuleFileName((HMODULE)MBI.AllocationBase, fname, sizeof(fname) - 1))
|
||||
RETURN_ERRNO(NULL, ME_NOTFOUND);
|
||||
if (!fname[0])
|
||||
RETURN_ERRNO(NULL, ME_NOTFOUND);
|
||||
|
||||
normalize_pathname(fname);
|
||||
return fname;
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
#endif
|
||||
|
||||
// Determine whether the given memory location is valid (ie whether we
|
||||
// should expect to be able to reference strings or functions at this
|
||||
|
@ -1,10 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
// Various differences between WIN32 and Linux.
|
||||
#include "types_meta.h" // bool
|
||||
#include "mreg.h" // REG_CMD_FN, etc
|
||||
#include "log_meta.h" // LOG_ERROR, etc
|
||||
|
||||
// String describing platform/DLL-type, for matching lines in plugins.ini.
|
||||
#ifdef _WIN32
|
||||
#define UNUSED /**/
|
||||
@ -20,75 +15,31 @@
|
||||
#define PLATFORM_DLEXT ".so"
|
||||
#endif
|
||||
|
||||
extern bool dlclose_handle_invalid;
|
||||
#include "mreg.h"
|
||||
|
||||
// Functions & types for DLL open/close/etc operations.
|
||||
#ifdef _WIN32
|
||||
typedef HINSTANCE DLHANDLE;
|
||||
typedef FARPROC DLFUNC;
|
||||
inline DLHANDLE DLOPEN(const char *filename)
|
||||
{
|
||||
return LoadLibraryA(filename);
|
||||
}
|
||||
inline DLFUNC DLSYM(DLHANDLE handle, const char *string)
|
||||
{
|
||||
return GetProcAddress(handle, string);
|
||||
}
|
||||
inline int DLCLOSE(DLHANDLE handle)
|
||||
{
|
||||
if (!handle)
|
||||
{
|
||||
dlclose_handle_invalid = true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
dlclose_handle_invalid = false;
|
||||
// NOTE: Windows FreeLibrary returns success=nonzero, fail=zero,
|
||||
// which is the opposite of the unix convention, thus the '!'.
|
||||
return !FreeLibrary(handle);
|
||||
}
|
||||
// Windows doesn't provide a function corresponding to dlerror(), so
|
||||
// we make our own.
|
||||
const char *str_GetLastError();
|
||||
inline const char *DLERROR()
|
||||
{
|
||||
if (dlclose_handle_invalid)
|
||||
return "Invalid handle.";
|
||||
|
||||
return str_GetLastError();
|
||||
}
|
||||
typedef HINSTANCE module_handle_t;
|
||||
#else
|
||||
typedef void *DLHANDLE;
|
||||
typedef void *DLFUNC;
|
||||
inline DLHANDLE DLOPEN(const char *filename)
|
||||
{
|
||||
return dlopen(filename, RTLD_NOW);
|
||||
}
|
||||
inline DLFUNC DLSYM(DLHANDLE handle, const char *string)
|
||||
{
|
||||
return dlsym(handle, string);
|
||||
}
|
||||
// dlclose crashes if handle is null.
|
||||
inline int DLCLOSE(DLHANDLE handle)
|
||||
{
|
||||
if (!handle)
|
||||
{
|
||||
dlclose_handle_invalid = true;
|
||||
return 1;
|
||||
}
|
||||
dlclose_handle_invalid = false;
|
||||
return dlclose(handle);
|
||||
}
|
||||
inline const char *DLERROR()
|
||||
{
|
||||
if (dlclose_handle_invalid)
|
||||
return "Invalid handle.";
|
||||
|
||||
return dlerror();
|
||||
}
|
||||
typedef void* module_handle_t;
|
||||
#endif
|
||||
|
||||
const char *DLFNAME(void *memptr);
|
||||
class CSysModule
|
||||
{
|
||||
public:
|
||||
CSysModule();
|
||||
module_handle_t load(const char* filename);
|
||||
bool unload();
|
||||
void* getsym(const char* name) const;
|
||||
module_handle_t gethandle() const;
|
||||
bool contain(void* addr) const;
|
||||
static const char* getloaderror();
|
||||
|
||||
private:
|
||||
module_handle_t m_handle;
|
||||
uintptr_t m_base;
|
||||
uintptr_t m_size;
|
||||
};
|
||||
|
||||
bool IS_VALID_PTR(void *memptr);
|
||||
|
||||
// Attempt to call the given function pointer, without segfaulting.
|
||||
@ -96,15 +47,9 @@ bool os_safe_call(REG_CMD_FN pfn);
|
||||
|
||||
// Windows doesn't have an strtok_r() routine, so we write our own.
|
||||
#ifdef _WIN32
|
||||
#define strtok_r(s, delim, ptrptr) my_strtok_r(s, delim, ptrptr)
|
||||
char *my_strtok_r(char *s, const char *delim, char **ptrptr);
|
||||
#else
|
||||
// Linux doesn't have an strlwr() routine, so we write our own.
|
||||
#define strlwr(s) my_strlwr(s)
|
||||
char *my_strlwr(char *s);
|
||||
#define strtok_r(s, delim, ptrptr) mm_strtok_r(s, delim, ptrptr)
|
||||
#endif // _WIN32
|
||||
|
||||
|
||||
// Set filename and pathname maximum lengths. Note some windows compilers
|
||||
// provide a <limits.h> which is incomplete and/or causes problems; see
|
||||
// doc/windows_notes.txt for more information.
|
||||
@ -165,89 +110,8 @@ bool os_safe_call(REG_CMD_FN pfn);
|
||||
#ifndef S_IWGRP
|
||||
#define S_IWGRP S_IWUSR
|
||||
#endif
|
||||
|
||||
const char *str_GetLastError();
|
||||
#endif // _WIN32
|
||||
|
||||
// Normalize/standardize a pathname.
|
||||
// - For win32, this involves:
|
||||
// - Turning backslashes (\) into slashes (/), so that config files and
|
||||
// Metamod internal code can be simpler and just use slashes (/).
|
||||
// - Turning upper/mixed case into lowercase, since windows is
|
||||
// non-case-sensitive.
|
||||
// - For linux, this requires no work, as paths uses slashes (/) natively,
|
||||
// and pathnames are case-sensitive.
|
||||
#if defined(__linux) || defined(__APPLE__)
|
||||
#define normalize_pathname(a)
|
||||
#elif defined(_WIN32)
|
||||
inline void normalize_pathname(char *path)
|
||||
{
|
||||
char *cp;
|
||||
|
||||
META_DEBUG(8, ("normalize: %s", path));
|
||||
for (cp = path; *cp; cp++)
|
||||
{
|
||||
if (isupper(*cp)) *cp = tolower(*cp);
|
||||
if (*cp == '\\') *cp = '/';
|
||||
}
|
||||
|
||||
META_DEBUG(8, ("normalized: %s", path));
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
// Indicate if pathname appears to be an absolute-path. Under linux this
|
||||
// is a leading slash (/). Under win32, this can be:
|
||||
// - a drive-letter path (ie "D:blah" or "C:\blah")
|
||||
// - a toplevel path (ie "\blah")
|
||||
// - a UNC network address (ie "\\srv1\blah").
|
||||
// Also, handle both native and normalized pathnames.
|
||||
inline int is_absolute_path(const char *path)
|
||||
{
|
||||
if (path[0] == '/') return TRUE;
|
||||
#ifdef _WIN32
|
||||
if (path[1] == ':') return TRUE;
|
||||
if (path[0] == '\\') return TRUE;
|
||||
#endif // _WIN32
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
// Buffer pointed to by resolved_name is assumed to be able to store a
|
||||
// string of PATH_MAX length.
|
||||
inline char *realpath(const char *file_name, char *resolved_name)
|
||||
{
|
||||
int ret;
|
||||
ret = GetFullPathName(file_name, PATH_MAX, resolved_name, NULL);
|
||||
if (ret > PATH_MAX)
|
||||
{
|
||||
errno = ENAMETOOLONG;
|
||||
return NULL;
|
||||
}
|
||||
else if (ret > 0)
|
||||
{
|
||||
HANDLE handle;
|
||||
WIN32_FIND_DATA find_data;
|
||||
handle = FindFirstFile(resolved_name, &find_data);
|
||||
if (INVALID_HANDLE_VALUE == handle)
|
||||
{
|
||||
errno = ENOENT;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FindClose(handle);
|
||||
normalize_pathname(resolved_name);
|
||||
return resolved_name;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
// Generic "error string" from a recent OS call. For linux, this is based
|
||||
// on errno. For win32, it's based on GetLastError.
|
||||
inline const char *str_os_error()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return str_GetLastError();
|
||||
#else
|
||||
return strerror(errno);
|
||||
#endif
|
||||
}
|
||||
const char* str_os_error();
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
#include "version/appversion.h"
|
||||
|
||||
#define PSAPI_VERSION 1
|
||||
|
||||
#if defined(linux) || defined(__APPLE__)
|
||||
// enable extra routines in system header files, like dladdr
|
||||
#ifndef _GNU_SOURCE
|
||||
|
@ -80,13 +80,12 @@ void EXT_FUNC meta_command_handler()
|
||||
// to a generic command-handler function (see above).
|
||||
void EXT_FUNC meta_AddServerCommand(char *cmd_name, void (*function)())
|
||||
{
|
||||
MPlugin *iplug = NULL;
|
||||
MRegCmd *icmd = NULL;
|
||||
MPlugin *iplug = g_plugins->find_memloc(function);
|
||||
|
||||
META_DEBUG(4, ("called: meta_AddServerCommand; cmd_name=%s, function=%d", cmd_name, function));
|
||||
|
||||
// try to find which plugin is registering this command
|
||||
if (!(iplug = g_plugins->find_memloc((void *)function)))
|
||||
if (!iplug)
|
||||
{
|
||||
// if this isn't supported on this OS, don't log an error
|
||||
if (meta_errno != ME_OSNOTSUP)
|
||||
@ -94,7 +93,7 @@ void EXT_FUNC meta_AddServerCommand(char *cmd_name, void (*function)())
|
||||
}
|
||||
|
||||
// See if this command was previously registered, ie a "reloaded" plugin.
|
||||
icmd = g_regCmds->find(cmd_name);
|
||||
auto icmd = g_regCmds->find(cmd_name);
|
||||
if (!icmd)
|
||||
{
|
||||
// If not found, add.
|
||||
@ -134,27 +133,18 @@ void EXT_FUNC meta_AddServerCommand(char *cmd_name, void (*function)())
|
||||
// it will fail to work properly.
|
||||
void EXT_FUNC meta_CVarRegister(cvar_t *pCvar)
|
||||
{
|
||||
MPlugin *iplug = nullptr;
|
||||
MRegCvar *icvar = nullptr;
|
||||
MPlugin *iplug = g_plugins->find_memloc(pCvar);
|
||||
|
||||
META_DEBUG(4, ("called: meta_CVarRegister; name=%s", pCvar->name));
|
||||
|
||||
if (!strncmp(pCvar->name, "iz_", 3))
|
||||
__asm int 3;
|
||||
|
||||
// try to find which plugin is registering this cvar
|
||||
if (!(iplug = g_plugins->find_memloc((void *)pCvar)))
|
||||
if (!iplug)
|
||||
{
|
||||
// if this isn't supported on this OS, don't log an error
|
||||
if (meta_errno != ME_OSNOTSUP)
|
||||
// Note: if cvar_t was malloc'd by the plugin, we can't
|
||||
// determine the calling plugin. Thus, this becomes a Debug
|
||||
// rather than Error message.
|
||||
META_DEBUG(1, ("Failed to find memloc for regcvar '%s'", pCvar->name));
|
||||
}
|
||||
|
||||
// See if this cvar was previously registered, ie a "reloaded" plugin.
|
||||
icvar = g_regCvars->find(pCvar->name);
|
||||
auto icvar = g_regCvars->find(pCvar->name);
|
||||
if (!icvar)
|
||||
{
|
||||
// If not found, add.
|
||||
|
@ -44,12 +44,11 @@ C_DLLEXPORT int Server_GetBlendingInterface(int version,
|
||||
if (!getblend)
|
||||
{
|
||||
META_DEBUG(6, ("Looking up Server_GetBlendingInterface"));
|
||||
getblend = (GETBLENDAPI_FN) DLSYM(GameDLL.handle,
|
||||
"Server_GetBlendingInterface");
|
||||
getblend = (GETBLENDAPI_FN)GameDLL.sys_module.getsym("Server_GetBlendingInterface");
|
||||
}
|
||||
if (!getblend)
|
||||
{
|
||||
META_DEBUG(6, ("Couldn't find Server_GetBlendingInterface in game DLL '%s': %s", GameDLL.name, DLERROR()));
|
||||
META_DEBUG(6, ("Couldn't find Server_GetBlendingInterface in game DLL '%s': %s", GameDLL.name, "function not found"));
|
||||
missing = 1;
|
||||
return 0;
|
||||
}
|
||||
|
@ -58,3 +58,83 @@ void execmem_allocator::allocate_page()
|
||||
m_used = 0;
|
||||
m_pages.push_back(page);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
// Since windows doesn't provide a verison of strtok_r(), we include one
|
||||
// here. This may or may not operate exactly like strtok_r(), but does
|
||||
// what we need it it do.
|
||||
char *mm_strtok_r(char *s, const char *delim, char **ptrptr)
|
||||
{
|
||||
char *begin = nullptr;
|
||||
char *end = nullptr;
|
||||
char *rest = nullptr;
|
||||
if (s)
|
||||
begin = s;
|
||||
else
|
||||
begin = *ptrptr;
|
||||
if (!begin)
|
||||
return nullptr;
|
||||
|
||||
end = strpbrk(begin, delim);
|
||||
if (end) {
|
||||
*end = '\0';
|
||||
rest = end + 1;
|
||||
*ptrptr = rest + strspn(rest, delim);
|
||||
}
|
||||
else
|
||||
*ptrptr = nullptr;
|
||||
|
||||
return begin;
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
void normalize_pathname(char *path)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
char *cp;
|
||||
|
||||
META_DEBUG(8, ("normalize: %s", path));
|
||||
for (cp = path; *cp; cp++) {
|
||||
if (isupper(*cp)) *cp = tolower(*cp);
|
||||
if (*cp == '\\') *cp = '/';
|
||||
}
|
||||
|
||||
META_DEBUG(8, ("normalized: %s", path));
|
||||
#endif
|
||||
}
|
||||
|
||||
bool is_absolute_path(const char *path)
|
||||
{
|
||||
if (path[0] == '/') return true;
|
||||
#ifdef _WIN32
|
||||
if (path[1] == ':') return true;
|
||||
if (path[0] == '\\') return true;
|
||||
#endif // _WIN32
|
||||
return false;
|
||||
}
|
||||
|
||||
char *realpath(const char *file_name, char *resolved_name)
|
||||
{
|
||||
int ret = GetFullPathName(file_name, PATH_MAX, resolved_name, NULL);
|
||||
|
||||
if (ret > PATH_MAX) {
|
||||
errno = ENAMETOOLONG;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
HANDLE handle;
|
||||
WIN32_FIND_DATA find_data;
|
||||
handle = FindFirstFile(resolved_name, &find_data);
|
||||
if (INVALID_HANDLE_VALUE == handle) {
|
||||
errno = ENOENT;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FindClose(handle);
|
||||
normalize_pathname(resolved_name);
|
||||
return resolved_name;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -23,3 +23,11 @@ bool is_yes(const char* str);
|
||||
bool is_no(const char* str);
|
||||
|
||||
const char* LOCALINFO(char* key);
|
||||
|
||||
#ifdef _WIN32
|
||||
char *mm_strtok_r(char *s, const char *delim, char **ptrptr);
|
||||
#endif
|
||||
|
||||
void normalize_pathname(char *path);
|
||||
bool is_absolute_path(const char *path);
|
||||
char *realpath(const char *file_name, char *resolved_name);
|
||||
|
Loading…
Reference in New Issue
Block a user