Files
openal-soft/router/router.c
T
Chris Robinson 8f3d496541 Avoid duplicate path searches in the router
And avoid inadvertently increasing the priority of the system path over the
executable's path, or either of them over the current working directory.
2018-03-21 20:39:04 -07:00

538 lines
15 KiB
C

#include "config.h"
#include "router.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "AL/alc.h"
#include "AL/al.h"
#include "almalloc.h"
#include "version.h"
DriverIface *DriverList = NULL;
int DriverListSize = 0;
static int DriverListSizeMax = 0;
altss_t ThreadCtxDriver;
enum LogLevel LogLevel = LogLevel_Error;
FILE *LogFile;
static void LoadDriverList(void);
BOOL APIENTRY DllMain(HINSTANCE UNUSED(module), DWORD reason, void* UNUSED(reserved))
{
const char *str;
int i;
switch(reason)
{
case DLL_PROCESS_ATTACH:
LogFile = stderr;
str = getenv("ALROUTER_LOGFILE");
if(str && *str != '\0')
{
FILE *f = fopen(str, "w");
if(f == NULL)
ERR("Could not open log file: %s\n", str);
else
LogFile = f;
}
str = getenv("ALROUTER_LOGLEVEL");
if(str && *str != '\0')
{
char *end = NULL;
long l = strtol(str, &end, 0);
if(!end || *end != '\0')
ERR("Invalid log level value: %s\n", str);
else if(l < LogLevel_None || l > LogLevel_Trace)
ERR("Log level out of range: %s\n", str);
else
LogLevel = l;
}
TRACE("Initializing router v0.1-%s %s\n", ALSOFT_GIT_COMMIT_HASH, ALSOFT_GIT_BRANCH);
LoadDriverList();
altss_create(&ThreadCtxDriver, NULL);
InitALC();
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
althrd_thread_detach();
break;
case DLL_PROCESS_DETACH:
ReleaseALC();
altss_delete(ThreadCtxDriver);
for(i = 0;i < DriverListSize;i++)
{
if(DriverList[i].Module)
FreeLibrary(DriverList[i].Module);
}
al_free(DriverList);
DriverList = NULL;
DriverListSize = 0;
DriverListSizeMax = 0;
if(LogFile && LogFile != stderr)
fclose(LogFile);
LogFile = NULL;
althrd_deinit();
break;
}
return TRUE;
}
#ifdef __GNUC__
#define CAST_FUNC(x) (__typeof(x))
#else
#define CAST_FUNC(x) (void*)
#endif
static void AddModule(HMODULE module, const WCHAR *name)
{
DriverIface newdrv;
int err = 0;
int i;
for(i = 0;i < DriverListSize;i++)
{
if(DriverList[i].Module == module)
{
TRACE("Skipping already-loaded module %p\n", module);
FreeLibrary(module);
return;
}
if(wcscmp(DriverList[i].Name, name) == 0)
{
TRACE("Skipping similarly-named module %ls\n", name);
FreeLibrary(module);
return;
}
}
if(DriverListSize == DriverListSizeMax)
{
int newmax = DriverListSizeMax ? DriverListSizeMax<<1 : 4;
void *newlist = al_calloc(DEF_ALIGN, sizeof(DriverList[0])*newmax);
if(!newlist) return;
memcpy(newlist, DriverList, DriverListSize*sizeof(DriverList[0]));
al_free(DriverList);
DriverList = newlist;
DriverListSizeMax = newmax;
}
memset(&newdrv, 0, sizeof(newdrv));
/* Load required functions. */
#define LOAD_PROC(x) do { \
newdrv.x = CAST_FUNC(newdrv.x) GetProcAddress(module, #x); \
if(!newdrv.x) \
{ \
ERR("Failed to find entry point for %s in %ls\n", #x, name); \
err = 1; \
} \
} while(0)
LOAD_PROC(alcCreateContext);
LOAD_PROC(alcMakeContextCurrent);
LOAD_PROC(alcProcessContext);
LOAD_PROC(alcSuspendContext);
LOAD_PROC(alcDestroyContext);
LOAD_PROC(alcGetCurrentContext);
LOAD_PROC(alcGetContextsDevice);
LOAD_PROC(alcOpenDevice);
LOAD_PROC(alcCloseDevice);
LOAD_PROC(alcGetError);
LOAD_PROC(alcIsExtensionPresent);
LOAD_PROC(alcGetProcAddress);
LOAD_PROC(alcGetEnumValue);
LOAD_PROC(alcGetString);
LOAD_PROC(alcGetIntegerv);
LOAD_PROC(alcCaptureOpenDevice);
LOAD_PROC(alcCaptureCloseDevice);
LOAD_PROC(alcCaptureStart);
LOAD_PROC(alcCaptureStop);
LOAD_PROC(alcCaptureSamples);
LOAD_PROC(alEnable);
LOAD_PROC(alDisable);
LOAD_PROC(alIsEnabled);
LOAD_PROC(alGetString);
LOAD_PROC(alGetBooleanv);
LOAD_PROC(alGetIntegerv);
LOAD_PROC(alGetFloatv);
LOAD_PROC(alGetDoublev);
LOAD_PROC(alGetBoolean);
LOAD_PROC(alGetInteger);
LOAD_PROC(alGetFloat);
LOAD_PROC(alGetDouble);
LOAD_PROC(alGetError);
LOAD_PROC(alIsExtensionPresent);
LOAD_PROC(alGetProcAddress);
LOAD_PROC(alGetEnumValue);
LOAD_PROC(alListenerf);
LOAD_PROC(alListener3f);
LOAD_PROC(alListenerfv);
LOAD_PROC(alListeneri);
LOAD_PROC(alListener3i);
LOAD_PROC(alListeneriv);
LOAD_PROC(alGetListenerf);
LOAD_PROC(alGetListener3f);
LOAD_PROC(alGetListenerfv);
LOAD_PROC(alGetListeneri);
LOAD_PROC(alGetListener3i);
LOAD_PROC(alGetListeneriv);
LOAD_PROC(alGenSources);
LOAD_PROC(alDeleteSources);
LOAD_PROC(alIsSource);
LOAD_PROC(alSourcef);
LOAD_PROC(alSource3f);
LOAD_PROC(alSourcefv);
LOAD_PROC(alSourcei);
LOAD_PROC(alSource3i);
LOAD_PROC(alSourceiv);
LOAD_PROC(alGetSourcef);
LOAD_PROC(alGetSource3f);
LOAD_PROC(alGetSourcefv);
LOAD_PROC(alGetSourcei);
LOAD_PROC(alGetSource3i);
LOAD_PROC(alGetSourceiv);
LOAD_PROC(alSourcePlayv);
LOAD_PROC(alSourceStopv);
LOAD_PROC(alSourceRewindv);
LOAD_PROC(alSourcePausev);
LOAD_PROC(alSourcePlay);
LOAD_PROC(alSourceStop);
LOAD_PROC(alSourceRewind);
LOAD_PROC(alSourcePause);
LOAD_PROC(alSourceQueueBuffers);
LOAD_PROC(alSourceUnqueueBuffers);
LOAD_PROC(alGenBuffers);
LOAD_PROC(alDeleteBuffers);
LOAD_PROC(alIsBuffer);
LOAD_PROC(alBufferf);
LOAD_PROC(alBuffer3f);
LOAD_PROC(alBufferfv);
LOAD_PROC(alBufferi);
LOAD_PROC(alBuffer3i);
LOAD_PROC(alBufferiv);
LOAD_PROC(alGetBufferf);
LOAD_PROC(alGetBuffer3f);
LOAD_PROC(alGetBufferfv);
LOAD_PROC(alGetBufferi);
LOAD_PROC(alGetBuffer3i);
LOAD_PROC(alGetBufferiv);
LOAD_PROC(alBufferData);
LOAD_PROC(alDopplerFactor);
LOAD_PROC(alDopplerVelocity);
LOAD_PROC(alSpeedOfSound);
LOAD_PROC(alDistanceModel);
if(!err)
{
ALCint alc_ver[2] = { 0, 0 };
wcsncpy(newdrv.Name, name, 32);
newdrv.Module = module;
newdrv.alcGetIntegerv(NULL, ALC_MAJOR_VERSION, 1, &alc_ver[0]);
newdrv.alcGetIntegerv(NULL, ALC_MINOR_VERSION, 1, &alc_ver[1]);
if(newdrv.alcGetError(NULL) == ALC_NO_ERROR)
newdrv.ALCVer = MAKE_ALC_VER(alc_ver[0], alc_ver[1]);
else
newdrv.ALCVer = MAKE_ALC_VER(1, 0);
#undef LOAD_PROC
#define LOAD_PROC(x) do { \
newdrv.x = CAST_FUNC(newdrv.x) newdrv.alcGetProcAddress(NULL, #x); \
if(!newdrv.x) \
{ \
ERR("Failed to find entry point for %s in %ls\n", #x, name); \
err = 1; \
} \
} while(0)
if(newdrv.alcIsExtensionPresent(NULL, "ALC_EXT_thread_local_context"))
{
LOAD_PROC(alcSetThreadContext);
LOAD_PROC(alcGetThreadContext);
}
}
if(!err)
{
TRACE("Loaded module %p, %ls, ALC %d.%d\n", module, name,
newdrv.ALCVer>>8, newdrv.ALCVer&255);
DriverList[DriverListSize++] = newdrv;
}
#undef LOAD_PROC
}
static void SearchDrivers(WCHAR *path)
{
WCHAR srchPath[MAX_PATH+1] = L"";
WIN32_FIND_DATAW fdata;
HANDLE srchHdl;
TRACE("Searching for drivers in %ls...\n", path);
wcsncpy(srchPath, path, MAX_PATH);
wcsncat(srchPath, L"\\*oal.dll", MAX_PATH - lstrlenW(srchPath));
srchHdl = FindFirstFileW(srchPath, &fdata);
if(srchHdl != INVALID_HANDLE_VALUE)
{
do {
HMODULE mod;
wcsncpy(srchPath, path, MAX_PATH);
wcsncat(srchPath, L"\\", MAX_PATH - lstrlenW(srchPath));
wcsncat(srchPath, fdata.cFileName, MAX_PATH - lstrlenW(srchPath));
TRACE("Found %ls\n", srchPath);
mod = LoadLibraryW(srchPath);
if(!mod)
WARN("Could not load %ls\n", srchPath);
else
AddModule(mod, fdata.cFileName);
} while(FindNextFileW(srchHdl, &fdata));
FindClose(srchHdl);
}
}
static WCHAR *strrchrW(WCHAR *str, WCHAR ch)
{
WCHAR *res = NULL;
while(str && *str != '\0')
{
if(*str == ch)
res = str;
++str;
}
return res;
}
static int GetLoadedModuleDirectory(const WCHAR *name, WCHAR *moddir, DWORD length)
{
HMODULE module = NULL;
WCHAR *sep0, *sep1;
if(name)
{
module = GetModuleHandleW(name);
if(!module) return 0;
}
if(GetModuleFileNameW(module, moddir, length) == 0)
return 0;
sep0 = strrchrW(moddir, '/');
if(sep0) sep1 = strrchrW(sep0+1, '\\');
else sep1 = strrchrW(moddir, '\\');
if(sep1) *sep1 = '\0';
else if(sep0) *sep0 = '\0';
else *moddir = '\0';
return 1;
}
void LoadDriverList(void)
{
WCHAR dll_path[MAX_PATH+1] = L"";
WCHAR cwd_path[MAX_PATH+1] = L"";
WCHAR proc_path[MAX_PATH+1] = L"";
WCHAR sys_path[MAX_PATH+1] = L"";
int len;
if(GetLoadedModuleDirectory(L"OpenAL32.dll", dll_path, MAX_PATH))
TRACE("Got DLL path %ls\n", dll_path);
GetCurrentDirectoryW(MAX_PATH, cwd_path);
len = lstrlenW(cwd_path);
if(len > 0 && (cwd_path[len-1] == '\\' || cwd_path[len-1] == '/'))
cwd_path[len-1] = '\0';
TRACE("Got current working directory %ls\n", cwd_path);
if(GetLoadedModuleDirectory(NULL, proc_path, MAX_PATH))
TRACE("Got proc path %ls\n", proc_path);
GetSystemDirectoryW(sys_path, MAX_PATH);
len = lstrlenW(sys_path);
if(len > 0 && (sys_path[len-1] == '\\' || sys_path[len-1] == '/'))
sys_path[len-1] = '\0';
TRACE("Got system path %ls\n", sys_path);
/* Don't search the DLL's path if it is the same as the current working
* directory, app's path, or system path (don't want to do duplicate
* searches, or increase the priority of the app or system path).
*/
if(dll_path[0] &&
(!cwd_path[0] || wcscmp(dll_path, cwd_path) != 0) &&
(!proc_path[0] || wcscmp(dll_path, proc_path) != 0) &&
(!sys_path[0] || wcscmp(dll_path, sys_path) != 0))
SearchDrivers(dll_path);
if(cwd_path[0] &&
(!proc_path[0] || wcscmp(cwd_path, proc_path) != 0) &&
(!sys_path[0] || wcscmp(cwd_path, sys_path) != 0))
SearchDrivers(cwd_path);
if(proc_path[0] && (!sys_path[0] || wcscmp(proc_path, sys_path) != 0))
SearchDrivers(proc_path);
if(sys_path[0])
SearchDrivers(sys_path);
}
void InitPtrIntMap(PtrIntMap *map)
{
map->keys = NULL;
map->values = NULL;
map->size = 0;
map->capacity = 0;
RWLockInit(&map->lock);
}
void ResetPtrIntMap(PtrIntMap *map)
{
WriteLock(&map->lock);
al_free(map->keys);
map->keys = NULL;
map->values = NULL;
map->size = 0;
map->capacity = 0;
WriteUnlock(&map->lock);
}
ALenum InsertPtrIntMapEntry(PtrIntMap *map, ALvoid *key, ALint value)
{
ALsizei pos = 0;
WriteLock(&map->lock);
if(map->size > 0)
{
ALsizei count = map->size;
do {
ALsizei step = count>>1;
ALsizei i = pos+step;
if(!(map->keys[i] < key))
count = step;
else
{
pos = i+1;
count -= step+1;
}
} while(count > 0);
}
if(pos == map->size || map->keys[pos] != key)
{
if(map->size == map->capacity)
{
ALvoid **keys = NULL;
ALint *values;
ALsizei newcap;
newcap = (map->capacity ? (map->capacity<<1) : 4);
if(newcap > map->capacity)
keys = al_calloc(16, (sizeof(map->keys[0])+sizeof(map->values[0]))*newcap);
if(!keys)
{
WriteUnlock(&map->lock);
return AL_OUT_OF_MEMORY;
}
values = (ALint*)&keys[newcap];
if(map->keys)
{
memcpy(keys, map->keys, map->size*sizeof(map->keys[0]));
memcpy(values, map->values, map->size*sizeof(map->values[0]));
}
al_free(map->keys);
map->keys = keys;
map->values = values;
map->capacity = newcap;
}
if(pos < map->size)
{
memmove(&map->keys[pos+1], &map->keys[pos],
(map->size-pos)*sizeof(map->keys[0]));
memmove(&map->values[pos+1], &map->values[pos],
(map->size-pos)*sizeof(map->values[0]));
}
map->size++;
}
map->keys[pos] = key;
map->values[pos] = value;
WriteUnlock(&map->lock);
return AL_NO_ERROR;
}
ALint RemovePtrIntMapKey(PtrIntMap *map, ALvoid *key)
{
ALint ret = -1;
WriteLock(&map->lock);
if(map->size > 0)
{
ALsizei pos = 0;
ALsizei count = map->size;
do {
ALsizei step = count>>1;
ALsizei i = pos+step;
if(!(map->keys[i] < key))
count = step;
else
{
pos = i+1;
count -= step+1;
}
} while(count > 0);
if(pos < map->size && map->keys[pos] == key)
{
ret = map->values[pos];
if(pos < map->size-1)
{
memmove(&map->keys[pos], &map->keys[pos+1],
(map->size-1-pos)*sizeof(map->keys[0]));
memmove(&map->values[pos], &map->values[pos+1],
(map->size-1-pos)*sizeof(map->values[0]));
}
map->size--;
}
}
WriteUnlock(&map->lock);
return ret;
}
ALint LookupPtrIntMapKey(PtrIntMap *map, ALvoid *key)
{
ALint ret = -1;
ReadLock(&map->lock);
if(map->size > 0)
{
ALsizei pos = 0;
ALsizei count = map->size;
do {
ALsizei step = count>>1;
ALsizei i = pos+step;
if(!(map->keys[i] < key))
count = step;
else
{
pos = i+1;
count -= step+1;
}
} while(count > 0);
if(pos < map->size && map->keys[pos] == key)
ret = map->values[pos];
}
ReadUnlock(&map->lock);
return ret;
}