router.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. #include "config.h"
  2. #include "router.h"
  3. #include <algorithm>
  4. #include <array>
  5. #include <cstdio>
  6. #include <cstdlib>
  7. #include <cstring>
  8. #include <string>
  9. #include <string_view>
  10. #include <vector>
  11. #include "AL/alc.h"
  12. #include "AL/al.h"
  13. #include "alstring.h"
  14. #include "opthelpers.h"
  15. #include "strutils.h"
  16. #include "version.h"
  17. eLogLevel LogLevel{eLogLevel::Error};
  18. gsl::owner<std::FILE*> LogFile;
  19. namespace {
  20. std::vector<std::wstring> gAcceptList;
  21. std::vector<std::wstring> gRejectList;
  22. void AddModule(HMODULE module, const std::wstring_view name)
  23. {
  24. for(auto &drv : DriverList)
  25. {
  26. if(drv->Module == module)
  27. {
  28. TRACE("Skipping already-loaded module %p\n", decltype(std::declval<void*>()){module});
  29. FreeLibrary(module);
  30. return;
  31. }
  32. if(drv->Name == name)
  33. {
  34. TRACE("Skipping similarly-named module %.*ls\n", al::sizei(name), name.data());
  35. FreeLibrary(module);
  36. return;
  37. }
  38. }
  39. if(!gAcceptList.empty())
  40. {
  41. auto iter = std::find_if(gAcceptList.cbegin(), gAcceptList.cend(),
  42. [name](const std::wstring_view accept)
  43. { return al::case_compare(name, accept) == 0; });
  44. if(iter == gAcceptList.cend())
  45. {
  46. TRACE("%.*ls not found in ALROUTER_ACCEPT, skipping\n", al::sizei(name), name.data());
  47. FreeLibrary(module);
  48. return;
  49. }
  50. }
  51. if(!gRejectList.empty())
  52. {
  53. auto iter = std::find_if(gRejectList.cbegin(), gRejectList.cend(),
  54. [name](const std::wstring_view accept)
  55. { return al::case_compare(name, accept) == 0; });
  56. if(iter != gRejectList.cend())
  57. {
  58. TRACE("%.*ls found in ALROUTER_REJECT, skipping\n", al::sizei(name), name.data());
  59. FreeLibrary(module);
  60. return;
  61. }
  62. }
  63. DriverIface &newdrv = *DriverList.emplace_back(std::make_unique<DriverIface>(name, module));
  64. /* Load required functions. */
  65. bool loadok{true};
  66. auto do_load = [module,name](auto &func, const char *fname) -> bool
  67. {
  68. using func_t = std::remove_reference_t<decltype(func)>;
  69. auto ptr = GetProcAddress(module, fname);
  70. if(!ptr)
  71. {
  72. ERR("Failed to find entry point for %s in %.*ls\n", fname, al::sizei(name),
  73. name.data());
  74. return false;
  75. }
  76. func = reinterpret_cast<func_t>(reinterpret_cast<void*>(ptr));
  77. return true;
  78. };
  79. #define LOAD_PROC(x) loadok &= do_load(newdrv.x, #x)
  80. LOAD_PROC(alcCreateContext);
  81. LOAD_PROC(alcMakeContextCurrent);
  82. LOAD_PROC(alcProcessContext);
  83. LOAD_PROC(alcSuspendContext);
  84. LOAD_PROC(alcDestroyContext);
  85. LOAD_PROC(alcGetCurrentContext);
  86. LOAD_PROC(alcGetContextsDevice);
  87. LOAD_PROC(alcOpenDevice);
  88. LOAD_PROC(alcCloseDevice);
  89. LOAD_PROC(alcGetError);
  90. LOAD_PROC(alcIsExtensionPresent);
  91. LOAD_PROC(alcGetProcAddress);
  92. LOAD_PROC(alcGetEnumValue);
  93. LOAD_PROC(alcGetString);
  94. LOAD_PROC(alcGetIntegerv);
  95. LOAD_PROC(alcCaptureOpenDevice);
  96. LOAD_PROC(alcCaptureCloseDevice);
  97. LOAD_PROC(alcCaptureStart);
  98. LOAD_PROC(alcCaptureStop);
  99. LOAD_PROC(alcCaptureSamples);
  100. LOAD_PROC(alEnable);
  101. LOAD_PROC(alDisable);
  102. LOAD_PROC(alIsEnabled);
  103. LOAD_PROC(alGetString);
  104. LOAD_PROC(alGetBooleanv);
  105. LOAD_PROC(alGetIntegerv);
  106. LOAD_PROC(alGetFloatv);
  107. LOAD_PROC(alGetDoublev);
  108. LOAD_PROC(alGetBoolean);
  109. LOAD_PROC(alGetInteger);
  110. LOAD_PROC(alGetFloat);
  111. LOAD_PROC(alGetDouble);
  112. LOAD_PROC(alGetError);
  113. LOAD_PROC(alIsExtensionPresent);
  114. LOAD_PROC(alGetProcAddress);
  115. LOAD_PROC(alGetEnumValue);
  116. LOAD_PROC(alListenerf);
  117. LOAD_PROC(alListener3f);
  118. LOAD_PROC(alListenerfv);
  119. LOAD_PROC(alListeneri);
  120. LOAD_PROC(alListener3i);
  121. LOAD_PROC(alListeneriv);
  122. LOAD_PROC(alGetListenerf);
  123. LOAD_PROC(alGetListener3f);
  124. LOAD_PROC(alGetListenerfv);
  125. LOAD_PROC(alGetListeneri);
  126. LOAD_PROC(alGetListener3i);
  127. LOAD_PROC(alGetListeneriv);
  128. LOAD_PROC(alGenSources);
  129. LOAD_PROC(alDeleteSources);
  130. LOAD_PROC(alIsSource);
  131. LOAD_PROC(alSourcef);
  132. LOAD_PROC(alSource3f);
  133. LOAD_PROC(alSourcefv);
  134. LOAD_PROC(alSourcei);
  135. LOAD_PROC(alSource3i);
  136. LOAD_PROC(alSourceiv);
  137. LOAD_PROC(alGetSourcef);
  138. LOAD_PROC(alGetSource3f);
  139. LOAD_PROC(alGetSourcefv);
  140. LOAD_PROC(alGetSourcei);
  141. LOAD_PROC(alGetSource3i);
  142. LOAD_PROC(alGetSourceiv);
  143. LOAD_PROC(alSourcePlayv);
  144. LOAD_PROC(alSourceStopv);
  145. LOAD_PROC(alSourceRewindv);
  146. LOAD_PROC(alSourcePausev);
  147. LOAD_PROC(alSourcePlay);
  148. LOAD_PROC(alSourceStop);
  149. LOAD_PROC(alSourceRewind);
  150. LOAD_PROC(alSourcePause);
  151. LOAD_PROC(alSourceQueueBuffers);
  152. LOAD_PROC(alSourceUnqueueBuffers);
  153. LOAD_PROC(alGenBuffers);
  154. LOAD_PROC(alDeleteBuffers);
  155. LOAD_PROC(alIsBuffer);
  156. LOAD_PROC(alBufferData);
  157. LOAD_PROC(alDopplerFactor);
  158. LOAD_PROC(alDopplerVelocity);
  159. LOAD_PROC(alSpeedOfSound);
  160. LOAD_PROC(alDistanceModel);
  161. #undef LOAD_PROC
  162. if(loadok)
  163. {
  164. std::array<ALCint,2> alc_ver{0, 0};
  165. newdrv.alcGetIntegerv(nullptr, ALC_MAJOR_VERSION, 1, &alc_ver[0]);
  166. newdrv.alcGetIntegerv(nullptr, ALC_MINOR_VERSION, 1, &alc_ver[1]);
  167. if(newdrv.alcGetError(nullptr) == ALC_NO_ERROR)
  168. newdrv.ALCVer = MAKE_ALC_VER(alc_ver[0], alc_ver[1]);
  169. else
  170. {
  171. WARN("Failed to query ALC version for %.*ls, assuming 1.0\n", al::sizei(name),
  172. name.data());
  173. newdrv.ALCVer = MAKE_ALC_VER(1, 0);
  174. }
  175. auto do_load2 = [module,name](auto &func, const char *fname) -> void
  176. {
  177. using func_t = std::remove_reference_t<decltype(func)>;
  178. auto ptr = GetProcAddress(module, fname);
  179. if(!ptr)
  180. WARN("Failed to find optional entry point for %s in %.*ls\n", fname,
  181. al::sizei(name), name.data());
  182. else
  183. func = reinterpret_cast<func_t>(reinterpret_cast<void*>(ptr));
  184. };
  185. #define LOAD_PROC(x) do_load2(newdrv.x, #x)
  186. LOAD_PROC(alBufferf);
  187. LOAD_PROC(alBuffer3f);
  188. LOAD_PROC(alBufferfv);
  189. LOAD_PROC(alBufferi);
  190. LOAD_PROC(alBuffer3i);
  191. LOAD_PROC(alBufferiv);
  192. LOAD_PROC(alGetBufferf);
  193. LOAD_PROC(alGetBuffer3f);
  194. LOAD_PROC(alGetBufferfv);
  195. LOAD_PROC(alGetBufferi);
  196. LOAD_PROC(alGetBuffer3i);
  197. LOAD_PROC(alGetBufferiv);
  198. #undef LOAD_PROC
  199. auto do_load3 = [name,&newdrv](auto &func, const char *fname) -> bool
  200. {
  201. using func_t = std::remove_reference_t<decltype(func)>;
  202. auto ptr = newdrv.alcGetProcAddress(nullptr, fname);
  203. if(!ptr)
  204. {
  205. ERR("Failed to find entry point for %s in %.*ls\n", fname, al::sizei(name),
  206. name.data());
  207. return false;
  208. }
  209. func = reinterpret_cast<func_t>(ptr);
  210. return true;
  211. };
  212. #define LOAD_PROC(x) loadok &= do_load3(newdrv.x, #x)
  213. if(newdrv.alcIsExtensionPresent(nullptr, "ALC_EXT_thread_local_context"))
  214. {
  215. LOAD_PROC(alcSetThreadContext);
  216. LOAD_PROC(alcGetThreadContext);
  217. }
  218. #undef LOAD_PROC
  219. }
  220. if(!loadok)
  221. {
  222. DriverList.pop_back();
  223. return;
  224. }
  225. TRACE("Loaded module %p, %.*ls, ALC %d.%d\n", decltype(std::declval<void*>()){module},
  226. al::sizei(name), name.data(), newdrv.ALCVer>>8, newdrv.ALCVer&255);
  227. }
  228. void SearchDrivers(const std::wstring_view path)
  229. {
  230. TRACE("Searching for drivers in %.*ls...\n", al::sizei(path), path.data());
  231. std::wstring srchPath{path};
  232. srchPath += L"\\*oal.dll";
  233. WIN32_FIND_DATAW fdata{};
  234. HANDLE srchHdl{FindFirstFileW(srchPath.c_str(), &fdata)};
  235. if(srchHdl == INVALID_HANDLE_VALUE) return;
  236. do {
  237. srchPath = path;
  238. srchPath += L"\\";
  239. srchPath += std::data(fdata.cFileName);
  240. TRACE("Found %ls\n", srchPath.c_str());
  241. HMODULE mod{LoadLibraryW(srchPath.c_str())};
  242. if(!mod)
  243. WARN("Could not load %ls\n", srchPath.c_str());
  244. else
  245. AddModule(mod, std::data(fdata.cFileName));
  246. } while(FindNextFileW(srchHdl, &fdata));
  247. FindClose(srchHdl);
  248. }
  249. bool GetLoadedModuleDirectory(const WCHAR *name, std::wstring *moddir)
  250. {
  251. HMODULE module{nullptr};
  252. if(name)
  253. {
  254. module = GetModuleHandleW(name);
  255. if(!module) return false;
  256. }
  257. moddir->assign(256, '\0');
  258. DWORD res{GetModuleFileNameW(module, moddir->data(), static_cast<DWORD>(moddir->size()))};
  259. if(res >= moddir->size())
  260. {
  261. do {
  262. moddir->append(256, '\0');
  263. res = GetModuleFileNameW(module, moddir->data(), static_cast<DWORD>(moddir->size()));
  264. } while(res >= moddir->size());
  265. }
  266. moddir->resize(res);
  267. auto sep0 = moddir->rfind('/');
  268. auto sep1 = moddir->rfind('\\');
  269. if(sep0 < moddir->size() && sep1 < moddir->size())
  270. moddir->resize(std::max(sep0, sep1));
  271. else if(sep0 < moddir->size())
  272. moddir->resize(sep0);
  273. else if(sep1 < moddir->size())
  274. moddir->resize(sep1);
  275. else
  276. moddir->resize(0);
  277. return !moddir->empty();
  278. }
  279. void LoadDriverList()
  280. {
  281. if(auto list = al::getenv(L"ALROUTER_ACCEPT"))
  282. {
  283. std::wstring_view namelist{*list};
  284. while(!namelist.empty())
  285. {
  286. auto seppos = namelist.find(',');
  287. if(seppos > 0)
  288. gAcceptList.emplace_back(namelist.substr(0, seppos));
  289. if(seppos < namelist.size())
  290. namelist.remove_prefix(seppos+1);
  291. else
  292. namelist.remove_prefix(namelist.size());
  293. }
  294. }
  295. if(auto list = al::getenv(L"ALROUTER_REJECT"))
  296. {
  297. std::wstring_view namelist{*list};
  298. while(!namelist.empty())
  299. {
  300. auto seppos = namelist.find(',');
  301. if(seppos > 0)
  302. gRejectList.emplace_back(namelist.substr(0, seppos));
  303. if(seppos < namelist.size())
  304. namelist.remove_prefix(seppos+1);
  305. else
  306. namelist.remove_prefix(namelist.size());
  307. }
  308. }
  309. std::wstring dll_path;
  310. if(GetLoadedModuleDirectory(L"OpenAL32.dll", &dll_path))
  311. TRACE("Got DLL path %ls\n", dll_path.c_str());
  312. std::wstring cwd_path;
  313. if(DWORD pathlen{GetCurrentDirectoryW(0, nullptr)})
  314. {
  315. do {
  316. cwd_path.resize(pathlen);
  317. pathlen = GetCurrentDirectoryW(pathlen, cwd_path.data());
  318. } while(pathlen >= cwd_path.size());
  319. cwd_path.resize(pathlen);
  320. }
  321. if(!cwd_path.empty() && (cwd_path.back() == '\\' || cwd_path.back() == '/'))
  322. cwd_path.pop_back();
  323. if(!cwd_path.empty())
  324. TRACE("Got current working directory %ls\n", cwd_path.c_str());
  325. std::wstring proc_path;
  326. if(GetLoadedModuleDirectory(nullptr, &proc_path))
  327. TRACE("Got proc path %ls\n", proc_path.c_str());
  328. std::wstring sys_path;
  329. if(UINT pathlen{GetSystemDirectoryW(nullptr, 0)})
  330. {
  331. do {
  332. sys_path.resize(pathlen);
  333. pathlen = GetSystemDirectoryW(sys_path.data(), pathlen);
  334. } while(pathlen >= sys_path.size());
  335. sys_path.resize(pathlen);
  336. }
  337. if(!sys_path.empty() && (sys_path.back() == '\\' || sys_path.back() == '/'))
  338. sys_path.pop_back();
  339. if(!sys_path.empty())
  340. TRACE("Got system path %ls\n", sys_path.c_str());
  341. /* Don't search the DLL's path if it is the same as the current working
  342. * directory, app's path, or system path (don't want to do duplicate
  343. * searches, or increase the priority of the app or system path).
  344. */
  345. if(!dll_path.empty() &&
  346. (cwd_path.empty() || dll_path != cwd_path) &&
  347. (proc_path.empty() || dll_path != proc_path) &&
  348. (sys_path.empty() || dll_path != sys_path))
  349. SearchDrivers(dll_path);
  350. if(!cwd_path.empty() &&
  351. (proc_path.empty() || cwd_path != proc_path) &&
  352. (sys_path.empty() || cwd_path != sys_path))
  353. SearchDrivers(cwd_path);
  354. if(!proc_path.empty() && (sys_path.empty() || proc_path != sys_path))
  355. SearchDrivers(proc_path);
  356. if(!sys_path.empty())
  357. SearchDrivers(sys_path);
  358. }
  359. } // namespace
  360. BOOL APIENTRY DllMain(HINSTANCE, DWORD reason, void*)
  361. {
  362. switch(reason)
  363. {
  364. case DLL_PROCESS_ATTACH:
  365. if(auto logfname = al::getenv("ALROUTER_LOGFILE"))
  366. {
  367. gsl::owner<std::FILE*> f{fopen(logfname->c_str(), "w")};
  368. if(f == nullptr)
  369. ERR("Could not open log file: %s\n", logfname->c_str());
  370. else
  371. LogFile = f;
  372. }
  373. if(auto loglev = al::getenv("ALROUTER_LOGLEVEL"))
  374. {
  375. char *end = nullptr;
  376. long l{strtol(loglev->c_str(), &end, 0)};
  377. if(!end || *end != '\0')
  378. ERR("Invalid log level value: %s\n", loglev->c_str());
  379. else if(l < al::to_underlying(eLogLevel::None)
  380. || l > al::to_underlying(eLogLevel::Trace))
  381. ERR("Log level out of range: %s\n", loglev->c_str());
  382. else
  383. LogLevel = static_cast<eLogLevel>(l);
  384. }
  385. TRACE("Initializing router v0.1-%s %s\n", ALSOFT_GIT_COMMIT_HASH, ALSOFT_GIT_BRANCH);
  386. LoadDriverList();
  387. break;
  388. case DLL_THREAD_ATTACH:
  389. break;
  390. case DLL_THREAD_DETACH:
  391. break;
  392. case DLL_PROCESS_DETACH:
  393. DriverList.clear();
  394. if(LogFile)
  395. fclose(LogFile);
  396. LogFile = nullptr;
  397. break;
  398. }
  399. return TRUE;
  400. }